ret2libc
ret2libc基于没有system或没有/bin/sh($0可以代替,因为在linux环境变量$0就是当前终端)的情况,构造出一条ret调用链来
工具
ROPgadget
1 | pip install ROPgadget |
ROPgadget可以用于获取需要的字符串,汇编指令,最后可以通过栈溢出跳往对应的汇编指令中
LibcSearcher
1 | pip install LibcSearcher |
该工具可以根据你所给的指令名称对应的指令地址获取对应的外部got表地址
1 | libc=LibcSearcher('指令名称',指令地址)#可以获取内部got表对应地址所对应的glibc |
原理
section | 所在 segment | section 属性 | 用途 |
---|---|---|---|
.plt | 代码段 | RE(可读,可执行) | .plt section 实际就是通常所说的过程链接表(Procedure Linkage Table, PLT) |
.plt.got | 代码段 | RE | .plt.got section 用于存放 __cxa_finalize 函数对应的 PLT 条目 |
.got | 数据段 | RW(可读,可写) | .got section 中可以用于存放全局变量的地址;.got section 中也可以用于存放不需要延迟绑定的函数的地址。 |
.got.plt | 数据段 | RW | .got.plt section 用于存放需要延迟绑定的函数的地址 |
地址泄露
当puts elfgot表内函数地址时,会puts出真正的表内的函数地址
1 | puts_got=elf.got['puts']#获取的实际上是got.plt地址 |
pop_rdi_retn 将当前栈顶值(puts_got)传给rdi,然后将栈顶的指针向下移动到(puts_plt),并在之后跳转到栈顶值(puts_plt)
rdi(puts_got)将作为参数被puts_plt(puts函数)输出
因此可以泄露出puts的实际got表地址,不是elf中的got.plt
system函数
详情可见[StormQ’s Blog (csstormq.github.io)](https://csstormq.github.io/blog/计算机系统篇之链接(14):.plt、.plt.got、.got 和 .got.plt section 之间的区别)
因为system函数地址未知,但我们可以通过外部got表的地址,计算内部got表地址,获取got表内的函数(当加载libc的时候,函数都会在got表内),got表内函数的相对地址不会变
1 | libc=LibcSearcher('puts',puts) |
shell字符串
题目中可能没有提供字符串,在libc中会含有该字符串,当泄露了got表后可以获得
1 | system=base+libc.dump('system')#因为函数相对地址不变,就可以找到内部got表内的system函数地址 |
传递参数
x64常用rdi作为传递的第一个参数,所以我们需要一个将shell地址传给rdi的汇编指令(可以将shell字符串的地址存在栈中,通过pop edi调用),同时又得让命令走向按照我们的意愿来,所以还得有个retn
1 | pop rdi |
1 | ROPgadget --binary "二进制文件" --only 'pop|ret' |grep rdi #可以获取pop rdi retn的地址 |
栈对齐
system函数需要栈为16字节的倍数,因为此处只用了24字节(传参地址,shell字符串地址,system地址)
还需要一个地址作为占位,可以选择只有retn指令的地址
1 | ROPgadget --binary "二进制文件" --only 'ret' #获取只有retn命令的地址 |
ROP链
需要有个具体的栈的顺序
1 | (retn地址,传参地址,shell字符串地址,system地址) |
这样随着逐渐retn就可以获取shell了
- 标题: ret2libc
- 作者: runwu2204
- 创建于 : 2023-07-21 00:30:25
- 更新于 : 2023-07-21 01:11:15
- 链接: https://runwu2204.github.io/2023/07/21/Pwn/linux/ret2libc/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。