TenDollar CTF 2018 XSS

CTF/Writeup 2018. 12. 1. 12:37

해당 문제는 들어가보면 여러기능중 Contact 기능만 동작한다. 해당 기능은 문제 이름에서 보이듯이 XSS가 터진다. 

XSS에는 별다른 필터는 없었는데 세션 값이 안날라왔다. 근데 잘 보면 아래와 같이 Referer 헤더에 admin 관련 URL이 존재한다.



해당 URL 구조를 봐서는 url 파라미터로 받아온 값을 서버측에서 요청하는 구조라 SSRF가 터질거라 생각했고  file wrapper를 사용해보니 정상적으로 파일을 읽어올 수 있었다.


file:///proc/self/cmdline

file:///tmp/uwsgi.ini


순으로 소스코드 파일 경로 확인 후 보면 아래와 같다.


main.py


# -*- encoding:utf-8 -*-

from flask import Flask, render_template, render_template_string, request

import sqlite3

import urllib2

from selenium import webdriver


app = Flask(__name__)


createtable = """CREATE TABLE IF NOT EXISTS contact (

id integer PRIMARY KEY AUTOINCREMENT,

email text,

message text,

is_checked integer DEFAULT 0

);

"""


@app.route("/")

def index():

return render_template('index.html')


@app.route("/contact")

def login():

return render_template('contact.html')


@app.route("/submit", methods=['GET'])

def submit():

email = request.args.get('email')

message = request.args.get('message')


conn = sqlite3.connect("/tmp/mydb.db")

cur = conn.cursor()

cur.execute(createtable)


sql = "insert into contact(email, message) values (?, ?);"

cur.execute(sql, (email, message))

conn.commit()

conn.close()


bot()


return "<script>alert(\"접수 완료\"); history.back(-1);</script>"


@app.route("/admin", methods=['GET'])

def admin():

_id = request.args.get('_id')

_pw = request.args.get('_pw')

_email = request.args.get('email')


if not (_id == "admin" and _pw == "admin123^__^"):

return "do not hack!"


conn = sqlite3.connect("/tmp/mydb.db")

cur = conn.cursor()

cur.execute(createtable)


sql = "select * from contact where is_checked = 0 limit 1;"


if _email is not None:

sql = "select * from contact where email = '%s' limit 1;" % _email.replace("'", "''")


cur.execute(sql)

rows = cur.fetchall()


if len(rows) == 0:

conn.close()

return "None"


idx = rows[0][0]

email = rows[0][1]

message = rows[0][2]

is_checked = rows[0][3]


sql = "update contact set is_checked = 1 where id = %d" % idx

cur.execute(sql)

conn.commit()

conn.close()


result = """

idx : %d<br>

email : %s<br>

message : %s<br>

is_checked : %d<br>

""" % (idx, email, message, is_checked)


return render_template_string(result)


@app.route("/archiver", methods=['GET'])

def archiver():

url = request.args.get('url')

r = urllib2.Request(url)

r.add_header('Referer', request.url)

return urllib2.urlopen(r).read()


def bot():

options = webdriver.ChromeOptions()

options.add_argument('headless')

options.add_argument('window-size=1920x1080')

options.add_argument("disable-gpu")

options.add_argument("--no-sandbox")

driver = webdriver.Chrome('./chromedriver', chrome_options=options)

driver.get('http://localhost/archiver?url=http%3A%2F%2Flocalhost%2Fadmin%3F_id%3Dadmin%26_pw%3Dadmin123%5E__%5E')

driver.implicitly_wait(1)

driver.quit()


if __name__ == "__main__":

app.run(host='0.0.0.0', debug=True, port=80)



코드를 쭉 보다보면 아래 코드를 통해 SSTI가 터지는걸 볼 수 있다.


result = """

idx : %d<br>

email : %s<br>

message : %s<br>

is_checked : %d<br>

""" % (idx, email, message, is_checked)

return render_template_string(result)


여기서 취약점을 터트리기 위해 사이트 내에서 유일하게 사용가능했던 contact 기능을 통해 message에 SSTI 구문을 아래와 같이 넣어봤다.


http://web1.tendollar.kr:10102/submit?email=JeonYoungSin&message={{7*7}}


그 후 아래와 같이 해당 이메일 접수글을 조회해보면 SSTI가 실제로 터지는걸 볼 수 있었다.



여기서부터는 별다른 필터가 없어서 아래와 같이 플래그를 가져왔다.







Flag = TDCTF{XSS_m3anS_n0t_jUSt_XSS_But_X55_SSRF_S5TI}































'CTF > Writeup' 카테고리의 다른 글

TenDollar CTF 2018 Cat-Proxy  (0) 2018.12.02
TenDollar CTF 2018 Kou  (0) 2018.12.01
TenDollar CTF 2018 LinkedList - 1,2  (0) 2018.12.01
TenDollar CTF 2018 Ninja  (0) 2018.12.01
TenDollar CTF 2018 I'm Blind Not Deaf  (0) 2018.12.01
블로그 이미지

JeonYoungSin

메모 기록용 공간

,