0x00 前言
看蒸米师傅的一步一步学ROP做的笔记
0x01 程序源代码:
和之前一样
1 | #include <stdio.h> |
那么现在开启ASLR,
1 | sudo -s |
查看一下:
1 | root@mask-virtual-machine:~/mzheng# cat /proc/sys/kernel/randomize_va_space |
然后查看一下:
1 | root@mask-virtual-machine:~/mzheng# ldd ./level2 |
你会发现,libc.so的地址每次都不一样,一直在变化,那么怎么办呢?
思路是:我们需要先泄漏出libc.so某些函数在内存中的地址,然后再利用泄漏出的函数地址根据偏移量计算出system()函数和/bin/sh字符串在内存中的地址,然后再执行我们的ret2libc的shellcode。
这里结合蒸米师傅给的那张图
栈,libc,heap的地址都是随机的,但是程序本身在内存中的地址并不是随机的
所以我们只要把返回值设置到程序本身就可执行我们期望的指令了
首先查看可以利用的plt函数以及对应的got表,这里提到的几个概念可以参考这篇文章 Linux中的GOT和PLT到底是个啥?
1 | root@mask-virtual-machine:~/mzheng# objdump -d -j .plt level2 |
这里蒸米师傅解释的很清楚,我就摘抄了下来:
我们发现除了程序本身的实现的函数之外,我们还可以使用read@plt()和write@plt()函数。但因为程序本身并没有调用system()函数,所以我们并不能直接调用system()来获取shell。但其实我们有write@plt()函数就够了,因为我们可以通过write@plt ()函数把write()函数在内存中的地址也就是write.got给打印出来。既然write()函数实现是在libc.so当中,那我们调用的write@plt()函数为什么也能实现write()功能呢? 这是因为linux采用了延时绑定技术,当我们调用write@plit()的时候,系统会将真正的write()函数地址link到got表的write.got中,然后write@plit()会根据write.got 跳转到真正的write()函数上去。(如果还是搞不清楚的话,推荐阅读《程序员的自我修养 - 链接、装载与库》这本书)
因为system()函数和write()在libc.so中的offset(相对地址)是不变的,所以如果我们得到了write()的地址并且拥有目标服务器上的libc.so就可以计算出system()在内存中的地址了。然后我们再将pc指针return回vulnerable_function()函数,就可以进行ret2libc溢出攻击,并且这一次我们知道了system()在内存中的地址,就可以调用system()函数来获取我们的shell了。
然后exp以及代码解释:
1 | #!/usr/bin/env python |