Wazuh – SSH brute-force attack
Vediamo come scovare tramite Wazuh un attacco SSH di tipo brute-force.
Un attacco brute-force si ha quando da un determinato IP (o da più IP se l’attacco è distribuito) viene tentato l’accesso al servizio (SSH, RDP, ….) tramite credenziali username/password, cercando di indovinare l’accoppiata che garantisca l’accesso.
Solitamente, per attacchi di questo tipo, vengono utilizzati dizionari che contengono milioni di combinazioni username/password o le combinazioni vengono generate in maniera random.
Un tentativo di tipo brute-force può:
- avere successo, e quindi garantire l’accesso al nostro server/servizio; successivamente verranno messe in atto una serie di tecniche per nascondere l’avvenuto accesso (cancellazione dei file di log, installazioni di trojan, utilizzo del server quale “cavallo di Troia” per il nostro network, utilizzo del server per effettuare attacchi su altri reti, ….)
- portare a un DoS per le troppe richieste ricevute (vengono esaurite le risorse disponibili); questo porta al collasso del server/servizio, evento spiacevole se sul server coesistono diversi servizi;
- portare al crash del servizio per esaurimento delle risorse.
Wazuh analizza e genera un alert per ogni tentativo di accesso riuscito e/o fallito; vedremo come viene innalzata il livello di gravità degli alert nel momento in cui viene rilevato un attacco (in questo caso, accessi non autorizzati provenienti dallo stesso IP address).
Proviamo a simulare un attacco di tipo SSH brute-force contro una macchina linux; nella macchina target, l’SSH è configurato per:
- Accettare connessioni solo da certi utenti
- AllowUsers user1 user2 user3 ….
- Non è permesso il Root login:
- PermitRootLogin no
- E’ disabilitata la modalità di autenticazione tramite password in chiaro
- PasswordAuthentication no
- E’ abilitata la modalità di autenticazione tramite chiavi
- PubkeyAuthentication yes
Nei file di log del sistema sottoposto ad attacco (nel caso di una RHEL/CentOS il file è /var/log/secure), verranno evidenziate righe come le seguenti:
... Jun 1 19:38:14 <server> sshd[9929]: Invalid user admin from 192.168.xxx.xxx port 43733 Jun 1 19:38:14 <server> sshd[9929]: Received disconnect from 192.168.xxx.xxx port 43733:11: Bye Bye [preauth] Jun 1 19:38:14 <server> sshd[9929]: Disconnected from invalid user admin 192.168.xxx.xxx port 43733 [preauth] Jun 1 19:38:15 <server> sshd[9933]: User root from 192.168.xxx.xxx not allowed because not listed in AllowUsers Jun 1 19:38:15 <server> sshd[9933]: Received disconnect from 192.168.xxx.xxx port 58241:11: Bye Bye [preauth] Jun 1 19:38:15 <server> sshd[9933]: Disconnected from invalid user root 192.168.xxx.xxx port 58241 [preauth] Jun 1 19:38:15 <server> sshd[9939]: Invalid user oracle from 192.168.xxx.xxx port 59815 Jun 1 19:38:15 <server> sshd[9939]: Received disconnect from 192.168.xxx.xxx port 59815:11: Bye Bye [preauth] Jun 1 19:38:15 <server> sshd[9939]: Disconnected from invalid user oracle 192.168.xxx.xxx port 59815 [preauth] Jun 1 19:38:15 <server> sshd[9931]: Invalid user cisco from 192.168.xxx.xxx port 53923 Jun 1 19:38:15 <server> sshd[9931]: Received disconnect from 192.168.xxx.xxx port 53923:11: Bye Bye [preauth] Jun 1 19:38:15 <server> sshd[9931]: Disconnected from invalid user cisco 192.168.xxx.xxx port 53923 [preauth] Jun 1 19:38:17 <server> sshd[9971]: User root from 192.168.xxx.xxx not allowed because not listed in AllowUsers ...
Chiaramente, se la scansione è mirata e la lista degli utenti utilizzati è molto lunga (magari presa da dizionari), la scansione può essere molto “intensa” e i file di log generati possono essere parecchio “pesanti”.
Il file di log suindicato, viene inviato da wazuh-agent al server su cui è installato il wazuh-manager; su tale server l’evento viene “catturato” e viene generato un alert.
Al wazuh-manager arrivano le righe del file di log provenienti dalla macchina target; simuliamo l’arrivo di tali righe tramite il comando ossec-logtest
Vediamo cosa accade quando diamo come input al comando la prima riga trovata nel file di log della macchina target:
# /var/ossec/bin/ossec-logtest
2020/06/01 20:38:44 ossec-testrule: INFO: Started (pid: 19780).
ossec-testrule: Type one log per line.
Jun 1 19:38:14 <server> sshd[9929]: Invalid user admin from 192.168.xxx.xxx port 43733 <== input che passo al programma
**Phase 1: Completed pre-decoding.
full event: 'Jun 1 19:38:14 <server> sshd[9929]: Invalid user admin from 192.168.xxx.xxx port 43733'
timestamp: 'Jun 1 19:38:14'
hostname: '<server>'
program_name: 'sshd'
log: 'Invalid user admin from 192.168.xxx.xxx port 43733'
**Phase 2: Completed decoding.
decoder: 'sshd'
srcuser: 'admin'
srcip: '192.168.xxx.xxx'
srcport: '43733'
**Phase 3: Completed filtering (rules).
Rule id: '5710'
Level: '5'
Description: 'sshd: Attempt to login using a non-existent user'
**Alert to be generated.
Nella fase 1 (pre-decoding) viene analizzata la stringa di log alla ricerca di parole chiave; nella fase 2 (decoding) viene indicato che verrà utilizzato il decoder SSH per l’analisi della sequenza, che l’utente che ha generato l’evento è admin, che il login è stato effettuato da un certo indirizzo IP di provenienza e da una certa porta. Infine la fase 3 (filtering) ci dice che verrà utilizzata la regola con ID 5710 per generare un alert di livello 5.
Nel file di log degli alert di wazuh-manager ( /var/ossec/logs/alerts/alerts.log ) troveremo l’alert generato da Wazuh:
** Alert 1591099365.7207961: - syslog,sshd,invalid_login,authentication_failed,pci_dss_10.2.4,pci_dss_10.2.5,pci_dss_10.6.1,gpg13_7.1,gdpr_IV_35.7.d,gdpr_IV_32.2,hipaa_164.312.b,nist_800_53_AU.14,nist_800_53_AC.7,nist_800_53_AU.6, 2020 Jun 01 19:38:14 () 192.168.xxx.xxx ->/var/log/secure Rule: 5710 (level 5) -> 'sshd: Attempt to login using a non-existent user' Jun 1 19:38:14 sshd[23579]: Disconnected from invalid user admin 192.168.yyy.yyy port 44039 [preauth]
Analizziamo l’evento tramite Kibana; apriamo l’app di Wazuh, e nel campo “Search” cerchiamo l’utente che ha tentato il login (admin); eventualmente possiamo restringere la ricerca inserendo anche l’intervallo temporale (19.35-19.40):
Da una veloce analisi, l’utente admin è stato utilizzato per effettuare 16 tentativi di accesso non autorizzati tramite SSH (livello 5) (e anche 2 tentativi di SQL injection di livello 6).
Apriamo in Kibana l’app “Discovery“, scegliamo come file di log “wazuh-alerts-3.x-*“, restringiamo il periodo temporale tra le 19.35 e le 19.40; successivamente dalla colonna di sinistra (Available fields) aggiungiamo rule.description e full_log:
Se espandiamo una delle righe precedenti (tramite il triangolino posto alla sua sinistra), possiamo analizzare l’informazione nel formato originale JSON; notiamo che:
agent.id 002
data.srcuser admin
full_log Jun 1 19:38:14 <server> sshd[9929]: Invalid user admin from 192.168.xxx.xxx port 43733
rule.groups syslog, sshd, invalid_login, authentication_failed
rule.id 5710
La regola che è stata applicata è la regola con ID 5710; vediamo nel dettaglio cosa fa questa regola:
# ID=5710; rulefiles=/var/ossec/ruleset/rules/*.xml; grep 'id="'$ID'"' $rulefiles -l; sed -e '/id="'$ID'"/,/\/rule>/!d' $rulefiles; /var/ossec/ruleset/rules/0095-sshd_rules.xml <rule id="5710" level="5"> <if_sid>5700</if_sid> <match>illegal user|invalid user</match> <description>sshd: Attempt to login using a non-existent user</description> <group>invalid_login,authentication_failed,pci_dss_10.2.4,pci_dss_10.2.5,pci_dss_10.6.1,gpg13_7.1,gdpr_IV_35.7.d,gdpr_IV_32.2,hipaa_164.312.b,nist_800_53_AU.14,nist_800_53_AC.7,nist_800_53_AU.6,</group> </rule>
La regola 5710 è una regola “children” della regola 5700; la regola 5700 analizza tutti gli eventi di tipo sshd e ha delle regole “children” (come la 5710) che servono per attivare specifici modelli di evento; successivamente, la regola 5710 va alla ricerca del testo “illegal user” o “invalid user” che appare in un evento che è stato già trovato dalla sua regola “parent” con ID 5700.
Se i tentativi di accesso vengono ripetuti nel tempo, viene attivata un’altra regola, la 5712:
# ID=5712; rulefiles=/var/ossec/ruleset/rules/*.xml; grep 'id="'$ID'"' $rulefiles -l; sed -e '/id="'$ID'"/,/\/rule>/!d' $rulefiles; /var/ossec/ruleset/rules/0095-sshd_rules.xml <rule id="5712" level="10" frequency="8" timeframe="120" ignore="60"> <if_matched_sid>5710</if_matched_sid> <description>sshd: brute force trying to get access to </description> <description>the system.</description> <same_source_ip /> <group>authentication_failures,pci_dss_11.4,pci_dss_10.2.4,pci_dss_10.2.5,gdpr_IV_35.7.d,gdpr_IV_32.2,hipaa_164.312.b,nist_800_53_SI.4,nist_800_53_AU.14,nist_800_53_AC.7,</group> </rule>
Tale regola viene attivata solo se la sua regola parent (la 5710) viene attivata su eventi che coinvolgono lo stesso IP address almeno 8 volte in 120 secondi. Il livello di gravità di questa regola è superiore (10) rispetto alla precedente (solo 5) perché viene individuato un numero elevato di tentativi di accesso SSH non riusciti dalla stessa fonte e generalmente questo è un segno di un attacco di tipo brute-force.
Quindi se su Kibana, troviamo l’attivazione della regola 5712, vuol dire che da un certo indirizzo IP è stato effettuato un tentativo di attacco di tipo SSH brute-force.
Se volessimo ricercare l’evento 5712, da Kibana apriamo la sezione Discover, scegliamo come log “wazuh-alerts-3.x-*” ed impostiamo come filtro: “rule.id: 5712”:
Quindi la regola 5712 è stata in realtà attivata, cioè da un certo indirizzo IP sono stati effettuati almeno 8 tentativi di accesso SSH in 120 secondi con risultato “illegal user” o “invalid user”
Approfondendo l’argomento, possiamo scovare altre informazioni utili; apriamo l’app wazuh e impostiamo solo l’intervallo temporale in cui è avvenuto il tentativo di intromissione brute-force:
Da questa dashboard possiamo vedere come il tentativo di intromissione tramite brute-force SSH sia stato solo una parte di un evento più grande, in cui sono stati effettuati tentativi di attacchi web, XSS, SSHD, SQL Injection, Postifx e altro.
Ritornando al nostro SSH, notiamo come Wazuh abbia applicato (oltre alla regola con ID 5712) anche le regole con ID 5718 e 5719:
# ID=5718; rulefiles=/var/ossec/ruleset/rules/*.xml; grep 'id="'$ID'"' $rulefiles -l; sed -e '/id="'$ID'"/,/\/rule>/!d' $rulefiles; /var/ossec/ruleset/rules/0095-sshd_rules.xml <rule id="5718" level="5"> <if_sid>5700</if_sid> <match>not allowed because</match> <description>sshd: Attempt to login using a denied user.</description> <group>invalid_login,pci_dss_10.2.4,pci_dss_10.2.5,gpg13_7.1,gdpr_IV_35.7.d,gdpr_IV_32.2,hipaa_164.312.b,nist_800_53_AU.14,nist_800_53_AC.7,</group> </rule> # ID=5719; rulefiles=/var/ossec/ruleset/rules/*.xml; grep 'id="'$ID'"' $rulefiles -l; sed -e '/id="'$ID'"/,/\/rule>/!d' $rulefiles; /var/ossec/ruleset/rules/0095-sshd_rules.xml <rule id="5719" level="10" frequency="8" timeframe="120" ignore="60"> <if_matched_sid>5718</if_matched_sid> <description>sshd: Multiple access attempts using a denied user.</description> <group>invalid_login,pci_dss_10.2.4,pci_dss_10.2.5,pci_dss_11.4,gpg13_7.1,gdpr_IV_35.7.d,gdpr_IV_32.2,hipaa_164.312.b,nist_800_53_AU.14,nist_800_53_AC.7,nist_800_53_SI.4,</group> </rule>
Possiamo dunque affermare con certezza (qualora ce ne fosse ancora bisogno) di essere stati vittime di un penetration test ad ampio raggio.
Successivamente vedremo come creare delle regole per attivare delle contromisure in maniera proattiva (reagire allo scanning nel momento esatto in cui accade).