
Kit de herramientas componible de línea de comandos para el triaje de malware y el análisis de binarios: decodificar, descifrar, hacer carving y extraer indicadores de archivos maliciosos y shellcode.
__ __ High Octane Triage Analysis __
|| _||______ __ __________ _____ ||
|| \||___ \__| ____/ ______/___ / ____\ ||
==||=====|| | __/ |/ \ /==| / __ \ __\===]|
'======|| | \ | | \_ _| \ ___/| | ||
||____ /__|___|__/ / | \____]| | ||
=========''====\/=========/ /==|__|=====|__|======'
\ /
\/
Binary Refinery™ es una colección de scripts de Python que implementan transformaciones de datos binarios, como compresión y cifrado.
A menudo nos referiremos a él simplemente como refinery, que es también el nombre del paquete correspondiente.
Los scripts están diseñados para leer exclusivamente la entrada desde stdin y escribir la salida a stdout.
La filosofía principal es que cada script debe ser una unidad en el sentido de que hace un trabajo,
y las unidades individuales se pueden combinar en canalizaciones con el operador de tubería | en la línea de comandos para realizar tareas más complejas.
El enfoque principal del proyecto es el triaje de malware,
y es un intento de implementar algo como CyberChef en la línea de comandos.
Crea un entorno virtual de Python. Necesitas Python 3.10 o posterior. Instala refinery así:
python -m pip install -U pip
python -m pip install -U binary-refinery[extended]
Ejecuta las unidades con -h para aprender cómo funcionan, busca en los docs o usa el comando binref para encontrarlas. Mira un video reciente si quieres verlo en acción. Pero también, lee el resto de este readme.
No hay un calendario de lanzamientos, pero los lanzamientos ocurren con mucha frecuencia y se recomienda actualizar periódicamente. Las correcciones de errores no se documentan fuera de GIT, pero todos los demás cambios (es decir, nuevas características) se documentan en el changelog. Sígueme en Mastodon para recibir actualizaciones sobre lanzamientos especialmente impactantes.
El texto de ayuda que se muestra al ejecutar una unidad con la opción -h o --help es su documentación principal. La documentación generada automáticamente contiene una compilación de esa salida para cada unidad en el nivel superior, pero también contiene la especificación de los tres conceptos fundamentales del kit de herramientas: framing, argumentos multibin y variables meta. La búsqueda de texto completo de la descripción y el texto de ayuda para cada unidad también está disponible en la línea de comandos, mediante el comando binref proporcionado. Reconociendo que la documentación de referencia puede ser algo árida, hay un esfuerzo continuo para producir una serie de tutoriales; recomiendo mucho que los consultes. Además de eso, recopilo recursos adicionales (incluidos algunos producidos por terceros) a continuación.
[!NOTE]
Refinery todavía está en alpha y la interfaz puede cambiar a veces, es decir, las unidades y los parámetros pueden ser eliminados o renombrados. Por lo tanto, puede suceder que líneas de comandos específicas de videos y publicaciones de blog más antiguos ya no funcionen.
2021/08] OALabs fue tan amable de permitirme mostrar el kit de herramientas en un video destacado.
En el video, básicamente trabajo con el contenido de
el primer tutorial.2021/11] Johannes Bader escribió una increíble publicación de blog sobre el análisis de malspam con binary refinery.2024/03] Malware Analysis For Hedgehogs hizo un video sobre cómo desempaquetar una muestra de XWorm usando refinery.2024/11] the CyberYeti me invitó a su streaming presentando refinery.2025/06] Estuve de nuevo en streaming con the CyberYeti, este es un poco más crudo.
Todos los errores que puedes ver aquí fueron corregidos. 😉Las demostraciones incluyen nuevamente muestras de la sección de ejemplos a continuación y los tutoriales.
Binary Refinery es (c) 2019 Jesko Hüttenhain, y se publica bajo una Licencia BSD de 3 cláusulas. Este repositorio también contiene una copia del texto completo de la licencia. Si quieres hacer algo con él que no esté cubierto por esta licencia, no dudes en contactar al autor.
Refinery requiere al menos Python 3.10. Se recomienda instalarlo en su propio entorno virtual: el paquete puede traer muchas dependencias, e instalarlo en tu Python global es algo propenso a conflictos de versiones. Además, dado que el kit de herramientas introduce un gran número de comandos nuevos, hay una buena probabilidad de que algunos de estos entren en conflicto en ciertos sistemas, y mantenerlos en su propio entorno virtual separado es una forma de prevenirlo.
Si quieres tener todos los comandos de refinery disponibles en tu shell en todo momento (es decir, sin tener que cambiar a un entorno virtual personalizado), también tienes la opción de elegir un prefijo para la instalación, que se pondrá delante de cada shim de comando instalado. Por ejemplo, si eliges r. como prefijo, entonces la unidad emit se instalará como el comando r.emit. Un beneficio adicional es que puedes escribir r. y pulsar Tab dos veces para obtener una lista de todos los comandos de refinery disponibles. Ten en cuenta, sin embargo, que no se asume ningún prefijo en la documentación y que es un objetivo de desarrollo de refinery no entrar en conflicto en la mayoría de los sistemas. El autor no usa un prefijo y proporciona esta opción como una red de seguridad.
La forma más sencilla de instalar y actualizar refinery es mediante pip. Asegúrate de ejecutar primero la versión más reciente:
python -m pip install -U pip
Luego simplemente instala el paquete refinery:
pip install -U binary-refinery
Si quieres elegir un prefijo para todas las unidades, puedes especificarlo mediante la variable de entorno REFINERY_PREFIX. Por ejemplo, el siguiente comando instalará refinery en el entorno de Python actual con el prefijo r. en Linux:
REFINERY_PREFIX=r. pip install -U binary-refinery
En Windows, tendrías que ejecutar los siguientes comandos:
set REFINERY_PREFIX=r.
pip install -U binary-refinery
Especificar el prefijo especial ! tendrá el efecto de que no se creen comandos de shell en absoluto, y binary refinery se instalará solo como biblioteca. Si quieres instalar el HEAD actual de refinery, puedes repetir todos los pasos anteriores, especificando este repositorio en lugar del paquete pip. Por ejemplo, lo siguiente instalará el commit más reciente de refinery:
pip install -U git+git://github.com/binref/refinery.git
Finalmente, si estás usando REMnux, puedes usar su contenedor docker de refinery.
Si quieres enseñar a tu claude local de análisis de malware a usar binary refinery, consulta la Binary Refinery Skill.
Lo siguiente es un resumen de qué tan bien se admiten actualmente varios entornos de shell:
Si estás usando un shell diferente y tienes comentarios para compartir, por favor házmelo saber!
Hay algunas unidades muy situacionales con dependencias externas (a veces grandes). Por ejemplo, stego es una unidad que requiere la biblioteca de análisis de imágenes Pillow. Algunas bibliotecas no se instalan por defecto para mantener el tiempo de instalación de refinery en un nivel razonable para los usuarios primerizos. Las unidades correspondientes te dirán qué hacer cuando falte su dependencia:
$ emit config.png | stego RG
(13:37:00) failure in stego: dependency Pillow is missing; run pip install Pillow
Luego puedes instalar estas dependencias faltantes manualmente. Si no quieres que te molesten las dependencias faltantes y no te importa una instalación larga de refinery, puedes instalar el paquete de la siguiente manera:
pip install -U binary-refinery[all]
lo que instalará todas las dependencias además de las requeridas. Más precisamente, están disponibles las siguientes categorías adicionales:
| Nombre | Dependencias Incluidas |
|---|---|
default | selección recomendada de dependencias razonables, elección del autor |
extended | una selección extendida, excluyendo solo las más oscuras |
all | todas las dependencias para todas las unidades de refinery |
Estas se enumeran aquí en orden ascendente, es decir, extended instalará todo lo que default instalaría.
Alternativamente, puedes clonar este repositorio y usar los scripts update.sh (en Linux) o update.ps1 (en Windows) para instalar el paquete refinery en un entorno virtual local. El proceso de instalación y actualización para este método consiste simplemente en ejecutar el script:
binary-refinery,binary-refinery[all].También puedes generar toda la documentación localmente. Para hacerlo, ejecuta el script run-pdoc3.py. Esto fallará a menos que lo ejecutes desde un entorno donde binary refinery haya sido instalado como paquete de Python. Para ejecutarlo, tienes que especificar la ruta de un entorno virtual como primer argumento de línea de comandos para run-pdoc3.py, lo que hará que el script se ejecute nuevamente usando el intérprete de ese entorno. Si estás seguro de que quieres ejecutar run-pdoc3.py, hay una opción de línea de comandos para forzar que el script se ejecute con el intérprete de Python predeterminado actual. El script instala el paquete pdoc3 y lo usa para generar una documentación HTML para el paquete refinery. La documentación se puede encontrar en el subdirectorio html directamente junto a este archivo readme.
Los tutoriales son cuadernos de Jupyter que puedes simplemente ejecutar si tu entorno virtual tiene Jupyter instalado. Vale la pena señalar que Visual Studio Code tiene un soporte muy cómodo para Jupyter.
Las unidades emit y dump juegan un papel especial: la primera sirve para emitir datos, mientras que la segunda sirve para volcar datos al portapapeles o al disco. Como ejemplo, considera la siguiente canalización:
emit M7EwMzVzBkI3IwNTczM3cyMg2wQA | b64 | zl | hex
Aquí, emitimos la cadena M7EwMzVzBkI3IwNTczM3cyMg2wQA, la decodificamos en base64 usando b64, descomprimimos el resultado con zlib usando zl, y finalmente decodificamos los datos descomprimidos con hex. Cada unidad realiza la operación "decodificación" de una determinada transformación por defecto, pero algunas también implementan la operación inversa. Si lo hacen, esto se logra siempre proporcionando la opción de línea de comandos -R, o --reverse. Puedes producir la cadena base64 anterior con el siguiente comando porque hex, zl y b64 todos proporcionan la operación inversa:
emit "Hello World" | hex -R | zl -R | b64 -R
Dado un archivo packed.bin que contiene un búfer de carga útil codificado en base64, la siguiente canalización extrae dicha carga útil a payload.bin:
emit packed.bin | carve -l -t1 b64 | b64 | dump payload.bin
La unidad carve se puede usar para extraer bloques de datos del búfer de entrada; en este caso, busca datos codificados en base64, los ordena por longitud (-l) y devuelve el primero de ellos (-t1), lo que extrae el fragmento más grande con apariencia base64 de packed.bin. Luego, los datos se decodifican en base64 y se vuelcan al archivo payload.bin.
La unidad pack tomará todas las expresiones numéricas de un búfer de texto y las convertirá en su representación binaria. Un ejemplo simple es la canalización
emit "0xBA 0xAD 0xC0 0xFF 0xEE" | pack | hex -R
que producirá la cadena BAADC0FFEE.
Extrae el fragmento más grande de datos codificados en base64 de un BLOB y decodifícalo:
emit file.exe | carve -ds b64
Extrae un archivo ZIP de un búfer, elige un DLL de él y muestra información sobre él:
emit file.bin | carve-zip | xtzip file.dll | pemeta
Lista las secciones de un archivo PE con su hash SHA-256 correspondiente:
emit file.exe | vsect [| sha256 -t | pf {} {path} ]]
Lista recursivamente todos los archivos en el directorio actual con su respectivo hash SHA-256:
ef "**" [| sha256 -t | pf {} {path} ]]
Extrae indicadores de todos los archivos enumerados recursivamente dentro del directorio actual:
ef "**" [| xtp -n6 ipv4 socket url email | dedup ]]
Convierte la dirección IP codificada 0xC0A80C2A en orden de bytes de red a un formato legible:
emit 0xC0A80C2A | pack -EB4 | pack -R [| sep . ]
Realiza una fuerza bruta XOR de un solo byte e intenta extraer una carga útil de archivo PE en cada iteración:
emit file.bin | rep 0x100 [| xor v:index | carve-pe -R | peek | dump {name} ]
Extrae un servidor C2 de RemCos:
emit c0019718c4d4538452affb97c70d16b7af3e4816d059010c277c4e579075c944 \
| perc SETTINGS [| put keylen cut::1 | rc4 cut::keylen | xtp socket ]
Extrae una configuración de AgentTesla:
emit fb47a566911905d37bdb464a08ca66b9078f18f10411ce019e9d5ab747571b40 \
| dnfields [| aes x::32 --iv x::16 -T ]] \
| rex -M "((??email))\n(.*)\n(.*)\n:Zone" addr={1} pass={2} host={3}
Extrae la carga útil de PowerShell de un dropper malicioso de macros XLS:
emit 81a1fca7a1fb97fe021a1f2cf0bf9011dd2e72a5864aad674f8fea4ef009417b [ \
| xlxtr 9.5:11.5 15.15 12.5:14.5 [ \
| scope -n 3 | chop -t 5 [| sorted -a | snip 2: | sep ] \
| pack 10 | alu --dec -sN B-S ]] \
| dump payload.cmd
Y obtén los dominios para la siguiente etapa:
emit payload.cmd | cmdarg | ps1 | xtp -f domain
Extrae la configuración de muestras de HawkEye desempaquetadas:
emit ee790d6f09c2292d457cbe92729937e06b3e21eb6b212bf2e32386ba7c2ff22c \
| put cfg perc[RCDATA]:c:: [\
| xtp guid | pbkdf2 48 rep[8]:h:00 | cca eat:cfg | aes -Q x::32 --iv x::16 ] \
| dnds
Warzone RAT:
emit 4537fab9de768a668ab4e72ae2cce3169b7af2dd36a1723ddab09c04d31d61a5 \
| vsect .bss | struct I{key:{}}{} [\
| rc4 eat:key | struct I{host:{}}{port:H} {host:u16}:{port} ]
Extrae la carga útil de un cargador de shellcode y extrae su c2:
emit 58ba30052d249805caae0107a0e2a5a3cb85f3000ba5479fafb7767e2a5a78f3 \
| rex yara:50607080.* [| struct LL{s:L}{} | xor -B2 rand[s]:msvc | xtp url ]
Obtén las macros maliciosas de VBA de un tiempo olvidado en que así era como se hacía:
emit ee103f8d64cd8fa884ff6a041db2f7aa403c502f54e26337c606044c2f205394 \
| vbamc
Y luego extrae la carga útil del descargador malicioso:
emit ee103f8d64cd8fa884ff6a041db2f7aa403c502f54e26337c606044c2f205394 \
| doctxt | repl drp:c: | carve -s b64 | rev | b64 | rev | ppjscript
Extrae URL de carga útil de un documento PDF malicioso:
emit 066aec7b106f669e587b10b3e3c6745f11f1c116f7728002f30c072bd42d6253 \
| xt JS | csd string | csd string | url | xtp url [| urlfix ]]
Extrae la URL de carga útil de un documento de exploit del editor de ecuaciones:
emit e850f3849ea82980cf23844ad3caadf73856b2d5b0c4179847d82ce4016e80ee \
| officecrypt | xt oleObject | xt native | rex Y:E9[] | vstack -a=x32 -w=200 | xtp
Supongamos que data es un archivo que fue cifrado con AES de 256 bits en modo CBC. La clave se derivó de la frase de contraseña secreta swordfish usando la rutina de derivación de clave PBKDF2 con el salt s4lty. El IV se antepone al búfer como los primeros 16 bytes. Se puede descifrar con la siguiente canalización:
emit data | aes --mode cbc --iv cut::16 pbkdf2[32,s4lty]:swordfish
Aquí, tanto cut:0:16 como pbkdf2[32,s4lty]:swordfish son argumentos multibin que utilizan un manejador especial. En este caso, cut:0:16 extrae el segmento 0:16 (es decir, los primeros 16 bytes) de los datos de entrada; después de aplicar este manejador multibin, los datos de entrada pierden los primeros 16 bytes y el argumento iv se establece en estos 16 bytes exactos. El argumento final especifica la clave de cifrado de 32 bytes: el manejador pbkdf2[32,s4lty], por otro lado, instruye a refinery para crear una instancia de la unidad pbkdf2 como si se le hubieran dado los parámetros de línea de comandos 32 y s4lty en este orden y procesar la cadena de bytes swordfish con esta unidad. Como prueba simple, la siguiente canalización cifrará y descifrará un fragmento de texto de muestra:
emit "Once upon a time, at the foot of a great mountain ..." ^
| aes pbkdf2[32,s4lty]:swordfish --iv md5:X -R | ccp md5:X ^
| aes pbkdf2[32,s4lty]:swordfish --iv cut:0:16
| Shell | Plataforma | Estado | Comentario |
|---|
| Bash | Posix | 🔵 Bueno | Usado ocasionalmente por el autor. |
| CMD | Windows | 🔵 Bueno | Usado extensamente por el autor. |
| PowerShell | Windows | 🟡 Razonable | Simplemente funciona si la versión de PowerShell es al menos 7.4. |
| Zsh | Posix | 🟠 Problemas Menores | Después de una discusión, hay una solución. |
| Fish | Posix | 🟠 Problemas Menores | Ver el problema #55 y la discusión #22. |