DreamHack/WEB

session

G_OM 2024. 10. 8. 22:06

 

간단한 로그인이라 하지만 flag를 딴 사람은 2350명이다.

 

Cookie 문제는 10000명이 넘었는데

 

 

 

 

 

 

 

 

 

 

 

문제 화면이다.

 

admin으로 login 하는 거 같다.

 

코드를 한번 봐보자.

 

 

 

 

 

 

 

 

 

 

 

 

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

app = Flask(__name__)

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

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

session_storage = {
}

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

    return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not admin"}')

@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(4).hex()
            session_storage[session_id] = username
            resp.set_cookie('sessionid', session_id)
            return resp 
        return '<script>alert("wrong password");history.go(-1);</script>'

if __name__ == '__main__':
    import os
    session_storage[os.urandom(1).hex()] = 'admin'
    print(session_storage)
    app.run(host='0.0.0.0', port=8000)

 

 

사용자 정보를 저장하는 {users}를 보면 guest(ID) : guest(PW) , user : user1234 , admin : {FLAG}로 정의되어있는 걸 볼 수 있다.

 

이때 FLAG는 알 수 없으니 login 함수를 봐보자

 

계정명은 admin 확인되었으니 pw를 보면...

 

 

 

 

 

 

 

 

 

 

 

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(4).hex()
            session_storage[session_id] = username
            resp.set_cookie('sessionid', session_id)
            return resp 
        return '<script>alert("wrong password");history.go(-1);</script>'

 

 

로그인요청은 POST로 처리를 하고 username은 이미 admin으로 알고 있으니 try 은 넘어간다.

 

if pw == password: 를 보면 session_id에 대한 설정이 나온다.

 

'session_id = os.urandom(4). hex()'를 이용해서 랜덤 하게 세션 ID를 생성한다

random 4byte -> hex(16진수 변환)

이런 식으로 나오는 거 같다.

 

실험해 보자

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

예를 들어 os.urandom(1)로 생성된 바이트 데이터가 b'\xf0' 값이라면. hex()를 통해서 'f0'으로 변환된다는 것이다.

 

지금 보는 os.urandom(4)는 4byte -> 32bit -> hex() -> 8자리 문자열 

 

하지만 8자리를 처음부터 무작위대입공격을 하기에는 너무 시간 소모가 크다.

 

그래서 코드를 다시 읽어봤다.

 

 

 

 

 

 

 

 

 

 

 

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

 

 

다시 보니 session_storage 가 있었다.

 

쿠키와 다르게 세션 스토리지는 클라이언트 측이 아닌 서버 측에 저장되어 있다

 

즉 admin의 session_id 가 서버에 미리 저장되어 있다는 뜻이다.

 

그렇다면 1byte -> 8bit -> hex() -> 2자리 문자열

(8 / 4 = 2)

 

경우의 수가 많이 줄어들었으니 무작위대입 공격이 가능하다.

 

python을 이용해 나온 값을 session_id에 대입하도록 하자.

 

 

 

 

 

 

 

 

 

 

 

 

 

session ID 값은 71이 나왔다.