Kibana代码审计

极客

Kibana代码审计:一次让我头皮发麻的漏洞挖掘实录

说实话,提到Kibana代码审计,我一开始是拒绝的,为啥呢?因为这东西是Node.js写的啊!你们也知道,Node.js那种回调套回调的代码风格,看起来简直就像是在拆俄罗斯套娃,一层又一层,烦得很,但没办法,项目需要,硬着头皮上吧,结果这一上,好家伙,直接给我挖出来一个让我半夜三点还兴奋得睡不着的漏洞,今天就来跟大家唠唠这次Kibana代码审计的完整心路历程,全是干货,别走神啊!

Kibana代码审计

为啥要搞Kibana代码审计?

先说说背景吧,Kibana是Elastic Stack里的可视化扛把子,基本上用ELK做日志分析的公司,前端都离不开它,但你们发现没有?这几年Kibana爆出来的漏洞可不少,什么原型链污染、SSRF、任意文件读取……CVE一个接一个,所以啊,Kibana代码审计这事儿,还真不是闲着没事干,是真有搞头。

我这次审计的版本是Kibana 7.x,具体哪个小版本就不说了,免得惹麻烦,拿到源码的第一反应是:我滴个乖乖,这代码量也太大了!光是src/core目录就够我喝一壶的,但没办法,Kibana代码审计的第一步,就是得先摸清它的架构。

Kibana代码审计的第一步:找入口

Kibana代码审计,最忌讳的就是一头扎进代码海里瞎翻,你得先找入口点,也就是用户能控制输入的地方,Kibana的入口主要分两块:一个是HTTP API路由,另一个是前端渲染。

我当时的策略很简单:先看src/core/server/http下面的路由注册逻辑,Kibana用的是Hapi.js框架,路由定义特别多,我写了个脚本,把所有server.route的调用都抓出来,然后按URL路径排序,这一步花了我大半天时间,眼睛都快看瞎了。

但就是在这个整理的过程中,我发现了一个有意思的接口:/api/console/proxy,这个接口是给Kibana的Dev Tools控制台用的,功能是代理请求到Elasticsearch,哎,等等,代理请求?这不就是SSRF的温床吗?

深入Kibana代码审计:追踪代理逻辑

找到了可疑接口,接下来的Kibana代码审计就有了方向,我顺着/api/console/proxy的路由定义往下追,找到了它的handler函数,代码大概长这样:

const { payload, query } = request;
const { path, method } = query;
// ... 省略一堆校验逻辑
const response = await proxyRequest(path, method, payload);

看到没?pathmethod都是从query参数里直接拿的!虽然前面有一些校验,但我当时心里就咯噔一下:这校验真的够吗?

于是我继续往下看proxyRequest的实现,这里Kibana用了一个叫elasticsearch-js的客户端库,关键来了:这个客户端在构造请求的时候,会对path参数做一次URL解析,而问题就出在这个解析逻辑上。

Kibana代码审计最刺激的地方就在于,你永远不知道下一个转角会遇到什么,我当时发现,如果path参数里包含符号或者符号,URL解析的结果会出乎意料,比如传入@evil.com/,解析后的host居然变成了evil.com!这不就是SSRF吗?

漏洞验证:从代码审计到实际利用

发现这个点之后,我赶紧搭了个本地环境,启动Kibana,打开Dev Tools,构造了这样一个请求:

POST /api/console/proxy?path=@127.0.0.1:9200/_cat/indices&method=GET

你猜怎么着?请求居然真的被代理到了本地的9200端口!虽然Elasticsearch本身就在本地,但这意味着我可以把请求代理到任意内网地址,比如云环境里的254.169.254元数据接口,或者内网的其他服务。

不过先别高兴太早。Kibana代码审计的严谨性告诉我,还得确认权限问题,这个接口需不需要认证?答案是:在默认配置下,Kibana的Dev Tools是需要登录的,但如果是内网环境,或者配置了匿名访问,那就完蛋了,而且我后来发现,在某些版本里,这个接口的认证逻辑存在绕过可能,具体细节就不展开说了,懂的都懂。

Kibana代码审计的反思:为啥这种漏洞总会出现?

挖到这个漏洞之后,我一直在想一个问题:为啥Kibana代码审计里总能发现这类问题?后来我想明白了,Kibana的开发团队其实挺专业的,但架不住功能迭代太快,Dev Tools这种“开发者工具”在設計之初,可能就没考虑过会被外部滥用,再加上Node.js的URL解析库本身就有一些历史遗留问题,组合起来就出了幺蛾子。

Kibana代码审计不能只看表面,比如那个proxyRequest函数,表面上做了参数校验,但校验逻辑用的是黑名单而不是白名单,黑名单这东西,你永远不知道攻击者能想出什么骚姿势绕过。

给做Kibana代码审计的朋友几点建议

最后总结几点吧,都是我踩过的坑:

  1. 别怕代码多,Kibana代码量是大,但入口点就那么几个,先抓路由,再顺藤摸瓜。
  2. 重点关注代理和转发类接口,这类接口天生就是SSRF的温床,/api/console/proxy只是其中之一。
  3. URL解析要特别小心,Node.js的url.parsenew URL行为不一样,Kibana代码审计时一定要确认用的是哪个。
  4. 版本差异要留意,不同版本的Kibana,同一个接口的实现可能天差地别,我这次审计的漏洞,在后续版本里就被修了。

好了,这次的Kibana代码审计实录就写到这儿,说实话,挖漏洞这事儿吧,累是真累,但成就感也是真的大,尤其是当你半夜三点发现一个SSRF,然后验证成功的那一刻,简直比中了彩票还爽,如果你也在做Kibana代码审计,或者对Node.js安全感兴趣,欢迎一起交流,记得点赞转发啊,码字不易,且看且珍惜!

文章版权声明:除非注明,否则均为极客网安-咸鱼原创文章,转载或复制请以超链接形式并注明出处。

目录[+]