ღ Miranda

Bypassing ASLR + DEP using ROP + Return-to-dl-resolve in 64-bit system

使用Return-to-dl-resolve技术在没有libc库的情况下执行system函数,系统为64位环境。

Environment

Vulnerable code

编译程序并且打开系统的ASLR:

Difference in x64

首先在x64下,函数的参数是通过寄存器传递的,而不是通过栈,所以在构造ROP时,要把参数放到对应寄存器中,看看read函数参数情况:

看到实际上是read(rdi, rsi, rdx),三个寄存器的值对应了三个参数。

write函数参数情况:

所以在构造ROP链时与x86下有些不同。

return-to-plt

call write@plt

首先还是先直接调用write@plt试试,和上一篇基本相同,只是相对应改成64位下的字长,代码如下:

运行结果:

Relocation directly

x64下,与_dl_runtime_resolve相关的两个结构体定义有所不同:

read函数为例,看看内存中数据是什么。

通过文件我们知道.rel.plt地址为0x4003d0,大小为48 (bytes),每一项24 (bytes),也就是两项,readwrite:

gdb查看readElf64_Rela:

文件的Elf64_Sym位置,每一项是24 (bytes):

readElf64_Sym结构体在SYMTAB[r_info >> 32]=SYMTAB[2]:

再通过STRTAB找到read字符串:

修改代码的部分:

运行:

Make fake Elf64_Rela structure

64位下,Elf64_Rel是通过下面的方式找到的,所以选择的地址也需要对齐:

先填入原来结构体内的内容,修改后的代码:

结果:

Make fake Elf64_Sym structure

由以下公式找到write的结构体:

内存查看:

按照之前的方式修改代码:

发现并不能成功,我们可以把要输入的字符串放在一个文件中然后用gdb调试程序:

单步跟随ROP链,发现在_dl_fixup中引发了Segmentation fault:

这里RCX就是伪造的r_info值,而RCX值过大,导致无法读取内存,引发了错误,我们往前看代码:

对应的C代码:

发现有个je可以跳过这一段代码,只要[r10+0x1c8]处的值为0就可以跳过,再往前看,发现只有函数开头mov r10,rdi改变了r10的值,然后都不会改变,r10的值是个特殊的值:

0x601000GOT表起始地址,之前说过,第二个元素是link_map的起始地址,所以我们的目的就是更改link_map+0x1c8处的值为0,由于开启了ASLR,所以还需要泄露link_map的地址。

Get shell

泄露link_map地址的方法就是在最前面先调用addr_write_plt,把link_map的地址打出来,由于我这里用之前的方法收到shell时发现命令能够执行但是输入字符不显示:

这里用pwntools改写一下,完整程序:

运行:

refer: x64でROP stager + Return-to-dl-resolveによるASLR+DEP回避をやってみる

发表评论

电子邮件地址不会被公开。