소스코드 분석
CONFIG = {
"SECRET": "DH{fake-fake-fake}"
}
class DataConfig(object):
def __init__(self, name):
self.name = name
def print_data(format_string, config_data):
return format_string.format(config_data=config_data)
config_data = DataConfig("How can I get the flag?")
@app.route('/',methods=['GET'])
def page1():
payload = request.args.get('body')
sys.stdin = io.StringIO(payload)
result = print_data(sys.stdin.readline(), config_data)
return render_template('index.html', value=result)
<print_data 함수>
format_string, config_data를 파라미터로 받는다. 그리고 만약 format_string의 값이 {config_data}라면
{config_data.__format__("")}를 내부적으로 호출한다. 클래스의 별도 정의가 없다면 object의 기본 구현이 동작한다.
하지만 만약 {config_data.name}이라면 DataConfig의 name이 호출된다.
<page1() 함수>
body라는 사용자 요청을 받고 payload라는 변수에 저장한다. 그리고 sys.stdin = io.StringIO(payload)를 실행하는데, 여기서 사용자 입력인 payload가 검증 없이 들어간다 -> 취약함
다음으로는 result = print_data(sys.stdin.readline(), config_data)를 통해 sys.stdin.readline()에는 사용자의 요청이 들어가고 config_data를 print_data의 config_data 인자값으로 들어간다.
익스플로잇
사용자 입력에 아무런 검증을 하지 않기 때문에
{config_data.__init__.__globals__}
를 입력하게 되면 flag를 얻을 수 있다.
그 이유는 config_data.__init__.__globals__는 DataConfig가 정의된 모듈의 전역 변수 사전이기 때문에 해당 웹 서비스의 모든 전역 변수를 출력해준다.
우리는 CONFIG의 값을 알아내야하기 때문에 해당 페이로드를 전송해주면

위와 같이 모든 전역 변수를 출력해주기 때문에
{'SECRET': 'DH{Ilovepythonandformat}'} 처럼 CONFIG의 값도 알 수 있다.
'CTF & Wargame(WEB)' 카테고리의 다른 글
| Dreamhack Movie time table (0) | 2025.06.01 |
|---|---|
| Dreamhack Switching Command (0) | 2025.05.30 |
| dreamhack username:password@ 풀이 (0) | 2025.05.20 |
| Black-Hacker-Company (0) | 2025.05.14 |
| SSTI 관련 문제 풀이 (0) | 2025.05.04 |