学习一波经典的ROP题目。
题目地址:r0pbaby
1.基本信息收集
文件信息
64位的程序
查看保护:
开启了NX(不可执行)+PIE(Position Independnet Code位置无关代码)等安全防护,对于这样的保护机制,绕过的方法是ROP(Return-oriented Programming),那ROP是什么?
2.漏洞定位及利用思路
ROP
ROP的核心思想:攻击者扫描已有的动态链接库和可执行文件,提取出可以利用的指令片段(gadget),这些指令片段均以ret指令结尾,即用ret指令实现指令片段执行流的衔接。
(往后做的时候遇到一个问题,看别的大佬的wp,有说要关闭ASLR的,把关不关ASLR分成了两种解法,我自己本地试的时候,发现我关了ASLR也没用,exp根本跑不起来,所以我就按有ASLR的解法来了。)
思路:
玩一玩这个程序:
第一选项打印libc地址
第二个选项打印system函数地址
第三个是向栈写数据
用ida看一下
发现危险函数memcpy(),说明存在栈溢出漏洞。
接下来用gdb调试一下:
看到程序在0x0000555555554eb3崩溃
此时rsp中的值是ABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA,来计算一下偏移量:
所以,ret的地址是以我们输入的偏移量为8的位置来取的。我们这样就可以控制rip了。
现在来想一下我们该干什么。我们的希望获取一个shell,也就是说要控制程序执行流程,最好能跳转执行system函数。
所以我们需要构造一个payload让程序执行system(“/bin/sh”)
接下来我们要做的:
1 | 找到"/bin/sh"位置 |
寻找gadget:
我们要跳转执行的地方,要有两个pop和一个call。先来复习一下64位架构下各寄存器的作用:
1 | %rax 作为函数返回值使用。 |
rdi是传第一个参数的,那么我们要寻找的gadget至少有一个pop rdi,我们可以用ida在libc中来找:
我们使用的libc是:libc-2.27.so
找到了符合的。
寻找”/bin/sh”:
用ida :
用ida打开libc-2.27.so,shift + f12 ,ctrl + f 搜索”/bin/sh’
或:
区别在于ida找到的是程序未加载到内存时的地址,第二种方法找到的是在内存中的地址。如果开启了ASLR,还是用ida吧。
寻找system:
ida打开libc-2.27.so,搜索字符串”system”
构造payload:
“A”*8 + p64(ppc) + p64(sys_addr) + p64(binsh_addr)
关于这个顺序,我的理解是,因为我们找到的gadget的是先pop rax,再pop rdi,也就是说,当程序跳转到这一块时,先要执行pop rax,又因为rax用来传递函数地址,而且后面还要call rax,那接下来跟的就只能是system函数的地址,pop rdi,就把”/bin/sh”用rdi传过去。
好了,到这里我们粗略的完成了payload的构造,接下来要考虑的具体一点。
我们默认是开启了ASLR保护的,程序运行后,我们上面找到的地址就发生变化了,那么程序运行我们如何定位我们需要的地址呢?
我们知道在程序未加载到内存中时,system在libc中的地址,我们也知道ppc和binsh在libc中的地址,那么就通过计算它们相对于libc_system的偏移,加载到内存中后就可以表示成system运行后的地址+偏移了。而system函数运行后的地址可以通过程序第二个选项来获得。
编写exp:
1 | from pwn import * |