1.实验内容
1.1本周学习内容
1.1.1安全漏洞简介
定义:系统的缺陷或不足。
作用:网络攻击和防御的关键点。
网络攻击:利用系统漏洞进行攻击。
防御:提前发现漏洞并修复。
- exploit:完整的代码攻击。
- shellcode:不完整的代码攻击。
- PoC:验证是否存在漏洞。
1.1.2缓冲区溢出的定义和原因
定义:当程序向一个固定大小的缓冲区写入超过其容量的数据时,溢出的数据会覆盖相邻的内存区域改写程序执行流程。
原因:(根本)冯诺依曼的安全缺陷,指令与数据不分离存储;(直接)程序没有严格的检查。
1.1.3缓冲区经典攻击
红色代码、冲击波病毒、震荡波病毒、心脏出血、乌克兰断网、勒索病毒。
1.1.4缓冲区基础知识
编译器:高级语言编写的程序需用编译器和连接器生成可执行代码(如GCC)。
调试器:调试程序的工具(如gdb命令、断点调试)。
寄存器:堆栈(SP)、指令寄存器(EIP)、EBP栈底指针寄存器(高地址)、ESP栈顶指针寄存器(低地址)等。
堆:动态分配的内存。
栈:遵循先进先出的内存空间。
汇编指令:push、call、pop、jmp、ret等。
1.2实验目的
本次实践的对象为linux可执行文件(pwn1)。该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序包含另一个代码片段(getShell),会返回一个可用Shell,正常情况下此代码不会被运行。
实践的目标是运行这个代码片段,本次实验将运用三种方法运行这个代码片段,并学习如何注入运行任何Shellcode。
实践内容:
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入shellcode并运行这段shellcode。
- 结合nc模拟远程攻击
1.3实验要求
- 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
- 掌握反汇编与十六进制编程器
- 能正确修改机器指令改变程序执行流程
- 能正确构造payload进行bof攻击
2.实验过程
2.1直接修改程序机器指令,改变程序执行流程
通过共享文件夹将pwn1文件下载至kali并命名为(pwn20222428)。
正常执行会回显任何用户输入的字符串。
通过反汇编命令(objdump -d pwn20222211 | more),找到main、foo、getshell函数。
此图中第一列为内存地址,第二列为机器指令,第三列为机器指令对应的汇编语言。main函数中的“call 8048491”是汇编指令,是指这条指令将调用位于地址8048491处的foo函数;其对应机器指令为“e8 d7ffffff”,e8是跳转的意思;d7ffffff为补码。执行这条指令时,CPU会执行 “EIP + d7ffffff”这个位置的指令。在此为80484ba +d7ffffff= 8048491(EIP是下一条指令的地址,此为80484ba),成功调用foo函数。根据实验要求,我们需要修改可执行文件,改变程序执行流程,直接跳转到getShell函数。所以需要修改“d7ffffff”为“getShell-80484ba"对应的补码(为c3ffffff)。
下面我们将修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff。
修改过程为:
vi pwn20222428 打开文件。
按esc键;输入:“%!xxd”进入十六进制编辑模式,使用“/e8 d7"快速找到需要修改的地址。
将d7修改为c3,用“:%!xxd -r”指令转换16进制为原格式,“:wq”保存退出。
验证:
再次反汇编查看call指令是否正确调用getShell。
执行文件查看是否会得到shell提示符。
2.2通过构造输入参数,造成BOF攻击,改变程序执行流
在程序执行过程中,堆栈结构经常用于管理函数调用和局部变量。每当一个函数被调用时,其返回地址(return address)和相关的参数、局部变量等信息会被压入调用栈(Call Stack)。返回地址是指当函数执行完毕时,程序应该跳转回哪个位置继续执行。foo函数向一个固定大小的缓冲区写入超过其容量的数据时具有缓冲区溢出(Bufferoverflow)漏洞,我们可以通过向这个缓冲区输入超出长度的字符串来覆盖该返回地址,使返回地址指向getshell,达到攻击目的。
攻击过程:
重新上传一个pwn1文件,命名为pwn20222428-2。
用gdb命令调试pwn20222428-2,输入字符串“1111111122222222333333334444444455555555”,输入“info r”查看寄存器eip的值。
分析可知,eip处由5555(二进制“0x35353535")覆盖,同理输入字符串“1111111122222222333333334444444412345678”,输入“info r”查看寄存器eip的值。
分析可知,eip处由1234(二进制“0x34333231")覆盖,我们需要将这四个字符改为getshell函数的内存地址,并输给pwn20222428-2,便可调用getshell并执行。
不能通过键盘直接输入十六进制值,所以先利用perl生成包含“11111111222222223333333344444444\x7d\x84\x04\x08\x0a”这个字符串的一个文件。(\x7d\x84\x04\x08\x0a为getshell地址)。
再使用指令xxd查看input文件的内容是否如预期。
验证:
通过管道符“|”,将input的输入作为pwn20222428-2的输入并查看是否会得到shell提示符。
2.3注入Shellcode并执行
准备工作:
重新上传一个pwn1,命名为pwn20222428-3。
准备一段Shellcode。
“\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\”作用为启动一个新的shell(本次实验所用)
通过以下命令修改设置。
execstack -s pwn20222211-3 //设置堆栈可执行
execstack -q pwn20222211-3 //查询文件的堆栈是否可执行
more /proc/sys/kernel/randomize_va_space //查看地址随机化的状态
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
more /proc/sys/kernel/randomize_va_space
攻击过程:
构造要注入的payload,结构为:nops+shellcode+retaddr。
其中“\x1\x2\x3\x4”是占位符,后续将替换为注入“shellcode”的地址,也就是foo函数中return address的位置(此地址需要通过gdb分析找到),利用perl生成包含这个特殊结构的input_shellcode文件。再将这一文件作为pwn的输入。
打开一个新的终端,输入ps -ef | grep pwn20222211-3,查看pwn20222211-3文件的进程以及进程号;并用gdb调试进程。
通过反汇编查找foo函数的结束地址并在这里输入命令break *结束地址设置断点;
输入c(c表示continue继续运行)旧终端需按enter键,否则新终端的continue一直进行。
通过info r esp命令查看栈顶指针的地址
栈顶指针位于0xffffcf2c且栈顶指针存放了之前注入的占位符(0x01020304),这就是返回地址的位置。
又因为shellcode挨着返回地址的位置,所以shellcode=0xffffcf2c+4=0xffffcf30。所以将“\x4\x3\x2\x1”更换为“\x30\xcf\xff\xff”,就能运行shellcode。
2.4结合nc模拟远程攻击
本次实验我克隆了初始的虚拟机,将两台虚拟机的网路连接方式设置为桥接网卡模式。
主机1,模拟一个有漏洞的网络服务。
主机2,连接主机1并发送攻击载荷。
3.问题及解决方案
- 问题1:已配置共享文件但重新打开虚拟机执行pwn文件时显示找不到文件。
- 问题1解决方案:编辑/etc/fstab文件,添加一行用于永久挂载共享文件夹的配置。(.host:/ /mnt/hgfs fuse.vmhgfs-fuse defaults,allow_other 0 0)
这行配置指定了使用FUSE类型的vmhgfs-fuse文件系统来挂载主机上的共享文件夹到/mnt/hgfs目录,并允许其他用户访问。 - 问题2:用gdb pwn20222428-2调试过程中发现未安装gdb
- 问题2解决方案:使用sudo apt update和sudo apt install gdb命令安装gdb
- 问题3:安装execstack时报错“Unable tolocate package execstack”。
- 问题3解决方案1:外部官网安装,官网链接为(http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb)再使用sudo dpkg -i execstack_0.0.20131005-1+b10_amd64.deb命令进行解压,最终安装成功。
- 问题3解决方案2:修改sources.list文件,使用中科大提供的源。
sudo vim /etc/apt/sources.list(打开sources.list文件)
在文件中添加以下内容。
deb http://http.kali.org/kali kali-rolling main contrib non-free
deb http://http.kali.org/kali sana main non-free contrib
deb http://security.kali.org/kali-security sana/updates main contrib non-free
deb http://old.kali.org/kali moto main non-free contrib
再进行安装,安装成功。
- 问题4:下载时发现kali并没有联网,无法下载。
- 问题4解决方案:在虚拟网络编辑器中,将VMnetO设置为桥接模式,并桥接至Intel(R) Wi-Fi 6E AX211 160MHZ。
4.学习感悟、思考等
通过本次实验,我不仅学习并掌握了三种获取shell的方法,还深入了解了Linux操作系统的相关语言,并具备了读懂部分汇编语言的能力。
在本次实验中,我掌握了三种关键的获取shell的方法。通过实践与网络资源的辅助,我熟悉并掌握了NOP、JNE、JE、JMP和CMP等汇编指令的机器码及其功能。NOP指令作为空指令,不执行任何操作;JNE和JE则是根据条件进行转移的指令;JMP指令则无条件地转移到指定的地址;CMP指令则用于比较两个操作数,但不保存比较结果。
在实验中,我还学习并熟练使用了十六进制编辑器,特别是xxd命令行十六进制编辑器。通过%!xxd命令,我能够轻松进入十六进制编辑模式,对文件进行精细的修改。这一技能在实验中发挥了重要作用。
此外,我利用反汇编命令成功查找了函数的内存地址、机器指令以及对应的汇编语言。这一过程中,我对程序的存储结构有了更为深入的了解。通过修改文件,我掌握了改变程序流程的方法,并对缓冲区溢出攻击有了更为深刻的认识。在实验中,我通过gdb正确构造了输入参数,进行了BOF(缓冲区溢出)攻击。这一过程中,我清晰地看到了缓冲区溢出攻击的流程,并深刻理解了其危害。同时,我还学习了如何通过反汇编和gdb正确构造payload进行bof攻击。通过大量资料的收集和学习,我对Payload的特定含义有了更为清晰的认识。
本次实验不仅提升了我的动手实践能力,还让我对网络安全有了更为深入的了解。同时,面对实验中出现的多种问题和知识点上的疑问,我进行了大量的资料搜索和学习,这一过程极大地提升了我独立解决问题和深入掌握知识的能力。