Controllare le password sui Database

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. 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 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;

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). 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 il vecchio meccanisco di autenticazione (MONGODB-CR) e' stato deprecato.

ClickHouse utilizza un file del sistema operativo con l'elenco di username e password: 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.

Algoritmi utilizzati

La teoria degli algoritmi di crittografia e' complessa e richiede basi matematiche significative... quindi non e' il caso di approfondirla!
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

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.

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 attacco brute force per tutto il tempo necessario a decrittografare le password. Ottenute le utenze/password ci si collega poi normalmente all'applicazione...

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.

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.

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: le password vanno cambiate!

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.7 - 14 Febbraio 2017 ❤️ San Valentino
Autore: mail [AT] meo.bogliolo.name