SONOTRI
  • cookie[web]
    2024년 12월 28일 04시 24분 40초에 업로드 된 글입니다.
    작성자: sonotree
    문제 설명
    쿠키로 인증 상태를 관리하는 간단한 로그인 서비스입니다.
    admin 계정으로 로그인에 성공하면 플래그를 획득할 수 있습니다.
    플래그 형식은 DH{...} 입니다.

    Approach: Code

    <login 엔드포인트>

    users = {
        'guest': 'guest',
        'admin': FLAG
    }
    
    @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')) )
                resp.set_cookie('username', username)
                return resp 
            return '<script>alert("wrong password");history.go(-1);</script>'
    
    app.run(host='0.0.0.0', port=8000)

     

    request.from
    클라이언트가 POST 요청을 보낸 데이터를 포함하는 딕셔너리 형식의 객체이다. 

    .get('[key]')
    request.form은 딕셔너리처럼 동작하므로, .get() 메서드를 사용해 특정 키 값을 가져올 수 있다.

    username = request.form.get('username') 부분을 통해 POST 요청의 폼 데이터에서 name='username' 필드 값을 가져온다. password도 마찬가지이다.

     

    그리고 try: pw = users[username]를 살펴보자. users는 위에서 딕셔너리 형태로 정의되어있다. request.form.get('username')에서 받아온 username 변수 값이 딕셔너리의 key 값으로 존재하는지 확인하며, 해당 값을 pw 변수에 저장한다. 만약 username이 users 딕셔너리의 키 값으로 존재하지 않으면 except 부분이 실행된다.

     

    make_responese:
    이 함수는 HTTP 응답 객체를 생성한다. 여기서는 redirect(url_for('index'))를 사용하여 사용자를 / 페이지(index)로 리디렉션 한다.

    redirect
    클라이언트를 지정된 URL로 이동시키는 HTTP 응답

    set_cookie
    응답 객체에 쿠키를 추가한다. resp.set_cookie('username', username) 여기서는 username 쿠키를 생성하고, 그 값으로 사용자가 입력한 username을 설정한다. 이후 클라이언트는 쿠키에 username 값을 저장하게 된다.

    return resp
    설정된 응답 객체 resp를 클라이언트로 보낸다.

    -> 클라이언트는 /로 리디렉션 되고, 쿠키에 username이 설정된다.

     

     

    </ 엔트포인트>

    @app.route('/')
    def index():
        username = request.cookies.get('username', None)
        if username:
            return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not admin"}')
        return render_template('index.html')

    request.cookies.get('username', None)을 통해 클라이언트가 보낸 쿠키중 username 값을 가져온다.


    Approach

    login 페이지에서 guest-guest 값을 입력하고 버프 스윕트로 인터셉트한 값은 아래와 같다. username과 password에 내가 입력한 guest-guest 값이 매핑된다.

    POST /login HTTP/1.1
    Host: host1.dreamhack.games:10573
    Content-Length: 29
    Cache-Control: max-age=0
    Origin: http://host1.dreamhack.games:10573
    Content-Type: application/x-www-form-urlencoded
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
    Referer: http://host1.dreamhack.games:10573/login
    Accept-Encoding: gzip, deflate, br
    Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
    Cookie: username=guest
    Connection: keep-alive
    
    username=guest&password=guest

     

    내가 guest-guest로 로그인하면 cookie에는 아래와 같이 guest라고 뜰 것이다. 로그인 한 상태에서 username을 admin으로 바꾸면? 아래 코드를 살펴보면 username 즉 value 값만 검사하기 때문에 flag가 출력될 것이다.

    @app.route('/')
    def index():
        username = request.cookies.get('username', None)
        if username:
            return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not admin"}')
        return render_template('index.html')


    Solve

    guest-guest로 로그인한 뒤, 개발자 도구로 value를 admin으로 바꿨더니 flag가 출력되었다.

    Hello admin, flag is DH{7952074b69ee388ab45432737f9b0c56}

    Dreamhack: 취약점 분석

    username 변수가, 요청에 포함된 쿠키에 의해 결정되어 문제가 발생한다. 쿠키는 클라이언트의 요청에 포함되는 정보로, 이용자가 임의로 조작할 수 있다.

    @app.route('/') # / 페이지 라우팅 
    def index():
        username = request.cookies.get('username', None) # 이용자가 전송한 쿠키의 username 입력값을 가져옴
        if username: # username 입력값이 존재하는 경우
            return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not admin"}') # "admin"인 경우 FLAG 출력, 아닌 경우 "you are not admin" 출력
        return render_template('index.html')

     

    'Dreamhack > Web Hacking' 카테고리의 다른 글

    session-basic[web]  (0) 2024.12.28
    chocoshop [Web]  (0) 2024.11.28
    Tomcat Manager [web]  (1) 2024.11.28
    댓글