2026-03-30

Encuentras un repositorio en GitHub que promete ser un exploit PoC, una herramienta útil o una lib que resuelve exactamente tu problema. Lo clonas, ejecutas npm install y… felicidades, acabas de instalar un stealer que está exfiltrando tus credenciales hacia un webhook de Discord.
Este escenario no es ficción. Repositorios maliciosos se publican a diario disfrazados de herramientas legítimas, exploits de seguridad y utilidades open source. El problema es que, la mayoría de las veces, el código malicioso está escondido detrás de ofuscación, hooks de instalación y payloads codificados en base64.
Para resolver esto, creé Shady Project Scanner: una suite de scanners basados en patrones que audita repositorios completos en busca de malware, backdoors y comportamientos sospechosos. Sin dependencias externas, hecho 100% en bash.
Es un conjunto de 6 scripts de detección que escanean repositorios buscando patrones maliciosos conocidos. Cada scanner se especializa en un ecosistema:
| Scanner | Objetivo |
|---|---|
scan-repo.sh | Verificaciones generales (cross-language) |
scan-node.sh | Node.js / npm |
scan-php.sh | PHP (webshells, backdoors) |
scan-python.sh | Python / PyPI |
scan-go.sh | Go modules |
scan-polinrider.sh | Malware PolinRider (firma específica) |
Características:
[!] rojo (alto riesgo), [~] amarillo (sospechoso), [i] cian (informativo)0 = limpio, 1 = hallazgos, 2 = errorgit clone https://github.com/lauralesteves/shady-project-scanner.git
cd shady-project-scanner
Listo. No necesitas instalar nada más.
La forma más simple es vía Makefile. Para ejecutar los 6 scanners de una vez:
make scan TARGET=/ruta/al/repositorio/sospechoso
Para ejecutar un scanner específico:
make scan-node TARGET=/ruta/al/repositorio
make scan-python TARGET=/ruta/al/repositorio
make scan-repo TARGET=/ruta/al/repositorio
O directamente:
./scanners/scan-repo.sh /ruta/al/repositorio
./scanners/scan-node.sh /ruta/al/repositorio
Vamos a usar como objetivo el repositorio 0xgrama/StockX_PoC_1.07, que se presenta como un exploit PoC para StockX. Repositorios como este son el escenario clásico: prometen una herramienta ofensiva y el verdadero objetivo es quien lo descarga.
Aviso: No clones este repositorio en tu máquina personal. Si quieres probarlo, usa un ambiente aislado como una VM o una instancia EC2 desechable.
Después de clonar el repositorio sospechoso en un ambiente seguro, solo apunta el scanner:
make scan TARGET=/ruta/a/StockX_PoC_1.07
Shady Project Scanner ejecutará, en secuencia, los 6 scripts de detección contra el repositorio. Veamos qué hace cada uno.
Este es el scanner más completo. Ejecuta 14 verificaciones aplicables a cualquier lenguaje:
Git Hooks maliciosos – Verifica si los hooks en .git/hooks/ contienen comandos como curl, wget, bash, eval o URLs de exfiltración (Discord webhooks, Slack, ngrok). Un hook post-checkout que descarga y ejecuta un script remoto es uno de los vectores de ataque más comunes.
Crypto miners – Busca referencias a xmrig, coinhive, pools de minería (supportxmr, nanopool, f2pool) y direcciones de billeteras Monero/Bitcoin.
Secretos y credenciales – Detecta claves AWS (prefijo AKIA/ABIA/ACCA), claves privadas, tokens de GitHub/Slack/JWT, strings de conexión a base de datos con contraseñas, y archivos sensibles como .env, .npmrc, .pypirc, .pem, id_rsa.
Manipulación de CI/CD – Verifica GitHub Actions fijadas a branches en vez de SHA, pull_request_target con acceso a secrets, curl | bash en workflows y permisos de escritura.
Abuso de Docker – Detecta containers privilegiados, montaje de rutas sensibles (/etc/shadow, ~/.ssh, ~/.aws, /var/run/docker.sock) y descargas de scripts remotos en Dockerfiles.
Ataques Unicode/Homoglyph – Busca caracteres de Trojan Source (CVE-2021-42574), como overrides bidireccionales (U+202A-E) y zero-width chars (U+200B-D), que pueden ocultar código malicioso visualmente.
Binarios sospechosos – Señala .exe, .dll, .so, .dylib, .bat, .ps1 y otros ejecutables. Scripts PowerShell y batch con patrones peligrosos reciben atención especial.
Build scripts – Analiza Makefiles y shell scripts en busca de curl | bash, base64 --decode | exec, reverse shells (/dev/tcp, mkfifo, nc) y modificaciones a archivos del sistema.
Blobs codificados grandes – Detecta líneas con más de 2000 caracteres en archivos fuente, indicando código minificado u ofuscado embebido (excluye *.min.js y bundles legítimos).
Cron/Tareas programadas – Verifica archivos cron con comandos de red o script (curl, wget, python, nc).
Configuración de IDE – Detecta tareas de VS Code con ejecución de shell y recomendaciones de extensiones que pueden ser maliciosas.
Abuso de Git config – Busca filter drivers personalizados en .gitattributes (pueden ejecutar código silenciosamente), overrides de .gitconfig local y FUNDING.yml con billeteras sospechosas.
Reverse shells – Detecta patrones de reverse shell en bash (/dev/tcp), Python (socket), PHP (fsockopen) y Perl (IO::Socket).
Endpoints hardcoded – Encuentra IPs no privadas con puerto en scripts de build y config, excluyendo rangos privados (127.0.0.1, 192.168.x.x, 10.x.x.x).
Enfocado en amenazas específicas del ecosistema JavaScript. 8 verificaciones:
Install hooks en package.json – Verifica si preinstall, postinstall o preuninstall contienen curl, wget, eval, base64 o node -e. También detecta dependencias con nombres de typosquatting conocidos (lodash vs 1odash, event-stream, flatmap-stream, ua-parser-js) y bundledDependencies sospechosas.
Abuso de eval() / Function() – Detecta eval() con argumentos dinámicos, new Function(), eval(atob(...)), eval(Buffer.from(...)) y el patrón más peligroso: eval(response.data) o eval(res.body), que es fetch-then-eval (ejecución remota de código).
child_process / ejecución de shell – Encuentra execSync, exec, spawnSync con comandos sospechosos, require('child_process') ofuscado y require dinámico con concatenación de strings.
Exfiltración de datos – Detecta lectura de process.env + solicitudes HTTP, acceso a archivos sensibles (.ssh, .aws, .npmrc), URLs de exfiltración (Discord, Slack, ngrok, webhook.site, pipedream, requestbin) y robo de tokens de CI/CD (GITHUB_TOKEN, NPM_TOKEN, AWS_SECRET_ACCESS_KEY).
Payloads ofuscados – Strings Base64 largos (>100 chars), patrones hex-encoded (\x en masa), Unicode escapes, Buffer.from + base64 + eval/exec, patrones de javascript-obfuscator (variables _0x) y ofuscación estilo JSFuck.
Config npm/yarn – Registries personalizados apuntando fuera del npm oficial y tokens de autenticación en .npmrc/.yarnrc.
Integridad del lockfile – Verifica si las URLs en package-lock.json apuntan fuera de los registries oficiales (npmjs.org, yarnpkg.com) o si los tarballs provienen de ubicaciones no estándar.
Native addons – Detecta archivos binding.gyp y binarios .node fuera de node_modules.
Scanner especializado en webshells, backdoors y código ofuscado en PHP. 9 verificaciones:
Firmas de webshell – Detecta shells conocidos (c99shell, r57shell, b374k, WSO, FilesMan, Ani-Shell, ALFA Shell, Weevely, p0wny, phpspy). También detecta el patrón más común de webshell: $_GET/$_POST/$_REQUEST/$_COOKIE pasados directamente a funciones peligrosas (eval, system, exec, passthru, shell_exec, popen, proc_open). Identifica file_get_contents + eval (fetch-then-eval), php://input + ejecución de código y hashes MD5 hardcoded (contraseñas de backdoor).
Cadenas de ofuscación – eval(base64_decode(...)), eval(gzinflate(...)), eval(str_rot13(...)), cadenas anidadas de decode, assert() con input codificado, preg_replace con modificador /e y create_function().
Funciones peligrosas – system/passthru/shell_exec con variables, operador backtick con interpolación, proc_open() y dl() (carga dinámica de extensión).
Abuso de escritura de archivos – file_put_contents con ruta controlada por el usuario, fwrite con contenido decodificado y move_uploaded_file sin validación de MIME.
PHP escondido en archivos no-PHP – Detecta código <?php dentro de archivos .jpg, .png, .gif, .ico, .css, .txt, .html. También señala extensiones dobles (.php.jpg) y extensiones sospechosas (.phtml, .php5, .phar).
Payloads codificados – Strings Base64 muy largos (>200 chars), secuencias hex largas (\x en masa), ofuscación con chr() (10+ caracteres encadenados), variables variables y concatenación de strings construyendo nombres de funciones.
Abuso de .htaccess – Inyección vía auto_prepend_file/auto_append_file, AddHandler/AddType convirtiendo imágenes en ejecutables PHP y directivas SetHandler.
Config PHP – php.ini/.user.ini con auto_prepend_file y directivas disable_functions.
Composer – Scripts sospechosos en hooks de instalación (post-install-cmd, post-update-cmd) que contienen curl, wget, bash, eval o base64.
Enfocado en amenazas del ecosistema Python. 8 verificaciones:
setup.py malicioso – Detecta imports de módulos sospechosos durante setup (subprocess, os.system, socket, urllib, requests), llamadas a exec/eval/compile, decodificación base64, clases de instalación personalizadas con ejecución de código y fetch de URLs durante pip install.
Abuso de exec() / eval() – exec/eval con payloads codificados (base64, codecs, zlib, marshal, bytes.fromhex), exec(compile(...)) y el patrón más crítico: requests.get + exec o urllib response + eval (fetch-then-exec). También detecta cadenas multi-layer: base64 -> zlib -> marshal -> exec.
Payloads ofuscados – Strings Base64 largos (>200 chars), marshal.loads() (deserialización de bytecode), __import__ dinámico, importlib.import_module con strings dinámicos, bytes.fromhex + exec, chr() en masa, lambda envolviendo exec(), getattr(__builtins__) y patrones de robo de credenciales de navegador (Chrome, Firefox + sqlite3).
Exfiltración de datos – Lectura de archivos sensibles (.ssh, .aws, .env, /etc/passwd, /etc/shadow) + llamadas de red, webhooks de exfiltración, recolección de os.environ + HTTP POST, resolución DNS + recolección de info del sistema y robo de tokens.
subprocess / ejecución de comandos OS – subprocess con shell=True, os.system() con argumento variable, os.popen() y patrones de reverse shell (socket.connect + exec, pty.spawn).
Riesgos de deserialización – pickle.load(s) con datos no confiables (HTTP, file open, stdin), yaml.load() sin SafeLoader y __reduce__ personalizado con ejecución de comandos.
Archivos de requirements – Dependencias de URLs git (git+https://), URLs no-PyPI e indexes personalizados (--index-url, --extra-index-url) apuntando fuera de registries conocidos.
Archivos .pth sospechosos – Archivos .pth con sentencias import (se ejecutan automáticamente al iniciar Python) y .egg-info con entry_points.
Scanner para ataques de supply chain en proyectos Go. 7 verificaciones:
Directivas replace en go.mod – Detecta replace apuntando a rutas locales (../), repositorios no estándar (fuera de github.com, golang.org, google, gopkg.in), directivas retract y dependencias de dominios inusuales.
Funciones init() sospechosas – Funciones init() en archivos que también importan net/http, net.Dial, os/exec, acceden a variables de entorno + hacen llamadas de red, o acceden a rutas sensibles (.ssh, .aws, /etc/passwd).
Abuso de os/exec – exec.Command con intérpretes shell (bash, sh, powershell) + comandos sospechosos (curl, wget, nc, base64, whoami), fmt.Sprintf como argumento de exec (ofuscación) y exec.Command con os.Getenv (variable de entorno como comando).
Exfiltración de datos – URLs de webhook/exfiltración, recolección de info del sistema (os.Hostname, runtime.GOOS) + HTTP POST, lectura de archivos sensibles, conexiones TCP/UDP raw + exec (posible C2) e IPs hardcoded.
Abuso de CGo – import "C" con funciones C peligrosas (system(), popen(), execl/execv/execvp(), fork(), dlopen()).
Directivas go:generate – Comandos generate sospechosos (curl, wget, bash, powershell, rm, nc, python) y fetch de URLs remotas.
Build constraints y embed tricks – go:embed con archivos ejecutables/ocultos (.sh, .bat, .exe, .dll, .so), //go:build ignore con código de exec/red, go:linkname y llamadas a syscall.Exec/ForkExec/StartProcess.
Scanner con firma específica para el malware PolinRider, que inyecta payloads JS ofuscados en archivos de configuración de proyectos y hace force-push vía batch scripts. 4 verificaciones:
Firma primaria – Busca el payload ofuscado ("rmcej%otb%",2857687) en archivos como postcss.config.mjs, tailwind.config.js, eslint.config.mjs, next.config.mjs y babel.config.js.
Firma secundaria – Detecta el patrón global['!']='8-270-2';var _$_1e42=. Con la flag --js-all, escanea todos los archivos .js además de los configs conocidos.
Scripts de propagación – Busca temp_auto_push.bat (script de force-push) y config.bat (orquestador).
Artefactos Git – Detecta entradas de config.bat en .gitignore y commits enmendados en git reflog, comportamiento consistente con la propagación de PolinRider.
Acepta flags extras: --verbose para output detallado y --js-all para escanear todos los .js.
Nunca clones directo en tu máquina. Usa un ambiente aislado: VM, container o instancia EC2 desechable.
Nunca ejecutes npm install, pip install o go build antes de escanear. Los hooks de instalación son el vector de ataque #1. Clona y escanea antes de cualquier cosa.
Combina herramientas. Shady Project Scanner está basado en patrones y complementa (no reemplaza) herramientas como npm audit, pip-audit, Snyk o Semgrep.
Desconfía de repos que piden deshabilitar seguridad. “Deshabilita tu antivirus antes de ejecutar” es la red flag más antigua que existe.
Verifica la cuenta del autor. Cuenta nueva, sin historial, sin contribuciones a otros proyectos? El repo probablemente no es lo que dice ser.
Shady Project Scanner es una herramienta liviana y sin dependencias que ejecuta más de 50 verificaciones en 6 ecosistemas diferentes, cubriendo desde webshells PHP hasta ataques de supply chain en Go modules. No es bala de plata, pero es una primera línea de defensa rápida y eficiente antes de ejecutar cualquier código de terceros.
Si trabajas en seguridad, haces CTF o simplemente quieres dejar de confiar ciegamente en npm install, dale un vistazo al proyecto y contribuye.
git clone https://github.com/lauralesteves/shady-project-scanner.git
cd shady-project-scanner
make scan TARGET=/ruta/al/repo/sospechoso