作者简介:
陈思雨(RickGray)
奇虎360 高级安全研究员
奇虎 360,Web 攻防团队 0keeTeam 成员之一。专注于 Web 方面漏洞的研究,喜好研究新的漏洞类型和攻击方法。
1、前言
作者来自360信息安全部的 0KeeTeam。作者专注于 Web 漏洞挖掘和分析以及安全工具的开发。本文列举两个漏洞组合场景,讲述如何从黑客的角度去看待运维中那些容易出现的漏洞点。
2、场景一:SSRF隔山打牛攻击Readis服务
你们是否有过这样的疑问,有业务暴露在外网的时候被攻击了,安全部门的同事要求搬到内网,运维们就要通过一些简单的做法直接把业务功能搬到内网。
接下来会用两个实际漏洞组合的例子,说明这些问题出现的点到底在哪里。
2.1 SSRF漏洞原理
SSRF 如何攻击内网的 Redis 服务的?
也许大家不是很清楚 SSRF 是什么,这是服务端的请求伪造,我用一个简单的流程讲一下 SSRF 漏洞的原理和具体的表现形式。
外网的服务器 O1 提供图片代理接口,用户提供图片的链接给了 O1。O1 根据地址请求资源,将具体的内容返回给用户。
正常的逻辑是一个用户,然后请求一个图片地址,到C1的服务器里取内容。O1直接请求 C1 上的资源返回给用户,这是正常的功能逻辑。
非正常的逻辑,一个黑客或者攻击者在看到这个连接地址后会怎么做呢?
搞安全人员会这样做,将图片连接替换成不是图片的资源连接,或者内网的地址。这时候如果 O1 没有做一些资源请求方面的限制,它就会去请求它所在内网的服务器上的资源,并返回给攻击者或者黑客。
刚才写到的漏洞流程中,黑客为什么可以将内网的资源请求并返回给攻击者?
第一、 O1图片没有对传过来的连接进行类型判断。
第二、 没有判断连接指向的资源是否是图片
第三、 没有判断请求资源是否是在可允许的范围之内,可能是内网的地址,也可能是敏感的服务器地址。
如果攻击者将参数替换成内网地址,O1会毫无保留请求地址,将资源内容返回给攻击者。这是简单的 SSRF 的漏洞原理和表现形式。
2.2 SSRF漏洞利用方式
首先,我们可以利用 SSRF 进行内网的端口扫描和 Web 指纹探测。如果请求内网地址的端口是存在的,在服务器返回给攻击者信息的时候,可能有500或者错误状态码,通过这些标志可以判断扫描的端口是否开放或者关闭的状态。
其次,针对内网应用服务的攻击,通过 Struts2 可以进行请求发送。在某一些应用漏洞中,可以直接地通过 GET 请求出发。SSRF
服务器的内网有 Struts 服务,我们可以通过 SSRF 直接尝试攻击内网的 Struts2 的服务。如果真的存在漏洞,攻击者间接的使用
SSRF 进行做这些应用。
最后转换协议。在 SSRF 向服务端请求的底层实现上,一般都是利用CURL 实现,用户所能控制的是 url 的值。如果我们讲常规的 http 协议转化成 file 协议,就会去请求本地的资源或者内网的文件,并且返回给攻击者。
gopher 协议,我们可以利用 gopher 协议对任意的端口进行应用层的数据发送。我列举了简单的例子,下面标注的是利用 gopher 协议实现请求的图。
以 gopher 协议开头,后面跟着是一个请求服务的地址,后面是一个端口。目录以下滑线作为关键字的开头,后面跟的就是具体应用层需要发送的数据。可以在 SSRF 利用中,通过 gopher 协议向任意的端口进行应用层数据的发送,这是比较关键的。
2.3 Redis未授权访问漏洞
Redis是比较流行的存储服务。大家知道的Redis漏洞中,未授权访问大家非常了解。
未授权访问这种漏洞,在我看来式因为运维人员或开发人员错误的配置造成的。一些官方的应用必须得给权限,但运维人员和开发人员在配置使用的过程中,没有按照官方的安全建议执行。
2.4 Redis未授权访问漏洞利用方式
我们可以通过攻击者未授权访问进行哪一些攻击?篡改 Redis 服务中的数据,清空数据进行破坏。
可以通过数据库备份的功能进行文件写的操作。怎样的条件下可以达到写文件的攻击?运行 Redis 服务的用户需要有一定的权限,可以往你所备份的数据库路径下写一个文件。
在 Redis 配置的时候,起用数据库备份的指令。在这儿已经列了一个 Save 和 Config。通过写文件操作,往服务器上写一个计划任务,这是后面所要执行计划任务的规则。
设置你所保存的文件名,刚刚说到了你所起的 Redis 服务,在这个路径下必须得有相应的文件操作权限,才可以成功地往里进行写入。下面是成功写入的截图。
简单说了 Redis 未授权访问利用的方式。据不完全统计,最近也经过一次扫描,发现在公网仍然存在着大约有1.5万台的服务器存在问题。
暴露在公网上的Redis有那么多,一些企业测试环境或者企业内部使用的Redis服务也是非常多。
2.5 组合利用两种漏洞攻击内网服务
我们如何攻击这些处在内网的 Redis 服务?
可以利用 SSRF 往内网发送任意的应用层数据,我们将 SSRF 漏洞和 Redis 未授权漏洞串联起来,我们就可以通过 SSRF 向内网的 Redis 服务进行攻击尝试。
有两个条件需要满足,第一存在 SSRF 漏洞的服务器必须得支持 gopher 协议,才可以成功地往内网的服务器端口进行数据发送。第二内网中确实有存在 Redis 的未授权服务。
我们将刚才 Redis 写计划任务的一系列指令,通过 gopher 协议进行封装。然后通过 SSRF 漏洞的接口,攻击者将这个参数替换成 gopher 的协议,O1解析 gopher 协议,向它处在的内网环境中的 Redis 服务进行攻击。
如果 L2 上的 Redis 服务确实存在未授权访问,且具有相应的权限,这时候攻击者就会成功地达到攻击的目标。
SSRF 堪称内网攻击的神器,在安全圈里。这是 SSRF 隔山打牛攻击内网的服务。
3、场景二:危险序列化结合脆弱中间件攻击分布式节点
3.1 危险的数据序列化
利用序列化的方式攻击分布式集群。数据序列化可以在不同的两个应用程序间进行对象的传递或者方法的调用。
在这儿有一个应用A,应用A中有一个对象A1,通过序列化方式以后,将序列化的数据传递给程序B,程序B通过反序列化的操作得到B1。
在一定的本质下,A1和B1的两个对象是等价的,包括了它们两个对象的属性值和一些相应的方法。不同之处,只是它们处在不同的应用环境或者不同的底层的地址上。
在历史上出现了很多反序列化造成的问题。PHP 有一些问题被攻击者利用,在底层代码实现的时候由于不安全的反序列化操作,造成了远程命令执行问题。
在 Django 框架下有 Session 控制的问题。Java 反序列化漏洞,当时涉及到的组件很多,上到 Java 外部框架下到 Java 的扩展库都存在着远程命令执行的问题。
在漏洞组合的例子中。这是 Java 反序列化执行命令的实例,上面是简单的代码。通过简单的操作,对用户输入的值进行反序列化的操作。下面通过传递一串特殊构造后的代码,在下面成功地触发命令执行漏洞。这个例子讲的是攻击和分布式框架。
3.2 窥探Celery中的消息队列
Celery 是 Python 中非常流行的分布式任务框架。Celery 消息队列间,通过队列的形式实现分布式任务的下滑。既然有消息的传递和分发,就会涉及到消息的封装。
一般分布式架构中都必须得有这两个东西,Celery 的框架中它所支持的消息中间件有 RabbitMQ、Redis、MongoDB,它所支持的消息封装方式,pickle、json、msgpack,yaml。
通过序列化操作将具体的任务信息进行封装,然后发送给中间件,中间件根据消息的具体路由信息,传递给具体的集群解析消息,并执行。
刚才所写到的 Celery 任务下发到流程中和刚刚提到的框架组成中,我不知道大家是否发现有比较明显的安全隐患。如果 Redis 和 pickle 存在安全隐患,如何结合这两点攻击后面所在的集群呢?
Redis 作为 Celery 中间件的时候,它的消息存储形式怎样?去除掉一些必要的字段后,我们可以看到在 Redis 中消息 JSON 的形式存储。比较关键的地方,它的 BODY 字段存储信息是 Celery 在任务下发那端,通过序列化的方式所形成的封装数据。
在默认配置下,Celery 又是使用 pickle 进行消息封装。Worke 端在得到消息后,会根据相应的配置反序列化,这一串数据。
简单的在 Worker 端可以用这个代码表示,通过 pickle 反序列化消息中的 boby 字段。
如果我们有可能去控制消息中间件,并且往其中写入我们想要的数据,这时候worke端反序列化的时候,就有可能反序列化我们注入的消息。
我们这里已经可以控制中间件,攻击者构造一个包含有恶意数据的消息,把它输入到消息中间件中,消息中间件根据攻击者所制造的路由信息会发送给 worke 端,worke 端根据配置反序列化这一串数据。如果整个流程都成功地话,worke 会有反序列化的漏洞。
3.3 脆弱的中间件
在上一个例子中,我也提到了 Redis 服务有大量的数量在互联网上暴露,并且存在未授权访问的问题。在 Celery 支持的中间件应用中,有 Redis 和 Mongo,它也是未授权访问的重灾区。
根据扫描统计,还有1.4万个 MongoDB 未授权暴露在官网上。有 Redis 未授权和 MongoDB 未授权存在着,数量也是非常大的。可以认为在未授权的 Redis 和 Mongo 中,确实存在着一些作为 Celery 中间件的应用。
如何从2.9万个未授权的服务中,鉴别这些服务是否作为Celery中间件而存在。如何检测 Celery 中间件在 Redis 和 MongoDB 中。我对 Redis 和 Mongo 进行分析,Celery 默认队列名是 Celery,你在写程序或者功能实现的时候可能有其它的队列,有队列A或者队列B,在这个地方可以存在 kombu binding。
3.4 Dancing on Internet
本地起了 Redis 服务,作为 Celery 的中间件。Celery 通过类型查看,存储的是具体的任务队列,保存在列表中。binding.Celery 字典的形式存在,保存的是路由的信息在里面。MongoDB 中 Celery 表现的形式,有刚刚提到的名称。我们如何结合这些安全问题攻击分析师框架呢?
需要具备几个条件,在使用 Celery 框架实现的应用中,它确实配置了 pickle 的消息封装方式进行处理。但经过了解,在 4.0.0 版本情况下 Celery 使用了 pickle 进行消息封装。
我们有可能控制消息中间件进行消息注入的操作,刚才写到了我们可以在1.5万个 Redis 和1.4万个 MongoDB 中,找出作为 Celery 中间件的应用进行攻击的尝试。
如果这一系列的流程都顺利,Worker 会解析攻击者注入的消息和数据,成功的触发一个反序列化的操作。成功的 Worker 会执行攻击者预先设定的指令和命令,不成功的肯定不受影响。
我们在针对这些命令检测的时候,如何判断漏洞是否有触发呢。我们需要在外网的回联服务器,我们在进行远程命令执行检测的时候,我们会将执行的命令设置为往我们服务器上发连接的具体形式。
我当时在进行全网验证的时候,设置了往我的服务器上进行简单的回联。在所执行的命令中进行标志位的处理,回联回来当时所在的用户是什么,我攻击的中间件IP和类型是什么。
我攻击的类型是 Redis,或者是 MongoDB。前面是 Worker 端执行的时候代表的用户,这是中间件的 IP
地址,这是中间件的具体应用类型。
这是这边的 IP 地址是 Worker 端回联的时候所在的 IP 地址,通过这两条消息的对比,我们可以看到在往
90.156 进行注入的时候,后端有两个不同的 Worker 触发了漏洞,并进行了回联,xx.xx.78.211 和 xx.xx.84.216。
通过简单的例子说明确实能够结合反序列化漏洞和消息注入攻击 Celery 分布式框架。存在消息注入的问题,不仅限于 Celery 的分布式框架,在其它的语言应用中也存在着这样的问题,只是没有被挖掘出来。
4、总结
为什么存在漏洞攻击的问题,最大的原因就是在存在 SSRF 漏洞的服务器上,没有限制接口资源的访问,这会导致攻击者可以控制你所请求的连接,然后可能会往你的内网服务器进行攻击的尝试。
在 SSRF 的漏洞中,它支持 gopher 协议进行更加广的攻击面。在企业内网中存在着很多弱口令服务,应用的弱口令或者说空口令。如果 Redis 的未授权,可能还有其它的一些未授权情况。
有一次做安全测试的时候,有一家公司叫我们从外网进行攻击尝试,我找到了 SSRF 漏洞。我对它的内网进行简单地探测,发现内网中存在着大量的 java 应用。
当时处在 java 反序列化爆发的期间,我自己已经把攻击的问题实现。我结合 SSRF 的漏洞攻击企业的内网,直接拿到了一台服务器权限。
这台服务器又保存了管理服务器的登录公钥和私钥,相当于集群部署的 muster 在服务器上,直接拿到了服务器下面的所有管理的服务器权限我都可以访问。
涉及到生产环境的服务器。说明在内网中这些脆弱的点,我们需要特别去关注。
反序列化的漏洞问题这跟运维关系不是特别大。开发人员进行功能开发的时候,常使用一些存在潜在问题的代码方法。
但运维在配置的时候存在一定的安全问题,也有 Redis 未授权口令问题。结合这些问题可以进行组合攻击,可以形成非常大的影响。
有一些关键字我进行了标记,那就是管理运维必须要注意的点。如未授权、服务器权限、配置不当、间接攻击、默认配置,未验证资源来源。
通过两个实例讲解,希望运维朋友们能够更加重视安全,重视运维过程中那些细小的点,不留下任何的安全隐患。
近期好文:
《一线券商教你如何保障大数据质量》
《一套高实用性基础架构,专治电商运维各种痛点》
《我是运维,我就这样挽救了800万用户》
《爱奇艺在搭建集群时遇到的那些“坑”》
《腾讯上万节点大规模集群的跨城自动迁移》
GOPS · 深圳站,运维人实现运维梦
参加GOPS越多
升职的几率越大
会议地点:南山区圣淘沙酒店(翡翠店)
会议时间:2017年4月21日-22日
您可点击“阅读原文”,享受特惠折扣购票