이번 문제를 풀 때 이전에 풀었던 session-basic 문제코드와 비교하며 풀었다. 그러므로 session-basic 풀이를 보고 오시는 걸 추천한다.
[문제]
[문제파일]
#!/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)
코드에서 얻을 수 있는 정보들
이전 session-basic 문제에서 /admin 페이지 부분이 빠진 코드였다. 하지만 이전 문제에서 admin페이지가 힌트였기 때문에 이 부분이 빠진 코드에서는 다른 힌트가 존재할 거라고 생각해 코드를 더 살펴보았다. 그 결과 session id 생성 코드 부분이 다른 걸 볼 수 있었다.
바뀐 코드 부분은 총 두 부분으로, 둘 다 세션 아이디 생성에 관한 코드였다.
1.
session_id = os.urandom(4).hex()
내가 로그인 할 때 세션값이 생성되는 원리 같다.
2.
session_storage[os.urandom(1).hex()] = 'admin'
마찬가지로 admin 계정의 세션값 생성 원리 같다고 추측했다.
이 부분을 활용하여 세션값 변조를 해야 될 것 같은데 이 부분이 어떻게 작용되나 잘 모르겠어서 문제 페이지에서 확인해보았다.
문제 페이지에서 로그인 시도를 먼저 해보도록 하겠다. 코드에 나온 guest 계정으로 로그인하였다.
로그인 결과, 세션 아이디가 session-basic문제와 다르게 확연히 짧아진 걸 보고 이 부분이 힌트인 걸 확신했다.
session_id = os.urandom(4).hex() < 이 코드대로 생성된 세션값이 d014a82a인 것을 확인했다. session-basic문제에서는 urandopn(32).hex()의 값이 64자리 16진수였다.
urandom(4).hex()의 결과로 8자리 16진수가 생성되는 걸 보아 urandopm(1).hex()의 결과는 2자리 16진수가 생성될 거라고 예측을 했고, 파이썬 코드로 실험해본 결과 두 자리 16진수가 세션값일 거라고 확신을 했다.
하지만 16*16=256개를 일일이 대입해보긴 힘들고,,,(사실 10개 정도 해보다가 오바라서 포기함. 운 좋으면 될 줄 알았죠^^) 검색 결과 버프스위트를 이용해 Brute-force를 할 수 있다고 해서 해보았다.
guest 계정으로 로그인한 메인페이지에서 proxy 탭에서 현재 sessionid 값을 선택해준 뒤 우클릭>send to intruder을 해준다.
(세션 아이디가 위와 다른 이유는 여러 번 풀어보면서 캡쳐 타이밍이 달랐기 때문...!)
그러며면 intruder 탭이 반짝거리는데 누르면 posotions탭에서 내가 방금 선택한 세션값 부분이 $$으로 선택되어 있다. 해당 값만 바꿔 공격해줄 것이니 범위가 잘 선택된 걸 볼 수 있다.
Payload 탭으로 넘어와 넣어줄 값을 설정해준다. payload type을 Brute forcer로 선택해준 뒤 character set에 16진수에 해당하는 1~f를 넣어주고 페이로드 길이를 2로 설정해준 뒤 우측 상단에 Start attack을 눌러주었다.
세션id 값이 내가 설정해준 범위대로 하나씩 잘 가고 있다가 length 길이가 다른 페이로드 하나를 발견하였다. 그때 세션아이디가 94였고 이게 admin의 세션id임을 예측하였다.
94를 세션값으로 넣어주자 flag가 뜨는 걸 볼 수 있었다. 이 값을 드림핵에 입력하자 정답처리가 되었다!
(개발자도구에서 세션값을 변경해줘도 되지만 버프스위트에서 넣어줘도 된다.)
[Dreamhack]CSRF-1 (0) | 2022.09.22 |
---|---|
[Dreamhack] xss-2 (0) | 2022.09.20 |
[Dreamhack] XSS-1 (0) | 2022.09.20 |
[Dreamhack] devtools-sources, web-misconf-1, Cookie (0) | 2022.09.19 |
[Dreamhack] session-basic (0) | 2022.07.26 |