2017-2018-2 20155315《网络对抗技术》Exp1:PC平台逆向破解

实验目的

  • 本次实践的对象是一个名为pwn1的linux可执行文件。
  • 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
  • 该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。

实验内容

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

实验要求

  • 熟悉Linux基本操作
  • 理解Bof的原理
  • 会使用gdb,vi

实验步骤

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

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

思路

  • 一个程序的可执行文件可通过objdump命令对其进行反汇编,通过对汇编语言的学习可以看出程序读取数据的过程。
  • 从反汇编的文件来看,main函数中调用foo函数,使用call指令。通过分析发现foo函数与getShell函数的首地址之间
    存在偏移,两者之间相差了14。系统调用foo函数对应机器指令为e8 d7ffffff,则如果想调用getShell函数,就要对e8 d7ffffff进行修改。
  • 已经知道电脑是小端模式,即数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。因此,如果要修改,就要将"d7"改为"c3"。
  • 具体操作过程:
    • 将pwn1进行备份,修改备份文件
    • 用vi打开备份文件,用:%!xxd将显示模式切换为16进制模式
    • /d7查找要修改的内容,定位后将d7改为c3
    • :%!xxd -r将转换16进制为原格式,保存退出。
  • 再次反汇编之后,确定已经将程序修改为调用getShell函数,接下来就是运行程序了。
  • 运行时发现无法找到目录或文件,按照老师提供的教程进行操作就可以了。

运行截图

思考

运行成功之后就完成了实验的第一个部分,按照老师的指导一步步操作还算顺利。遇到的问题是,第一次在16进制模式修改完数据后出现操作失误,先保存后转换,在运行的时候导致文件损坏不可用。这是因为一开始保存的时候就改变了文件的格式,使得它不再是一个可执行文件的格式。查找资料后没有找到能将其再次转换的方法,只好重新进行实验。

参考资料

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

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

思路

  • 利用缓存区溢出进行攻击,是利用输入的数据将返回值进行覆盖。如果用getShell函数的地址进行覆盖,就会使程序调用getShell函数实现BOF攻击。
  • 调用函数的时候,就会将函数的地址作为返回值压栈,即放入栈顶。字符串字节数足够大的时候就能覆盖返回值。
  • 理清思路,使用gdb进行调试,弄清楚是哪几个字节会覆盖返回地址。
  • 将“1234”替换为getShell函数的地址,即0x0804847d。已经知道电脑是小端模式,输入的时候要注意使用正确的字节序。
  • 同时,输入的时候要注意,我们是没办法直接输入ASCII码值为“0804847d"的字符,需要使用perl命令先生成包括这样字符串的一个文件。
perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > input
  • xxd input查看input文件的内容
  • 后将input的输入,通过管道符“|”,作为输入。运行之后就进入了getShell函数,实验的第二部分就完成了。

运行截图


思考

  • 已经确定了使用getShell的地址进行覆盖,要注意的是在输入地址的时候,只输入0804847d不会被计算机识别为16进制值,要使用/x08/x04/x84/x7d
  • 关于Perl:Perl有很多命令行参数,通过它可以让你的程序更简练,并且可以写出很多只有一行命令的perl。
    • -e:用于在命令行而不是在脚本中执行 Perl 命令。
    • perl遵循正则表达式的标准。
  • 尝试过用vim编辑器输入16进制,将其变为16进制编辑状态编辑后总会有错误,是因为无法同时改变ASCII码值与其对应的符号。
  • 关于“|”管道:将第一条命令的结果作为第二条命令的参数来使用。用“;”区分两条命令,如果直接在命令行输入cat而不输入其余的任何东西,这时候的cat会等待标准输入。(cat input; cat) | ./pwn1先运行程序,将input的内容作为输入显示在程序中,第二个cat就会等待标准输入,此时就可以输入shell命令了。

参考资料

(三)注入Shellcode并执行

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

思路

  • 使用shellcode进行攻击,经过验证结构为:anything+retaddr+nops+shellcode.nop一为是了填充,二是作为“着陆区/滑行区”,猜测返回地址只要落在任何一个nop上,自然会滑到我们的shellcode。
  • 一开始没有关闭地址随机化,每一次操作esp的地址都会变化,因此实验的关键就是要关闭地址随机化。
  • 之后使用gdb调试程序,使用ps -ef | grep 文件名获取程序运行的PID,在gdb中对其进行追踪。查询esp寄存器的内容,并用x/16x查看其中的内容,看到 01020304
  • shellcode在retaddr之后,因此我们要插入的地址是01020304地址加上0x04

运行截图

思考

一开始做实验的时候,没有认真思考shellcode的结构问题,再次打开虚拟机之后也没有关闭地址随机化,导致实验遇到了问题。重新开始之后,跟着老师的教程走来完成实验。其实确立了思路之后,重要的就是查命令来完成实验,对shellcode也不是很了解,还要继续学习。

参考资料

原文地址:https://www.cnblogs.com/-zyl/p/8531778.html