20145229吴姗珊逆向BOF实践

20145229吴姗珊逆向BOF实践

实践

实践目标

  • 本次实践的对象是一个名为pwn1的linux可执行文件
  • 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
  • 该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。
  • 我们将学习两种方法:
    1. 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
    2. 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。

实践步骤

  • 安装虚拟机、靶机及Kali,安装成功如下图

  • 建立姓名学号文件夹,放入pwn1

  • 直接运行pwn1,知道其作用为回显刚刚输入的字符

  • 当输入的字符过长会导致缓冲区溢出

  • 指令objdump反汇编pwn1,more管道按页显示,命令 objdump -d pwn1 | more

  • 分析代码并修改指令改变其功能
    main函数反汇编的第4行,"call 8048491 "是汇编指令,是说这条指令将调用位于地址8048491处的foo函数;其对应机器指令为"e8 d7ffffff",e8即跳转之意。本来正常流程,此时此刻EIP的值应该是下条指令的地址,即80484ba,但一解释e8这条指令呢,CPU就会转而执行 "EIP + d7ffffff"这个位置的指令。"d7ffffff"是补码,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491这个值(foo函数调用入口),main函数调用foo,对应机器指令为" e8 d7ffffff",那我们想让它调用getShell,只要修改"d7ffffff"为,"getShell-80484ba"对应的补码就行。用Windows计算器,直接 47d-4ba就能得到补码,是c3ffffff。

之后汇编码将由e8d7ffffff变为e8c3ffffff

  • 下载图形化的16进制编辑器
    指令:apt-get install wxhexeditor
    wxHexEditor

  • 通过构造输入参数,造成BOF攻击,分析各函数功能

main:函数的第四行call 8048491意思为跳转到foo函数

getshell:我们的目标是触发函数getShell,这个恶意代码可以实现shell
foo:可执行文件正常运行是调用如下函数foo,这个函数有Buffer overflow漏洞

  • 缓冲区溢出跳转getshell
    1.首先尝试用gdb调试

2.输入1111111122222222333333334444444455555555,观察寄存器数值

3.发现eip为0x35353535,查ASCLL表发现是5555。eip寄存器的功能就是保存程序下一步要执行指令的地址,可以看出本来应返回到foo函数的返回地址已被"5555"覆盖

4.通过将55555555换成12345678,再观察eip值找出谁被覆盖,通过查表可知为1234

5.确认getshell地址的字节序列0804847d如何组合

  • 通过设置断点查看0804847d的顺序,在0804049d处设置断点,通过查看之后的eip值,eip值不变,对比之前 eip 0x34333231 0x34333231 ,通过查表查出为4321,可以确定getshell字符序列应该是11111111222222223333333344444444\x7d\x84\x04\x08

码表如下

  • 生成字符串
    我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以先生成包括这样字符串的一个文件。\x0a表示回车,如果没有的话,在程序运行时就需要手工按一下回车键。
    Perl是一门解释型语言,不需要预编译,可以在命令行上直接使用。
    使用输出重定向“>”将perl生成的字符串存储到文件input中。可以使用16进制查看指令xxd查看input文件的内容是否如预期。

  • 跳转getshell
    将input的输入,通过管道符“|”,作为pwn1的输入

  • 注入shellcode
    shellcode:
    Shellcode是一组可注入的指令,可在被攻击的程序内运行。由于shellcode要直接操作寄存器,通常用汇编语言编写并翻译成十六进制操作码。我们想让目标程序以不同与设计折预期的方式运行,操纵程序的方法之一是强制它产生系统调用。ShellCode就是一段程序的机器码形式,而ShellCode的编写过程,就是得到我们想要程序的机器码的过程。
    在Linux里有两种方法来执行系统调用。间接的方法是libc,直接的方法是用汇编指令调用软中断执行系统调用。在Linux里,程序通过int 0x80软中断来执行系统调用,调用过程如下:
    1、把系统调用编号载入EAX;
    2、把系统调用的参数压入其他寄存器;最多支持6个参数,分别保存在EBX、ECX、EDX、ESI、EDI和EBP里;
    3、执行int 0x80指令;
    4、CPU切换到内核模式;
    5、执行系统函数。

  • 需要一个shellcode代码,在网上找了一个,命名为helloshellcode,直接对这个程序进行编译,编译时注意需要首先转换为32位

  • 想提取其中的shellcode就需要通过反汇编来获取相应的汇编代码或是二进制代码。如果要提取该程序中的获取shell的shellcode,就是要获取函数execve调用时参数及相应的系统调用。接下来进行反汇编

  • 使用gdb查看反汇编

从上图中可以看出execve函数是先赋值寄存器后进行调用*0x80e8a90,可以看出就是上面所说的第一种放大—调用软中断执行系统调用。一旦加载寄存器之后,就会调用int 0x80 汇编指令来发出软中断,强迫内核暂停手头上的工作并处理该中断。

  • 提取shellcode
    在上面放的用gdb查看的反汇编的图里的部分指令进行组合就可以了,不过老师在上课的时候说过里面不能包含0字符,需要把0字符全部去掉,否则无法执行

  • 汇编写helloshellcode及编译

  • 本次的shellcode参考了网上大神的分享,自己对这汇编方面理解太少,能理解整个过程的原理,在实践代码方面举步维艰,不过熟能生巧,自己会多加强这方面的学习

实践感想

本次的实践是本次课的第一次实验,根据老师给出的教程一步步往下做没有遇到太大的问题,只是在确定大端小端的时候遇到了一些疑难,缓冲区溢出最重要的就是找出覆盖的部分,然后进行一个计算即可进行跳转,其实原理很简单,只是对汇编方面的知识太过生疏导致理解汇编时非常吃力,但是在做注入shellcode的时候,根据网上的教程做下来,大体的概念清楚,做下来花了不少时间,还需要花一定的时间理解消化,希望自己以后也可以加强对汇编的学习,将所有知识融会贯通进行学习。

posted on 2017-02-26 23:45  sssssqyk  阅读(176)  评论(0编辑  收藏  举报

导航