首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【DASCTF】百万富翁

【DASCTF】百万富翁

作者头像
熔城Sec
发布2026-09-15 14:09:13
发布2026-09-15 14:09:13
1070
举报

01

题目简介

  • 题目名称:百万富翁
  • 题目平台:CTF²
  • 题目类型:Web

02

解题步骤

启动并访问靶机

根据题目猜测,应该是需要我们打到一百万分。但是手动操作基本是不可能的,所以我们只能查看JS文件了。我们在Player.js里面发现了金币更新的方法updateCoin()

阅读代码,这段代码是更新金币数的,但是里面有两个加密了的中奖弹窗,这两个弹窗的解密逻辑是一样的!

先看到两个base64加密的数组

代码语言:javascript
复制
var _0x3f85=['MxXCgw4=','w53DhVRWw6X...ZMKF'];

之后有一个解码的function,这个方法有两个输入,_0x3f85fc要看输入的是哪个数组,_0x57fdeb就是密钥了。

代码语言:javascript
复制
var _0x57fd=function(_0x3f85fc,_0x57fdeb){ ... }

然后解密的逻辑是base64→UTF-8→RC4,明白逻辑之后,所以就能构建脚本了。使用AI辅助构建脚本很方便

代码语言:javascript
复制
# -*- coding: utf-8 -*-
"""
复刻浏览器解密管线:atob(base64) -> %XX 编码 -> decodeURIComponent(UTF-8) -> RC4(key) 异或
等价于:base64 解码得到字节 -> 按 UTF-8 解码成字符串 -> 标准 RC4 解密
"""
import base64
import re
_HEX = set('0123456789abcdefABCDEF')
def extract_flag(f1: str, f2: str) -> str:
    """
    两段弹窗文本各含半截 flag,拼出完整 DASCTF{...}:
      f1 = ...DASCTF{<前半 hex>      (无闭合 })
      f2 = <后半 hex> }...           (无开头 DASCTF{)
    做法:左半从 'DASCTF{' 起只保留 hex;右半从 '}' 往前回溯 hex;再拼回。
    """
    # 左半:去掉字面前缀 'DASCTF{',再去掉其余非 hex 字符
    left = f1[f1.index('DASCTF{') + len('DASCTF{'):]
    hex_left = re.sub(r'[^0-9a-fA-F]', '', left)
    # 右半:从最后一个 '}' 向前回溯连续的 hex 字符
    end = f2.rindex('}')
    start = end
    while start > 0 and f2[start - 1] in _HEX:
        start -= 1
    hex_right = f2[start:end]
    return 'DASCTF{' + hex_left + hex_right + '}'
def rc4(data: str, key: str) -> str:
    """
    标准 RC4 解密(对称,加密解密同一套逻辑)。
    - data: 待解密字符串(已按 UTF-8 解码后的字符串)
    - key : RC4 密钥(字符串,如 'dhCd')
    返回解密后的明文字符串。
    """
    # 1) KSA:初始化并打乱 S 盒
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + ord(key[i % len(key)])) % 256
        S[i], S[j] = S[j], S[i]
    # 2) PRGA:生成密钥流并与密文逐字符异或
    out = []
    i = j = 0
    for k in range(len(data)):
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        # ord(data[k]) 对应 JS 的 data.charCodeAt(k)
        out.append(chr(ord(data[k]) ^ S[(S[i] + S[j]) % 256]))
    return ''.join(out)
def decrypt(b64: str, key: str) -> str:
    """
    解密单段密文:
      b64  -> base64 密文(题目 JS 数组里的字符串)
      key  -> RC4 密钥(题目函数调用里的第二个参数)
    """
    raw = base64.b64decode(b64)   # 1) atob:base64 -> 原始字节
    text = raw.decode('utf-8')    # 2)+3) %XX 编码 + decodeURIComponent == 按 UTF-8 解码
    return rc4(text, key)         # 4) RC4 解密
# ===== 题目原始数据(来自 Player.js 的 _0x3f85 / _0x3dd2 数组)=====
# 第一段:金鲨条件
A = [
    'MxXCgw4=',
    'w53DhVRWw6XDjcOJCMOOw7TDq8OfwrbDlzh5TCXDpsOzw5o0wpzComjDv2zDucO/w4nDsMODwpLDk8Kpw60eK07ChgzDmGpTJcOPECZowp0Gwq0awrp9wodQw5RuwoEPw74FJ3nDg2x8IkvCuMO4w5PCjMKJZMKF'
]
# 第二段:百万富翁条件
B = [
    'ZUXDiiA=',
    'e8KafsKXw4XCgw3CiG/CgcKCw74rwqIow6w/UE4JwoHDi8KNw7o6wovDscOAw7nCq2nCiMKcwpMWw50QwrNLwqrCk8KJbsKuwrIPwrADLcOWZ8OCw4QKwqhpw5MgwrjDqRJqOsO2wpnCslLCoWhPw5Jkf3s='
]
if __name__ == '__main__':
    print('[段1] 属性名 =', decrypt(A[0], 'HhP['))   # 期望 'coin'
    print('[段1] flag前半 =', decrypt(A[1], 'dhCd'))
    print('[段2] 属性名 =', decrypt(B[0], 'fhy)'))   # 期望 'coin'
    print('[段2] flag后半 =', decrypt(B[1], 'GK)i'))
    # 两段各含半截 DASCTF{...},拼出完整 flag
    flag = extract_flag(decrypt(A[1], 'dhCd'), decrypt(B[1], 'GK)i'))
    print('\n==== 完整 flag ====')
    print(flag)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-08-28,如有侵权请联系 cloudcommunity@tencent.com 删除
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档