쿠키와 세션을 학습한 이후 바로 문제가 주어진다. 우리는 세션 하이재킹을 이용할 것이라고 미리 짐작할 수 있다.
문제 분석
문제 설명에서는 admin 계정으로 로그인 시 플래그를 얻을 수 있다고 한다.
admin 계정에 로그인을 하기 위해서는 admin의 비밀번호를 알아내거나, admin의 쿠키 혹은 세션을 알아내야 할 것이다.
제공된 웹페이지를 열어보자.
간단한 홈페이지가 구성되어 있고 로그인 기능이 제공되나 우리는 알고 있는 정보가 아직은 없다.
제공된 문제 파일에는 app.py 파일 하나가 들어있다.
코드를 살펴보자.
from flask import Flask, request, render_template, make_response, redirect, url_for
app = Flask(__name__)
flask는 파이썬을 이용하여 웹서비스를 구현할 수 있는 모듈이다.
이 모듈을 사용하고 있는 것을 보아 아까 열어본 웹 페이지의 코드라는 것을 짐작해 볼 수 있다.
try:
FLAG = open('./flag.txt', 'r').read()
except:
FLAG = '[**FLAG**]'
users = {
'guest': 'guest',
'user': 'user1234',
'admin': FLAG
}
# this is our session storage
session_storage = {
}
users라는 딕셔너리가 눈에 띈다. 이름과 데이터 형태로 보아 ID/PW 쌍이라고 생각할 수 있을 것이다.
그러나 우리에게 필요한 admin의 값은 어떤 파일에서 읽어오기 때문에 알아낼 수가 없다.
@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')
return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not admin"}')
Flask를 이용해 본적은 없으나 @app.route('/')는 제공된 웹페이지의 '/', 즉 첫화면인 것으로 알아볼 수 있다.
코드의 내용을 살펴보면 쿠키에서 'sessionid'라는 키의 값을 가져오고 session_storage에서 세션 값을 찾아 username을 확인한다.
그리고 username == "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:
# you cannot know admin's pw
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(32).hex()
session_storage[session_id] = username
resp.set_cookie('sessionid', session_id)
return resp
return '<script>alert("wrong password");history.go(-1);</script>'
로그인 페이지에 대한 내용이다.
깊게 살펴보진 말고 위에 있던 users 에서 ID/PW를 확인하여 로그인에 성공 시 랜덤값의 세션을 session_storage에 저장한다고 한다.
이를 보아 로그인에 성공해야 세션값이 생성되는 것을 알 수 있다.
하지만 우리는 아직 admin의 비밀번호를 알지 못하며 세션도 얻을 수 없다.
조금 더 코드를 확인해 보자
@app.route('/admin')
def admin():
# what is it? Does this page tell you session?
# It is weird... TODO: the developer should add a routine for checking privilege
return session_storage
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
session_storage[os.urandom(32).hex()] = 'admin'
print(session_storage)
app.run(host='0.0.0.0', port=8000)
이용할 수 있는 취약점을 찾아냈다.
/admin 페이지를 이용했을 때 우리는 session_storage의 값을 확인할 수 있다.
또한 아래에서 이 파일이 실행될 때 admin의 세션값이 저장되는 코드가 있는 것을 확인하였다.
고로 서버가 처음 실행시 admin의 세션이 session_storage에 저장되고 이를 /admin에서 확인할 수 있다.
문제 해결
/admin 페이지 접속
'제공된 주소/admin'를 입력하여 접속해본다.
해당 코드를 복사하여 세션값을 변조하여야 한다.
관리자도구 > application 에서 쿠키를 찾아 sessionid 키를 추가하고 복사한 값을 입력할 것이다.
입력이 완료되었다면 홈페이지를 새로고침한다.
우리는 세션하이재킹을 이용하여 admin 계정에 접속하였으며 플래그를 얻었다.
'Wargame' 카테고리의 다른 글
[Dream Hack] xss-2 풀이 (0) | 2022.09.07 |
---|---|
[Dream Hack] xss-1 풀이 (0) | 2022.09.06 |
[Dream Hack] Cookie 풀이 (0) | 2022.09.01 |
[Dream Hack] devtools-sources 풀이 (0) | 2022.09.01 |