this is a test not true
0x00准备
本次实验的机器为
Ubuntu 16.04.2 LTS
64位系统需要关闭ASLR,
echo 0 > /proc/sys/kernel/randomize_va_space
,如果提示权限不够,可能需要用su
提升权限用
gcc
编译需要关闭stack-protector
,打开NX需要
gdb
peda
python2
ROPgadget or Ropper
攻击目标
test.c
,gcc -g -fno-stack-protector -o test test.c
1
2
3
4
5
6
7
8
int main(){
char buf[10];
read(0,buf,80);
puts("23333\n");
return 0;
}
0x01分析
测试程序很明显存在一个溢出的漏洞,但不能够写入一段shellcode
,然后运行,因为此时栈上的数据是不可执行的,也就是打开了NX,可以通过checksec
来查看程序的保护情况
1 | gdb-peda$ checksec |
幸运的是可以使用ret2libc
加上一点ROP
,劫持程序执行流,让它运行system()
0x02确定返回地址的偏移量
1 | gdb-peda$ pattern_create 100 test.txt |
获得返回地址的偏移量24
0x03确定相关地址
1 | gdb-peda$ p system |
因为关掉了ASLR
所以动态链接库的地址不会变化,可以直接使用system
函数的地址0x7ffff7a52390
,字符串/bin/sh
的地址0x7ffff7b99d17
0x04构造ROP链
还有一个需要解决的问题,怎样把/bin/sh
传到system
函数中去,在linux64
的系统上,一般使用寄存器传递参数,按照rdi,rsi,rdx,rcx,r8,r9
的顺序传递,如果参数过多,再用栈传递参数
所以需要一个简短的ROP链pop rdi;ret
,可以使用工具Ropper
ROPgadget
或者直接objdump
1 | $ ROPgadget --binary test|grep pop|grep rdi |
0x05编写payload
1 | from struct import * |
整个流程大概是这样的:
返回地址被pop rdi
的地址覆盖,所以程序流被控制了,执行pop rdi;ret
,把栈顶弹出到rdi
中,栈顶现在是/bin/sh
的地址,然后它的地址自然被传递到了rdi
寄存器中,接着执行ret
,栈顶被弹入到rip
,也就是system()
的地址被存入了rip
,现在调用system()
函数,参数存在rdi
中
0x06测试
1 | $ (cat test.txt;cat)|./test |
可以看到get到了shell
0x07总结
通过ret2libc
可以绕过NX