본문 바로가기
컴소니/보안

[웹 해킹] Dreamhack session-basic(Level 1)

by 금소니 2023. 7. 31.
반응형

#258

1. 개요

워게임 명 : session-basic

난이도 : Level 1

관련 개념 : Cookie, Session

문제 : 쿠키와 세션을 이용하여 admin 계정 권한 획득

화면이 조금 바꼈네요.

admin 계정의 세션 ID를 탈취하여 로그인하면 FLAG 값을 얻을 수 있을 것으로 보입니다.

 

마찬가지로 해킹 강의의 실습 문제입니다.

2. 소스 코드 확인

1) 초기 선언 부분

#!/usr/bin/python3
from flask import Flask, request, render_template, make_response, redirect, url_for

app = Flask(__name__)

#FLAG 값 호출
try:
    FLAG = open('./flag.txt', 'r').read()
except:
    FLAG = '[**FLAG**]'

#사용자 계정 정보
users = {
    'guest': 'guest',
    'user': 'user1234',
    'admin': FLAG
}

#세션 저장소
# this is our session storage
session_storage = {
}

2) app.route('/')

#루트 페이지(/) 함수
@app.route('/')
def index():
    session_id = request.cookies.get('sessionid', None)
    try:
        # get username from session_storage
        username = session_storage[session_id]
    except KeyError:
        return render_template('index.html')

    #admin일 경우 FLAG 값 반환 그렇지 않을 경우 "you are not admin" 반환
    return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not admin"}')

3) app.route('/login', methods=['GET', 'POST'])

#로그인 페이지(/login) 구현
#GET, POST 메소드 사용
@app.route('/login', methods=['GET', 'POST'])
def login():
    #GET일 경우
    if request.method == 'GET':
        return render_template('login.html')
    #POST일 경우(계정 입력)
    elif request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        try:
            # you cannot know admin's pw
            pw = users[username]
        except:
            return '<script>alert("not found user");history.go(-1);</script>'
        if pw == password:
            #패스워드가 일치할 경우 index 페이지로 이동
            resp = make_response(redirect(url_for('index')) )
            #세션 ID 생성
            session_id = os.urandom(32).hex()
            #세션 ID 저장
            session_storage[session_id] = username
            resp.set_cookie('sessionid', session_id)
            return resp
        return '<script>alert("wrong password");history.go(-1);</script>'

4) app.route('/admin')

#관리자 페이지(/admin) 함수
@app.route('/admin')
def admin():
    # developer's note: review below commented code and uncomment it (TODO)

    #session_id = request.cookies.get('sessionid', None)
    #username = session_storage[session_id]
    #if username != 'admin':
    #    return render_template('index.html')
    #세션 저장소 반환
    return session_storage

5) 메인

#main
if __name__ == '__main__':
    import os
    # create admin sessionid and save it to our storage
    # and also you cannot reveal admin's sesseionid by brute forcing!!! haha
    #메인에 admin에 해당되는 세션 ID 생성
    session_storage[os.urandom(32).hex()] = 'admin'
    print(session_storage)
    #웹 서비스 실행
    app.run(host='0.0.0.0', port=8000)

3. 웹 화면 확인

이번 문제에서는 웹 화면을 가상 서버를 생성하여 확인할 수 있습니다.

링크에 접속해 보니 웹 화면은 아래와 같습니다.

4. 문제 풀이

1) admin의 세션 ID 확인

문제의 목적은 admin의 세션 ID를 통해 로그인하여 FLAG값을 얻는 것입니다.

먼저 소스를 분석하였을 때 웹 서버가 실행되면서 admin의 세션 ID를 생성하는 것을 확인할 수 있었습니다.

session_storage[os.urandom(32).hex()] = 'admin'
print(session_storage)

session_storage의 경우 /admin 페이지에서 확인할 수 있었고 해당 페이지의 경우 별도의 권한없이 접속할 수 있었습니다.

그 결과 해당 페이지에 접근하였을 때 admin의 세션 ID를 확인할 수 있었습니다.

 

2) 타 계정의 세션 ID 확인

이제 admin을 로그인하기 위해서 타 계정의 경우 어떻게 로그인하고 어떤 세션 ID를 가지는지 확인해보도록 하겠습니다.

로그인할 수 있는 계정정보는 역시 소스 코드에서 확인할 수 있었습니다.

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

guest 계정과 user계정이 있는데 아무 계정이나 이용해보도록 하겠습니다.

아마 저 문구에 admin 계정으로 로그인할 경우 FLAG값이 있을 것으로 보입니다.

 

저는 guest 계정으로 로그인하였고 이 때 세션 ID는 개발자 도구를 이용하여 확인할 수 있습니다.

 

3) 세션 ID 바꿔주기

로그인하였을 때 세션이 어떻게 저장되는지를 확인할 수 있었습니다.

여기서 sessionid값을 아까 /admin 페이지에서 확인할 수 있었던 admin의 세션 ID로 바꿔준다면 admin 권한으로 로그인할 수 있습니다.

빨간 부분으로 표시된 부분을 admin의 세션 ID로 바꿔주고 새로고침한 결과...

FLAG 값을 확인할 수 있었습니다.

강의를 공부한 후 푸는 문제라 쉽게 푸실 수 있습니다.

반응형

댓글