Controllare le password sui Database

John the Ripper Il controllo sulla qualita' delle password utilizzate su un Database migliora in modo significativo la sicurezza di un sistema. In questa pagina descriviamo come controllare le password sui piu' diffusi DB relazionali (Oracle, MySQL, Postgres) con un approccio Brute Force ovvero provandole tutte! Il programma utilizzato per il controllo e' John the Ripper. John the Ripper, un noto tool per la sicurezza dei sistemi, e' uno degli strumenti piu' adatti per la decrittazione delle password poiche' utilizza sia liste di password conosciute, sia l'approccio combinatorio sfruttando algoritmi particolarmente efficienti.

Codice

Un accesso diretto ai database per trovare le utenze meno sicure provando le utenze/password piu' comuni e' tecnicamente fattibile ma molto lento ed intrusivo. L'idea di base utilizzata in questa pagina e' quella di scaricare su file l'elenco delle utenze e delle password (crittografate) e poi controllarle su un altro sistema con John the Ripper...
L'esecuzione di John the Ripper su un sistema Unix e' banale:

# ./john /tmp/mypass.txt

Se una password viene scoperta da John in pochi secondi appartiene ad un dizionario o e' una password veramente troppo facile: e' una password da cambiare! John continua a provare password sempre piu' complesse e lunghe fino a che non viene interrotto. Password lunghe e basate su algoritmi complessi possono richiedere mesi o anni per essere ritrovate da John: queste sono password buone.

John si aspetta un file con il vecchio formato /etc/password, quindi gli script che seguono servono a preparare tale file partendo da un database relazionale.
I principali database relazionali mantengono le password in modo crittografato su un catalogo di sistema. Poiche' ogni DB utilizza oggetti differenti gli esempi sono specifici per ogni tipologia di DB: Oracle, MySQL, Postgres, SQL Server, ... e, per non farci mancare proprio nulla, diamo anche un'accenno ai principali CMS.

Oracle

Oltre al famigerato SYS/CHANGE_ON_INSTALL le password di default di Oracle e dei sui tool sono molte ma possono essere controllate facilmente con la query descritta in questo documento [NdA e' un problema non piu' presente con le versioni piu' recenti di Oracle].
Fino alla versione 11g Oracle calcola l'hash delle password con un triplo DES ed un salt e le mantiene nella tabella di sistema dba_users. Il numero massimo di tentativi di accesso errati e' regolato dal valore FAILED_LOGIN_ATTEMPTS.

Per un controllo piu' completo delle password utilizzate dagli utenti Oracle e' possibile generare un file adatto a John con:

set heading off
set feedback off
set pages 0
set echo off
spool /tmp/mypass.txt

select username||':'|| password
  from dba_users
 where account_status='OPEN';
spool off

Poiche' il formato dell'hash di Oracle e' simile ad altri, per indicare a John la formattazione corretta va utilizzato il comando:

# ./john --format=oracle /tmp/mypass.txt

Dalla versione 11g le password Oracle sono case sensitive, l'hash non e' visibile sulla vista DBA_USERS, l'algoritmo di crittografazione ed il salt sono piu' complessi (da 3DES a SHA-1) ed il salt non dipende piu' dal nome dell'utente ma viene generato. Ecco come estrarre il file per le utenze su cui e' stato utilizzato il nuovo algoritmo (da analizzare con format=oracle11):

set heading off
set feedback off
set pages 0
set lines 132
spool /tmp/mypass.txt

select name||':'|| substr(spare4,3)
  from SYS.USER$
 where spare4 is not null;
spool off
Un trucco molto noto ai DBA Oracle, quando non conoscono una password, e' salvare la vecchia password, impostarne una nuova conosciuta, eseguire le attivita' desiderate ed infine ripristinare la vecchia password con:
ALTER USER username IDENTIFIED BY VALUES 'XXX';
Con la versione 11g... il trucco dell'ALTER funziona anche tra utenze diverse! In precedenza il salt basato sullo username impediva di utilizzare lo stesso valore.

Dalla versione 12 le password utilizzano SHA-2 (SHA-512). Per compatibilita' gli utenti possono utilizzare password in versioni diverse ma ovviamente le versioni piu' recenti sono molto piu' sicure. Per verificare la versione della password si utilizza la query:

SELECT USERNAME, PASSWORD_VERSIONS FROM DBA_USERS;

MySQL

MySQL mantiene le utenze, gli host di provenienza e l'hash delle password nella tabella mysql.user. Le versioni precedenti alla 4.1 utilizzano un algoritmo di crittografazione piuttosto modesto (64 bit), senza salt e con molte collisioni (quindi poco sicuro anche contro gli attacchi brute force).
Dalla versione 4.1 e' utilizzato un doppio SHA-1 ma, anche in questo caso, senza salt: SELECT concat('*', SHA1(UNHEX(SHA1("secret")))); La funzione di crittografazione e' richiamabile da SQL: password() [NdE l'algoritmo si sceglie con SET old_passwords = n; e si utilizza old_password() per le versioni precedenti alla 4.1]. L'assenza di un salt rende abbastanza semplice il confronto con hash precalcolati e l'identificazione di utenze con la stessa password...
Dalla versione 5.6 e' disponibile il plugin sha256_password che utilizza SHA-2 per l'hashing, un salt ed un differente protocollo per l'autenticazione, tuttavia tale plugin non e' ancora molto utilizzato (il default e' mysql_native_password). Dalla versione 5.7 sono state desupportate le password pre-4.1 ed e' stata deprecata la funzione password(). Sulle versioni Enterprise e sui fork sono disponibili plugin di autenticazione esterni (eg. PAM).
Per bloccare eventuali attacchi brute force MySQL mantiene una tabella di cache degli host interna e mette in blackout l'IP del client raggiunto un certo numero di tentativi falliti (max_connect_errors).
Solo a partire dalla versione 5.6 (o su alcuni fork) e' possibile un controllo diretto degli errori di connessione (performance_schema.host_cache), in precedenza tale informazione non era disponibile.

Per ottenere un file per John con MySQL il codice SQL e':

select user, password, host
  from mysql.user
  into outfile '/tmp/mypass.txt'
  fields terminated by ':'
  lines terminated by '\n';

Con la versione 8.0 cambiano ancora le cose (in principio un client 5.7 di default non riusciva a collegarsi alla versione 8.0) e viene utilizzato il plugin caching_sha2_password.

PostgreSQL

La tabella Postgres pg_user, tipicamente accessibile a tutti gli utenti, contiene la lista degli utenti ma non le password... E' necessario utilizzare la tabella pg_shadow, accessibile solo agli amministratori, che riporta anche l'hash della password. Le password in Postgres vengono crittografate con MD5 (per essere precisi viene crittografata la concatenazione della password e del nome utente: SELECT 'md5'||MD5(passwd||usename) . Nell'handshake di autenticazione tra client e server viene scambiato l'hash in chiaro o l'MD5 con salt dell'hash a seconda dell'impostazione presente nel file di configurazione hba.conf (password vs md5). Nelle versioni piu' recenti di Postgres sono presenti le tabelle pg_roles e pg_authid con una strutturazione piu' completa dei diritti di accesso e le autorizzazioni [NdA dalla versione 8.1 del 2005]. Con la versione 10.1 PostgreSQL supporta anche l'algoritmo scram-sha-256 per lo scambio e la memorizzazione della password che e' molto piu' robusto dal punto di vista crittografico e non e' attaccabile facilmente perche' utilizza salt differenti. Il formato di memorizzazione e' SCRAM-SHA-256$Iteration count:Salt$StoredKey:ServerKey in base64. Tuttavia tale algoritmo non e' supportato dalle release precedenti e quindi sara' necessario un po' di tempo prima che venga utilizzato in modo significativo. E' anche possibile utilizzare il formato UNENCRYPTED... ma per fortuna non lo si usa mai. Il codice SQL seguente e' valido per tutte le versioni di Postgres (eccetto per le password in SCRAM-SHA-256) ed estrae un file adatto all'analisi con John (formato raw-md5):

\pset tuples_only
\pset format unaligned
\pset fieldsep ':'
\pset recordsep '\n'
\o /tmp/mypass.txt

select usename, substr(passwd,4)
  from pg_shadow
 where passwd like 'md5%';

SQL Server

SQL Server mantiene i pwdhash nel master.mdf. Formati e tabelle dipendono dalla versione...
SQL Server utilizza SHA-1 (format=mssql), la query per ottenere l'elenco delle utenze e degli hash e':

select name, password
   from master..sysxlogins
   where password IS NOT NULL 
Se la visualizzazione dei valori esadecimali dell'hash della password non e' corretta si puo' utilizzare la funzione master.dbo.fn_varbintohexstr(password).
Con SQL Server 2005 l'algoritmo e' lo stesso ma il differente formato dell'hash (format=mssql05) e' piu' sicuro (non c'e' la conversione in uppercase). In questo caso la query e' quasi identica:
select name, password
  from master.dbo.sysxlogins
 where password IS NOT NULL 
Con SQL Server 2008 la query e' invece:
select name, password_hash 
  from master.sys.sql_logins

Altri DB

DB2 si appoggia al sistema operativo per l'autenticazione delle utenze. Le utenze sono quindi contenute nel file /etc/passwd e tipicamente iniziano con db2 (eg. db2fenc1, db2inst1, dasusr1). L'analisi con John non richiede quindi nulla di diverso rispetto ad un controllo password su Unix, per restringere il file ai solo utenti interessati e' sufficiente un grep -i ^db2

SQLite non dispone di alcun meccanismo di autorizzazione ed utilizza i normali permessi del sistema operativo sul file di database. Alcune applicazioni utilizzano file di database crittografati (eg. Whatsapp con un AES-192), in questi casi e' necessario prima ottenere il file di database in chiaro e quindi accedere con un client SQLite.

CouchDB mantiene le eventuali utenze in _config, le password sono crittografate con SHA-1 ed hanno un salt basato sullo UUID. Per default e' tutto libero a tutti...

Anche su MongoDB per default l'autenticazione non e' abilitata (parametro --auth) [NdA lo era fino alla 3.0]. Le utenze sono definite per database, le utenze del database admin possono agire su tutti i database. L'elenco delle utenze e delle password si ottiene con db.system.users.find().pretty(). L'algoritmo per la memorizzazione della password e' MD5(utente:mongo:password): senza salt! Nella versione 2.4 l'algoritmo e' SHA256(MD5). Con la versione 3.0 e' stato introdotta l'autenticazione SCRAM (Salted Challenge Response Authentication Mechanism) notevolmente piu' sicura, l'implementazione di Mongo utilizza SHA-1. Con la versione 3.6 la vecchia autenticazione MONGODB-CR e' stata deprecata. Dalla versione 4.0 viene utilizzato lo SHA-256 che e' ora il default.

ClickHouse utilizza un file del sistema operativo con l'elenco di username e password: /etc/clickhouse-server/users.xml. Le password possono essere anche in chiaro... ma tipicamente vengono crittografate in SHA256 dal DBA. E' anche possibile utilizzare il doppio SHA-1 come con MySQL.
Dall'introduzione dell'RBAC (eg. praticamente completa dalla versione 20.4) la gestione degli accessi e della sicurezza e' molto sofisticata in ClickHouse. Tra le altre e' presente una tabella system.users e le password sono riportate nei file /var/lib/clickhouse/access/xxx.sql in forma crittografata (default SHA256).

Algoritmi utilizzati

La teoria degli algoritmi di crittografia e' complessa e richiede basi matematiche significative... quindi non sarebbe il caso di approfondirla!
Peroo' qualcosa bisogna conoscerlo comunque... servono algoritmi sicuri per per la verifica d'integrita', lo scambio di chiavi, per l'autenticazione, per la cifratura simmetrica. La prova del nove, quella che si impara alle elementari e che per i numeri binari diventa la parita', e' un tipico algoritmo per il controllo degli errori ovvero per la verifica di integrita'. Le serrature che proteggono le porte di casa sono un altro esempio noto a tutti: se richiedono chiavi piu' complesse sono piu' difficili da scassinare. Lo stesso vale con le chiavi binarie: piu' sono lunghe e piu' sono sicure! Per passare un segreto tra amici? Basta usare qualcosa che si conosce solo tra noi. Per nascondere qualcosa il modo piu' semplice e' quello di metterla dove ve ne sono molte altre simili; cosi' con un numero binario basta moltiplicarlo per un altro o per molti altri. Per avere una chiave binaria sicura... basta utilizzarne una piu' lunga del messaggio da cifrare ed usarla una sola volta; anzi questa e' l'unico tipo di chiave veramente sicura. Pero' attualmente ci si accontenta che non si riesca far bollire tutta l'acqua della terra. Beh, ho semplificato parecchio, ma le basi sono queste!

La tabella seguente riassume gli algoritmi di hash delle password utilizzati per i database descritti in questa pagina:

Algoritmo Bit HEX Database Note
DES 56 14
custom 64 16 MySQL < 4.1 old_password()
MD5 128 32 PostgreSQL
MongoDB
Triple DES fino a 168 Oracle
SHA-1 160 40 MySQL
Oracle >= 11
SQL Server
CouchDB
password() Memorizza il dato con un '*' iniziale (41 HEX)
 
 
 
SHA-2 da 224 a 512 MySQL >= 5.6
Oracle >= 12.1
PostgreSQL >= 10.1
MongoDB >= 2.4
ClickHouse

Non c'e' DB2 perche' dipende dal sistema operativo... Su Unix/Linux l'algoritmo dipende dal salt presente in /etc/shadow: se inizia con $1$ usa MD5, se inizia con $5$ usa SHA-256, se inizia con $6$ usa SHA-512. Negli altri casi utilizza il DES.

Naturalmente nel valutare la robustezza di una base dati nel confronto ad un attacco bruteforce non e' importante solo l'algoritmo utilizzato ma anche la scelta del SALT e le policy sulla qualita' della password (comprese quelle di default). Ma per ora basta cosi!

Applicazioni

Le tecniche riportate in questo documento sono utilizzabili anche su molte applicazioni che utilizzano una base dati. Le applicazioni che subiscono il maggior numero di attacchi sono tipicamente disponibili su web ed implementate con un'architettura LAMP... ci e' parso utile riportare qualche dettaglio sulle piu' diffuse [NdA ovviamente con il LAMP la base dati e' tipicamente MySQL].

Se un'applicazione non e' robusta un possibile attacco puo' essere svolto in due passi: con un attacco di tipo SQL_injection rivolto all'aplicazione on-line si ottiene l'elenco delle utenze e delle password, quindi si analizza off-line l'elenco con un approccio brute force nel tempo necessario a decrittografare le password principali. Ottenute le utenze/password ci si collega poi normalmente all'applicazione e si pubblica tutto quello che si vuole...
Vediamo alcuni dei piu' diffusi CMS:

I nomi dei database possono cambiare, in particolare se sullo stesso server sono ospitati piu' applicazioni, e possono essere utilizzati algoritmi custom per l'autenticazione... ma la maggioranza delle installazioni utilizza le modalita' indicate sopra.

Note

Per analizzare i file ottenuti dai DB va utilizzata la versione arricchita Jumbo di John the Ripper oppure la versione Pro (a pagamento). Entrambe le versioni citate contengono gli algoritmi di crypt necessari. Il sito ufficiale dove trovare il sofware e' ospitato da Openwall; per macos si puo' utilizzare Homebrew: basta lanciare il comando brew install john-jumbo .

Avvertenza Un attacco diretto di tipo Brute Force ad un Database non e' praticamente realizzabile con le versioni attuali dei diversi DB poiche' richiederebbe troppo tempo (i DB rallentano o bloccano appositamente i successivi tentativi di connessione in caso di password errata). Il metodo descritto in questo documento richiede un accesso privilegiato sul DB solo per un breve periodo (il tempo di lanciare una select) e consente un approccio Brute Force per decriptare le password utilizzando un altro server per tutto il tempo necessario.

Una precisazione... Con un attacco Brute Force non e' corretto dire che le password vengono decrittografate: gli algoritmi utilizzati per hash delle password non sono reversibili. Semplicemente vengono provate tutte le possibili combinazioni di caratteri calcolando ogni volta il valore crittografato. Quando si trova una corrispondenza si e' ottenuta la password. Password corte o basate su liste note vengono riconosciute in pochi secondi. Una buona password richiede mesi per essere "decrittografata" su un HW normale. Comunque nessuna password e' in grado di resistere per un tempo indefinito: per questo le password vanno cambiate!

John utilizza ancora il vecchio formato del file /etc/passwd. Ora su linux le password vengono mantenute sul file /etc/shadow con il fomato $id$salt$hashed dove il primo campo indica l'algoritmo di cifratura: $1$ per MD5, $2a$ per Blowfish, $2y$ per Blowfish, $5$ per SHA-256, $6$ per SHA-512.

Altri documenti di questo tipo su questa pagina Hack


Titolo: Controllare le password su Database
Livello: Hack (5/5)
Data: 31 Ottobre 2012 🎃 Halloween
Versione: 1.0.9 - 14 Febbraio 2021 ❤️ San Valentino
Autore: mail [AT] meo.bogliolo.name