읽기 안내
동일 문제의 Session과 session-basic 기록을 한 페이지에 모았습니다. 두 원문의 코드와 서로 다른 실습 화면, 회고를 각각 보존했습니다.
원문 1 · Session
문제 목표 및 기능 요약
해당 문제의 목표는 관리자 권한을 획득해 FLAG를 획득하는 것이다.
| 페이지 | 설명 |
|---|---|
/ |
이용자의 username을 출력하고 관리자 계정인지 확인한다. |
admin |
관리자가 이용자의 세션 정보를 확인한다. |
웹 서비스 분석
엔드포인트: /
다음 코드는 인덱스 페이지를 구성하는 코드다. 해당 페이지에서는 세션을 통해 이용자를 식별한다. 먼저 쿠키의 sessionid의 값을 통해 session_storage에서 해당 Session ID의 username을 조회한다. 만약 username이 "admin"일 경우 FLAG를 출력한다.
index 페이지 코드
@app.route('/') # / 페이지 라우팅
def index():
session_id = request.cookies.get('sessionid', None) # 쿠키에서 sessionid 조회
try:
username = session_storage[session_id] # session_storage에서 해당 sessionid를 통해 username 조회
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"}')
엔드포인트: /admin
admin 페이지 코드는 관리자 페이지를 구성하는 코드다. developer's note 아래 주석처리된 소스코드는 인덱스 페이지와 비슷한 구조로 세션을 통해 현재 접속한 이용자가 admin인지 확인하려고 했음을 볼 수 있다.
admin 세션 생성은 서비스 실행 시 os.urandom(32).hex()를 통한 무작위 값 생성을 통해 username이 admin인 세션 정보를 session_storage에 생성한다. 해당 session_storage 정보를 조회할 수 있다면 무작위 값을 추론하지 않고도 곧바로 Sesssion ID를 획득할 수 있음을 알 수 있다.
admin 페이지 코드
@app.route('/admin')
def admin():
# developer's note: review below commented code and uncomment it (TODO)
#session_id = request.cookies.get('sessionid', None)
#username = session_storage[session_id] session_storage에 저장된 username을 불러옴
#if username != 'admin': # username이 admin인지 확인
# return render_template('index.html')
return session_storage
admin 세션 생성
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' # username이 admin인 Session ID를 무작위로 생성
print(session_storage)
app.run(host='0.0.0.0', port=8000)
취약점 분석
admin 페이지 코드를 다시 살펴보면 전체 세션 정보가 포함된 session_storage는 username이 admin인 관리자만 조회할 수 있도록 되어있다. 하지만 해당 부분은 개발자에 의해 주석처리 되었으므로 인증을 거치지 않고 session_storage를 조회할 수 있음을 알 수 있다.
@app.route('/admin')
def admin():
# developer's note: review below commented code and uncomment it (TODO)
#session_id = request.cookies.get('sessionid', None)
#username = session_storage[session_id]
#if username != 'admin':
# return render_template('index.html')
# 인증을 수행하는 위의 코드가 주석처리되어 인증을 하지 않-
return session_storage
익스플로잇
먼저 이용자 별 세션 정보를 조회한다. /admin 페이지에 접속하면 세션 정보 조회와 같이 현재 접속된 모든 이용자의 Session ID와 username을 조회할 수 있다.
세션 정보 조회

이후 쿠키의 sessionid의 값을 admin의 Session ID로 생성해야 한다. 웹 브라우저를 통해 쿠키 변조와 같이 웹 브라우저의 개발자 도구를 사용하면 쿠키의 정보를 수정할 수 있다.
admin의 Session ID가 적용된 상태에서 서버에 요청하면 FLAG 획득할 수 있다.
웹 브라우저를 통한 쿠키 변조

후기
이번 문제에서는 제거되지 않은 디버그 코드를 통한 세션 하이재킹으로 자신 이외의 이용자에 대한 Session ID를 알아낼 수 있었다. 실습에서는 해당 취약점들을 연계하여 다른 계정의 권한을 획득할 수 있었다.
기본적으로 배포 전 디버그 코드가 남아있는지 검사한다면 이번 실습에서 나온 공격을 방지할 수 있다.
세션 하이재킹 공격에 대해서는 세션 타임아웃을 적용해 해결할 수 있다. 일정 주기마다 Sesison ID를 재발급해 정상 로그인한 이용자는 장기간 세션을 유지할 수 있는 반면, 탈취한 Session ID로 접속한 이용자는 일정 시간 이후 더 이상 해당 인증이 유효하지 않게 되므로 안전한 서비스를 구현할 수 있다.
원문 2 · session-basic
웹 서비스 분석
엔드포인트 : /
index 페이지 코드
@app.route('/') # / 페이지 라우팅
def index():
session_id = request.cookies.get('sessionid', None) # 쿠키에서 sessionid 조회
try:
username = session_storage[session_id] # session_storage에서 해당 sessionid를 통해 username 조회
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"}')
엔드포인트 : \admin
admin 페이지 코드는 관리자 페이지를 구성한다.
admin 세션 생성은 서비스 실행 시 os.urandom(32).hex()를 통한 무작위 값 생성을 통해 username이 admin인 세션 정보를 session_storage에 생성한다. 해당 session_storage 정보를 조회할 수 있다면 무작위 값을 추론하지 않고도 곧바로 Session ID를 획득할 수 있다.
admin 페이지 코드
@app.route('/admin')
def admin():
# developer's note: review below commented code and uncomment it (TODO)
#session_id = request.cookies.get('sessionid', None)
#username = session_storage[session_id] session_storage에 저장된 username을 불러옴
#if username != 'admin': # username이 admin인지 확인
# return render_template('index.html')
return session_storage
admin 세션 생성
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' # username이 admin인 Session ID를 무작위로 생성
print(session_storage)
app.run(host='0.0.0.0', port=8000)
취약점 분석
admin 페이지 코드를 보면 전체 세션 정보를 담고있는 session_storage는 username이 admin인 관리자만 조회하도록 의도되어 있다.
그러나 해당 로직이 주석처리가 되어있으므로 인증을 거치지 않고 session_storage를 조회할 수 있다.
익스플로잇
URL에 /admin을 추가로 입력하여 admin 페이지로 접속한다. 위에서도 말햇다시피 인증하는 로직이 주석처리가 되어있어 바로 관리자 페이지로 들어갈 수 있게 된다.

관리자에 대한 Session ID 값이 나와있다. 알아낸 정보를 활용하기 위해 개발자 도구를 켜서 cookie 값을 변조하듯이 값을 넣고 새로고침을 하면 플래그가 뜬다.


후기
세션 하이재킹을 통해 자신 이외의 사용자에 대한 Session ID 값을 알아냈다.
이번 문제를 통해 느낀점은 디버깅을 위해 주석처리 해뒀던 코드가 있는지 배포 전에 다시 한번 더 확인하는 습관을 들여야겠다고 느꼈다.
작성 기록과 문제 출처
원문과 출처
풀이와 설명: MadEyE / 이선용의 개인 Notion 기록.
문제에서 제공한 코드·서비스 화면과 외부 참고자료의 권리는 해당 작성자와 플랫폼에 있습니다.
원문 본문·코드·실습 증적을 보존했으며, 원문에 포함된 외부 글은 참고 링크로 안내합니다.
이미지 원본 출처
다음 글