본문 바로가기
웹/드림핵

csrf-1

by SH_L 2022. 9. 3.
반응형

[문제]

 

 

[풀이]

 

@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

 

/vuln 페이지를 구성하는 코드이다. 코드를 살펴보면 이용자가 전달한 param 파라미터의 값을 출력한다. 이때, 이용자의 파라미터에 "frame", "script", "on" 3가지의 악성 키워드가 포함되어 있으면 이를 '*' 문자로 치환한다. 해당 키워드 필터링은 XSS 공격을 방지하기 위한 목적으로 존재한다.

 

 

/vuln 페이지에 접속하면 <script> 태그가 <*>로 치환된 것을 확인할 수 있다.

 

@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 페이지를 구성하는 코드이다. 코드를 살펴보면 이용자가 전달한 memo 파라미터 값을 기록하고, render_template 함수를 통해 출력한다.

 

 

/memo 페이지에 접속하면 memo.html의 내용을 확인할 수 있다.

 

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

 

/admin/notice_flag 페이지를 구성하는 코드이다. 코드를 살펴보면 로컬 호스트인 127.0.0.1에서 접근하고, userid 파라미터가 admin일 경우 memo_txt에 FLAG를 작성한다. 그 외의 경우에는 "Access Denied" 메시지가 출력된다.

 

 

/admin/notice_flag 페이지 자체는 모두가 접근할 수 있고, userid 파라미터에 admin 값을 넣는 것도 가능하다. 하지만 일반 유저가 admin인 것처럼 해당 페이지에 접근할 때의 IP address는 조작할 수 없다.

 

@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 페이지를 구성하는 코드이다. 코드를 살펴보면 메서드에 따른 요청마다 다른 기능을 수행한다. GET 메서드일 경우 이용자에게 URL을 입력받는 페이지를 제공한다. POST 메서드일 경우 param 파라미터 값을 가져와 check_csrf 함수의 인자로 넣고 호출한다.

 

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)

 

check_csrf 함수는 인자를 다시 CSRF 취약점이 발생하는 URL의 파라미터로 설정하고, read_url 함수를 이용해 해당 URL을 방문한다. 이때, 방문하는 URL은 로컬 호스트 이용자가 방문하는 시나리오이기 때문에 127.0.0.1의 호스트로 접속하게 된다.

 

flag를 얻기 위해서는 /admin/notice_flag 페이지를 로컬 호스트에서 접근해야 한다. 이를 위해 /vuln 페이지를 방문하는 로컬 호스트 이용자가 /admin/notice_flag 페이지로 요청을 전송하게끔 하는 것이 이 문제의 핵심으로 보인다.

 

 

/flag 페이지에서 “127.0.0.1”로 로컬 호스트가 지정되었기에 로컬 호스트 이용자가 /admin/notice_flag 페이지로 방문하도록 하는 코드를 이어서 작성한다. 이때, userid“admin"인 상태로 방문해야하기 때문에 <img src="/admin/notice_flag?userid=admin" />와 같이 익스플로잇 코드를 입력한다.

 

 

익스플로잇 코드를 제출한 다음에 다시 /memo 페이지로 돌아가면 플래그를 확인할 수 있다.

반응형

' > 드림핵' 카테고리의 다른 글

simple_sqli  (0) 2022.09.03
csrf-2  (0) 2022.09.03
xss-2  (0) 2022.09.01
xss-1  (0) 2022.08.21
Session-basic  (0) 2022.08.20