[웹해킹] csrf-1

Woo·2025년 1월 8일

워게임(웹해킹)

목록 보기
6/14

📖문제

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


📖 분석

해당 문제는 CSRF 취약점을 사용해 플래그를 획득하는 문제이다.
서버 생성 후 사이트를 들어가본다.

총 5개의 페이지가 존재한다.

📗 / 페이지

@app.route("/")
def index():
    return render_template("index.html")

📗 /vuln 페이지

@app.route("/vuln")
def vuln():
    param = request.args.get("param", "").lower()
    xss_filter = ["frame", "script", "on"]
    for _ in xss_filter:
        param = param.replace(_, "*")
    return param

이 문제는 xss문제가 아니므로 xss에 관련 공격을 필터링 걸어놨다.
frame, script, on이 3가지 키워드가 들어가는 문자열은 *으로 치환한다.

📗 /memo 페이지

memo_text = ""


@app.route("/memo")
def memo():
    global memo_text
    text = request.args.get("memo", None)
    if text:
        memo_text += text
    return render_template("memo.html", memo=memo_text)

memo 파라미터의 값을 기록하고, render_template를 사용해 출력한다.

📗 /admin/notice_flag 페이지

@app.route("/admin/notice_flag")
def admin_notice_flag():
    global memo_text
    if request.remote_addr != "127.0.0.1":
        return "Access Denied"
    if request.args.get("userid", "") != "admin":
        return "Access Denied 2"
    memo_text += f"[Notice] flag is {FLAG}\n"
    return "Ok"

로컬 호스트(127.0.0.1)에서 유저 아이디가 "admin"일 때 플래그를 획득할 수 있다.
memo 페이지에 플래그를 출력함을 알 수 있다.

📗 /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_csrf(param):
            return '<script>alert("wrong??");history.go(-1);</script>'

        return '<script>alert("good");history.go(-1);</script>'

param 파라미터를 check_csrf 함수를 통해 참이면 good 메시지를 띄운다.
이래 아래 app.py에서 동작을 하는 함수들을 살펴보자

📘 app.py

주요 코드

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()
        print(str(e))
        # return str(e)
        return False
    driver.quit()
    return True


def check_csrf(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)

우선 위의 flag 페이지에서 check_csrf함수를 사용하였기에 이 함수 먼저 살펴보면 인자를 다시 CSRF 취약점이 발생하는 URL의 파라미터로 설정하고, read_url 함수를 이용해 방문한다.

read_url 함수에서 url은 서버가 동작하고 있는 로컬호스트의 이용자가 방문하는 시나리오이기 때문에 127.0.0.1의 호스트로 접속하게 된다.


📖 풀이

/vuln 페이지에서 frame, script, on 키워드를 금지하였으나 <, >같은 태그를 사용할 수 있기 때문에 csrf 공격이 가능하게 된다.

<img src="/admin/notice_flag?userid=admin" />을 작성해 공격을 시도하면 플래그를 얻을 수 있다.

good 메시지가 출력이 되고, memo 페이지에 가보면 플래그가 쓰여져있을 것이다.

profile
다덤벼

0개의 댓글