最近,Java的FTP URL处理代码中的一个协议流注入漏洞已经被安全研究人员发现并公布,它允许协议流注入。根据研究,这个协议流注入漏洞可以利用现有的XXE或SSRF漏洞,让黑客通过SMTP协议从Java应用程序发送未经授权的恶意电子邮件。
像这样的协议注入漏洞,这几年一直是一些安全专家研究的重点领域,最新的研究发现, 黑客会利用FTP这样的协议注入漏洞绕过目标设备所设置的防火墙,进而与目标主机系统建立远程TCP连接(端口1024-65535)。不过研究还发现,Python的urllib2和urllib库也存在一模一样的漏洞。不过黑客可以利用Java漏洞,在用户没有启用任何的Java浏览器插件的情况下,对桌面用户进行攻击。
不过截止2017年2月20号,以上所披露的这些漏洞还没有被相关厂家修复。
漏洞介绍
实际上Java很容易通过URL中的多个数据字段进行注入攻击,包括URL中的用户名字段以及地址中所指定的任何目录。虽然Python里的URL库(Python2的urllib2以及Python3的urllib)同样存在类似的协议流注入漏洞攻击,但黑客仅能通过URL中指定的目录名称来实施攻击,所以攻击所造成的危害是非常有限的。
一般来说,黑客可以利用恶意URL中的FTP协议流注入漏洞来对Java进行攻击。如果黑客可以让被攻击的Java应用去获取恶意URL指定的目录名称,那么黑客就可以将FTP命令注入客户端的协议流中。以下面这个URL为例,
这样就可以向TCP流数据中添加新行了,然后让 邮件接收服务器误认为URL中的“INJECTED”是客户端发送的一条命令。当Java应用获取到了上面的这个URL之后,会将其切分成多个单独的指令序列来发送,
FTP的安全问题介绍
为了能够完全理解本文所介绍的攻击,我们就必须清楚的了解FTP协议的工作原理。FTP(File Transfer Protocol)是文件传输协议的简称。用于Internet上的控制文件的双向传输。同时,它也是一个应用程序(Application)。用户可以通过它把自己的PC机与世界各地所有运行FTP协议的服务器相连,访问服务器上的大量程序和信息。
FTP的主要作用,就是让用户连接上一个远程计算机(这些计算机上运行着FTP服务器程序)察看远程计算机有哪些文件,然后把文件从远程计算机上拷到本地计算机,或把本地计算机的文件送到远程计算机去。
FTP通信首先要建立一个数据通道,因为只有数据通道才能传输目录和文件列表,然后是在控制信道中,由客户端(一般通过端口21)与服务器建立一条TCP连接,通过控制信道来发送各种命令。
FTP两种工作模式介绍:
1.主动FTP模式
最初的FTP规范中使用的就是传统的主动模式的FTP。在这种模式下,客户端从一个临时端口(大于1024的端口号)连接到FTP服务器的命令控制端口(端口21),当客户端准备好传输数据时,FTP服务器从其数据端口(端口21)打开一个到该IP地址和客户端提供的临时端口的连接。这里的关键是不向服务器发起真实的数据连接,而是告诉服务器他自己的端口号(通过执行port命令);然后服务器连接回到客户端指定的端口。在这种模式中服务器被认发起者。
对于防火墙之后的客户端,主动模式的FTP会有点小问题。
从2002年开始, FTP的传统模式一直就不断被攻击,当时有一名用户意外地在一个Web页面中加载了一个非特权Java Applet,这个Applet可以让目标主机建立一条指向攻击者服务器的FTP控制通道,然后让防火墙开启任意TCP端口并将它们转发回受害者的桌面系统,到目前为止,十五年过去了,很多商业防火墙仍然默认支持这种FTP的传统模式。
2.被动FTP模式
FTP客户端执行pasv命令表明它希望以被动模式来访问数据,服务器响应以其IP地址和一个客户端可以连接来传输数据的临时端口。客户端运行的pasv命令告诉服务器监听一个非正常端口(即端口20)的数据端口,然后等待客户端的连接,而不是自己发起新连接。这里的关键区别在于客户端初始化到服务器所提供的IP地址和端口的连接。在这种关系中,服务器被认为是数据通讯的被动者。
但是随着防火墙和网络地址翻译器(NAT)的广泛使用,防火墙也开始支持“被动”模式的FTP了,利用动态路由算法来将服务器端发起的TCP连接定向转发到相应的主机。
绕过防火墙
由于这个FTP控制通道的注入漏洞允许我们控制FTP客户端所发送的命令,所以我们现在可以还原一下2002年的那次绕过防火墙的攻击,我们可以向流数据中注入一个恶意的PORT命令,当防火墙收到这个命令之后,它会将该命令的内部IP地址以和端口转换成外部IP和端口,然后使用一个临时的网络地址翻译器(NAT)规则并建立单向的TCP连接,然后将数据传送给FTP客户端。
假设目标主机的内部IP地址为10.1.1.1,黑客的服务器为evil.example.com。我们就可以通过下面这个FTP URL来诱骗防火墙开启1337端口,
不过,在传统模式的FTP PORT命令中,端口号会被切分成两个ASCII码字节,即1337 == 5*256 + 57。不过要想要在传统模式的环境中实现攻击,还有两个问题要解决:
第一个问题:确定内部IP地址
要解决这个问题,攻击者需要首先确定目标主机的内部IP地址,否则防火墙将会忽略我们注入的PORT命令。这时,黑客会发送一个URL,看看客户端会有什么反应,然后再不断进行攻击(一般情况下,只需2-3次尝试便会成功)。
在刚开始进行客户端试探时,黑客会给攻击目标提供一个指向攻击者服务器异常端口的FTP URL,不如下面这个URL,
不过,在进行这一步操作时,还没有用到协议流注入攻击尝试。而是用FTP客户端启动被动会话并检索z.txt文件,但如果黑客的FTP服务器拒绝PASV命令,则客户端会以传统模式发送PORT命令。
由于控制通道使用的是非标准端口,所以目标主机的防火墙解析出会话中的PORT命令是不太能的,这就会导致被攻击者的内部IP地址被泄露给黑客。
问题二:数据包分组
FTP被设计为同步的、基于文本行的协议,通信双方的数据是按行传输的。这也就意味着通信的双方必须在下一行命令进行之前就相互响应。
因为目前大多数商业防火墙都是安装在Linux平台中的,所以就以Linux的conntrack模块为例来分析。
linux内核中的netfilter是一款强大的基于状态的防火墙,具有连接跟踪(conntrack)的实现。conntrack是netfilter的核心,许多增强的功能,例如,地址转换(NAT),基于内容的业务识别(l7, layer-7 module)都是基于连接跟踪。
所以在conntrack环境下,黑客就必须确保在攻击进行之前,PORT命令出现在数据包的头部,所以下面这个URL并不会让Linux防火墙打开目标端口。
仔细分析一下这个URL的数据包跟踪。你就会发现客户端所发送的命令被分割成了单个的数据包。
所以,即便Java或Python可以在一次write(2)调用中发送两条指令,我们还是要找到一种方法来迫使客户端在数据包的头部发送PORT命令。因为用户空间应用程序可能对具有远大于TCP/IP网络数据流所形成的那些单个的数据包的write(2)调用,所以我们要使用的CWD命令的目录要足够长,才能完全充满了一个TCP数据包,自然PORT命令就会进入到下一个数据包的头部了。
不过这么做并非万无一失,因为MTU值(此值设定TCP/IP协议传输数据报时的最大传输单元)可能相对较大, Java 或Python应用程序可能会攻击期间拒绝执行这种非常长的URL。此外,任何一对主机之间的网络变化,都会让MTU值的发生变化。为了避免这样的问题出现,我们可以强制FTP控制通道的TCP连接使用最小的MTU值,不过在攻击时,防火墙规则可以将最大报文段长度(MSS)压缩到536字节,这样就更容易计算出恶意URL的长度。规则(rules)其实就是网络管理员预定义的条件,规则一般的定义为“如果数据包头符合这样的条件,就这样处理这个数据包”。规则存储在内核空间的信息 包过滤表中,这些规则分别指定了源地址、目的地址、传输协议(如TCP、UDP、ICMP)和服务类型(如HTTP、FTP和SMTP)等。当数据包与规 则匹配时,防火墙就根据规则所定义的方法来处理这些数据包,如放行(accept)、拒绝(reject)和丢弃(drop)等。配置防火墙的 主要工作就是添加、修改和删除这些规则。
验证攻击
为了对前文所述的漏洞进行攻击验证,目前研究者已经开发出了对应的攻击脚本,当脚本启动时,
脚本首先会给黑客提供一个URL来对目标主机进行测试,然后启动恶意FTP服务器。当服务器接收到第一个请求之后,FTP服务器便会计算出一个包含目录的新URL,该目录的长度足以让PORT命令进入到下一个数据包头部。一般来说,整个攻击过程(包括用于确定受害者的内部IP的请求)只需要三次SSRF攻击便可以完成,之后就能在目标主机上打开一个TCP端口,如果这一步成功了,以后每一次的SSRF攻击都会对应的打开一个TCP端口。由于大部分防火墙不允许客户端在1024以下的端口设置FTP数据通道,因此黑客的攻击端口范围一般是1024-65535之间。
但是在Oracle公司和Python开发者修复相应漏洞之前我不会将这个脚本发布出来。
不过大家不用担心,在Oracle和Python的开发人员修复相应漏洞之前,他们是不会将这个攻击验证脚本公布的。
攻击场景
在各种各样的攻击场景中,Java应用程序获取URL的方法各不相同,我们在这里一一分情况说明一下:
1.JNLP文件
这个攻击场景确实很让人意外。如果在安装了Java的情况下,桌面用户访问恶意网站,那么即使Java applet被禁用,黑客仍能让Java Web Start来解析JNLP文件,而这些文件中将包含可以触发该漏洞的恶意FTP URL。一个聪明的黑客可以利用这个漏洞利用来识别受害者的内部IP地址,然后计算出数据包分组,一次性完成攻击,另外一个聪明的黑客甚至可以利用一个JNLP文件同时开启多个通信端口。还要注意,由于Java能在防火墙向用户发出任何安全警告之前就解析JNLP文件,所以这样的攻击完全可以在用户毫不知情的情况下完成。(除非浏览器本身就会警告用户Java Web Start已经启动)。
2. 中间人攻击
如果Java或Python(urllib)应用程序正在获取任何HTTP URL,则拥有某些管理权限的网络攻击者便会趁机注入HTTP的重定向来发起攻击。
3. 服务器端请求伪造(SSRF)
如果应用程序能接受任何HTTP,HTTPS或FTP URL,则攻击就更加简单了。通过简单地将客户端重定向到恶意FTP URL就可以实现攻击了。
4. XML外部实体注入攻击(XXE)
大多数XXE的漏洞都会产生类似SSRF访问,所以这种攻击也是很简单的。请注意,由于XML解析设置的问题,某些XXE漏洞并不能用来进行攻击。但是,在某些情况下,SSRF仍然可能通过DOCTYPE标签,比如XML解析器可以对外部漏洞进行利用,那黑客就可以在一个单一的文件中注入URL,然后由此来确定目标的内部IP地址,对数据包分组并最终使用动态重定向来进行攻击。
防火墙测试
由于许多商业防火墙使用Linux作为其设备的基本操作系统的缘故,大多数FTP攻击测试都是针对Linux内核防火墙的,在许多情况下,这些防火墙都默认启用传统的FTP模式。比如通过对Palo Alto防火墙和Cisco ASA防火墙进行的攻击测试,这两个防火墙在默认设置下都很容易受到攻击。虽然对商业防火墙的测试并不能说明所有问题,但可以推测目前大部分防火墙都容易受到FTP协议流注入的攻击。
漏洞责任披露
Python安全小组在2016年1月就发布了FTP协议流注入攻击的提醒,但截至目前他们仍然没有采取明显的行动。
Oracle在2016年11月初就对各个厂商通知了攻击的完整细节,不过目前没有适用于Java的修补程序。
安全防护的建议
1.给商业防火墙供应商的建议
禁用传统模式的FTP,向配置接口添加必要的警告提示
2. 给Linux netfilter团队的建议
在conntrack模块中开启FTP转换可能带来的安全风险提示,避免其他开发商以及提供商再犯同样的错误。
3.给其他软件制造商和服务提供商的建议
对自己生产的产品进行漏洞处理,确保它们不会受到SSRF或XXE攻击的影响。因为目前在默认情况下,Java中的XML解析很脆弱,使得XXE漏洞非常常见。
4.给普通用户的建议
建议从所有桌面系统中卸载Java。如果由于原来应用程序的某些功能会受到影响,建议从所有浏览器中禁用Java浏览器插件,并解除.jnlp文件扩展名与Java Web Start二进制文件之间的关联。另外请把在应用程序服务器和设备上运行的各种Java和Python的应用升级到最新版本。在防火墙的所有FTP模式中,仅仅使用“被动”模式就可以了。