https://dreamhack.io/wargame/challenges/266

첫 화면은 이렇다.
login을 누르고 guest를 입력해보았다.
이렇게 뜬다. 전 문제인 cookie와 비슷한 형식이다.

역시 admin을 하면 알림창이 뜬다.

EditThisCookie를 열어서 확인해보면 sessionid 창이 있는 것을 알 수 있다.
F12를 눌러도 잘 모르겠어서 코드를 한번 확인해보겠다.
#!/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)
코드를 분석해보면
try:
FLAG = open('./flag.txt', 'r').read()
except:
FLAG = '[**FLAG**]'
users = {
'guest': 'guest',
'user': 'user1234',
'admin': FLAG
}
guest와 user의 비밀번호는 각각 guest, user1234 이다.
admin의 비밀번호는 FLAG 변수에 저장된 값이다.
@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"}')
세션 쿠키에서 session_id를 가져온다.
session_id에 맞는 접속자를 session_storage에서 찾아 화면에 표시한다. 만약 접속자가 admin이라면 FLAG와 함께 출력한다.
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)
session_id의 4바이트 무작위 문자열을 생성하고, 그것을 16진수로 바꿔 반환한다.
그래서 위 session id 사진을 보면 8자리 문자열이 생성된 것을 볼 수 있다.
랜덤한 session_id와 admin를 생성하여 session_storage에 추가한다.
중요한 점은 admin의 session id는 1바이트라 2자리의 문자열이다.
1바이트는 00부터 FF까지므로 256가지라 경우의 수를 전체 검색해보면 된다.
--> 256번 공격을 시도하여 가능한 모든 session_id를 찾으면 된다. 이렇게 찾은 session_id를 사용하면 관리자 계정으로 로그인할 수 있게 된다.
Burp Suite 프로그램을 다운받는다.
이 프로그램은 intruder 기능을 이용해 무작위 대입 공격을 시도할 수 있다.

guest 계정으로 로그인한 메인 페이지 창을 띄운다.
그 다음 Burp Suite 프로그램에서 proxy탭의 현재 session_id 값을 선택해주고, 우클릭 및 send to intruder을 한다.

intruder 탭을 누르면 선택한 세션 값이 으로 선택되어 있다. 해당 값만 바꿔서 공격할 것이니 범위가 잘 선택된 걸 볼 수 있다.

posirions 옆 payload로 넘어와 넣어줄 값을 설정해준다. payload type을 Brute forcer로 선택해준 뒤 character set에 16진수에 해당하는 1~f를 넣는다. 페이로드 길이를 2로 설정해준 뒤 우측 상단에 Start attack을 눌러준다.

대입 공격 중 length 길이가 다른 페이로드 하나를 발견하였다. 그때 session_id가 e7였고 이게 admin의 session_id라고 생각했다.
EditThisCookie를 열어서 sessionid 값을 e7로 바꾸어주고 새로고침을 눌렀다.
새로고침을 하면 위 사친처럼 FLAG가 뜨는 것을 확인 할 수 있다.