CSRF 문제 풀기

세바님·2024년 4월 20일
0

서론

오늘은 CSRF 공격 문제를 풀어보았습니다.

Dreamhack CSRF-1


먼저 vuln page를 누르고 들어가니 param에 넘긴 <script>alert(1)</script> 가 필터링 된 모습이다.
소스코드를 확인하니 frame, script, on을 필터링하는 코드가 있었다.

@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

그리고 /admin/notice_flaguserid 라는 쿼리 파라미터로 admin을 주면 플래그를 얻을 수 있다는 것을 발견했다.

@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

필터링을 피하면서 해당 경로로 접근하기 위해 img 태그의 src 속성을 이용했다.

실행하니 메모페이지에 플래그가 나온 모습이다. 굿

Dreamhack CSRF-2

이번엔 memo 페이지가 사라지고 로그인이 생겼다.

소스코드를 확인하니 vuln 페이지는 이전 문제와 동일한 모습이었다.
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", "")
        session_id = os.urandom(16).hex()
        session_storage[session_id] = 'admin'
        if not check_csrf(param, {"name":"sessionid", "value": session_id}):
            return '<script>alert("wrong??");history.go(-1);</script>'

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

어드민으로 로그인 해야 플래그를 얻을 수 있다는걸 알 수 있었다.

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    elif request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        try:
            pw = users[username]
        except:
            return '<script>alert("not found user");history.go(-1);</script>'
        if pw == password:
            resp = make_response(redirect(url_for('index')) )
            session_id = os.urandom(8).hex()
            session_storage[session_id] = username
            resp.set_cookie('sessionid', session_id)
            return resp 
        return '<script>alert("wrong password");history.go(-1);</script>'

추가로 현재 게스트 계정과 어드민 계정이 있는데, 게스트 계정은 username, password가 guest이고 어드민은 username이 admin, password는 플래그이다.

users = {
    'guest': 'guest',
    'admin': FLAG
}

또한, /change_password 에서 pw라는 쿼리 파라미터로 비밀번호를 바꿀 수 있다.

@app.route("/change_password")
def change_password():
    pw = request.args.get("pw", "")
    session_id = request.cookies.get('sessionid', None)
    try:
        username = session_storage[session_id]
    except KeyError:
        return render_template('index.html', text='please login')

    users[username] = pw
    return 'Done'

flag 페이지에서 post 요청을 보내면 session_id 를 admin으로 고치므로 이전 문제처럼 img 태그를 이용해 /change_password 로 요청을 보내면 될 것 같다.

바꾼 비밀번호로 어드민 계정에 로그인을 해보면?

로그인이 잘 된 모습이다. 굿

profile
꼴리는대로 사는게 꿈입니다

0개의 댓글