Security_Analysis

[DreamHack.io]_CSRF_1 본문

[Penetration]/_WEB

[DreamHack.io]_CSRF_1

Positivie 2023. 12. 1. 15:52
728x90
반응형

DreamHack.io 의 웹해킹의 다섯번째 문제 "CSRF_1" 를 풀어보자. 

 

  CSRF란

 "임의 이용자의 권한으로 임의 주소에 HTTP 요청을 보낼 수 있는 취약점으로, 공격자는 임의 이용자의 권한으로 서비스 기능을 사용하여 이득을 취할 수 있음"

 

app.py를 먼저 확인해보자

# app.py
# ========================================================

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("/vuln")
def vuln():
    param = request.args.get("param", "").lower()
    xss_filter = ["frame", "script", "on"]
    for _ in xss_filter:
        param = param.replace(_, "*")
    return param


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


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)


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

 

서버를 열어보면 이동할 수 있는 페이지가 4개 존재한다. 

Vuln(csrf) Page

먼저 vuln(csrf) page 로 이동해보았다 

URL에 GET방식으로 XSS 공격을 위한 예시구문이 실행되어 MessageBox(Alert) 창이 열린것을 확인했다. 


Memo Page

두번째로 memo 페이지로 이동해보았다. 

memo 페이지로 이동해보니 역시 이 페이지 또한 GET 방식으로 URL에 있는 값을 입력해주는 것으로 확인할 수 있다.

 


Notice Flag Page

세번째 페이지 notice flag로 이동해보았다.


Flag Page

마지막으로 네번째 페이지 flag로 이동해보았다. 


힌트 

코드를 통해서 몇가지 인트를 얻었다.

<1>. notice_flag 페이지는 접속한 IP가 "127.0.0.1"  != Access Denied 출력

 <2>. notice flag 페이지의 접속한 USERID가 admin이 아니면 != Access Denied 2 출력

 <3>. flag 페이지에다가 값을 넣으면 check_csrf 함수를 통해서 parameter를 urlib.parse.quote(param) 을 통해 read_url에 넘긴다


풀이

1번째 힌트인 request.remote.addr 은 파라미터로 가져오는게 아니기 때문에 조작할 수가 없다고 판단해서 PASS

2번째 힌트는 request.args.get 으로 파라미터에서 인자를 가져오는 것이기 대문에 userid 값에 admin을 넣어서 /admin/notice_flag에 전달 하도록 작성해 보았다. 

제출 버튼을 누르고 난후 memo 페이지로 접속해보면 아래와 같이 플래그가 확인된다. 


 

플래그 찾기 성공!

 

 다음 문제 :  CSRf_2

 


※ 마지막 확인하는 부분에서 코드를 제대로 확인하지 않아 실수를 했었다.

      파라미터로 /admin/notice_flag에다가 userid='admin' 을 넣어서 보냈기 때문에 제출 버튼 이후에 "/admin/notice_flag" 로 접속했던 것이다 . 그 결과는 역시나 "Access Denied"가 나왔다. 

 

 코드를 다시 한번 살펴보고 이해를 할 수 있었다.

 

 1). 먼저 flag 페이지에다가 코드를 넣었으니 check_csrf(param) 을 통해서 check_csrf 함수를 실행시켰을 것이다.

 2). check_csrf 함수에서 param= 뒤에는 공격자가 입력한 코드가 있을 것이다. 

 3). 이거를 url 변수로 하여 read_url로 넘겼다. 

 4). read_url 에서는 127.0.0.1:8000 으로 driver.get을 했고 url에도 127.0.01:8080 이 있는 상태이며 get으로 열었기 때문에 admin_notice_flag의 두가지 조건을 만족했다.

 5). (request.remote.addr / request.args.get) 을 만족했기 때문에 get으로 url 불렀을 때 flag가 memo_text에 추가되었고, 

 6). 사용자가 memo 페이지를 눌렀을 때는 global 로 memo_text 값을 가져오기 때문에 flag가 보인 것이다.

def read_url(url, cookie={"name": "name", "value": "value"}):
	# 생략 # 
        driver.get("http://127.0.0.1:8000/")
        driver.get(url)

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

        return '<script>alert("good");history.go(-1);</script>'
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)


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


app.run(host="0.0.0.0", port=8000)

 

 

 

P.S> 모의해킹 자체를 처음하다보니 제가 알고있는게 많이 적어서,,, 혹시나 제가 생각했던게 잘못되었을 경우 언제든 피드백 부탁드립니다. 

728x90
반응형

'[Penetration] > _WEB' 카테고리의 다른 글

[DreamHack.io]_SqlInjection_1  (0) 2023.12.03
[DreamHack.io]_CSRF_2  (0) 2023.12.02
[DreamHack.io]_(4)_XSS_2  (1) 2023.11.30
[DreamHack.io]_(3)_XSS_1  (0) 2023.11.29
[DreamHack.io]_(2)_Session  (0) 2023.11.28