;

Se ti piace andare ai WordCamp come faccio io, probabilmente hai già sentito questo: “WordPress password hashing non è sicuro”, o nella versione più tecnica: “…perché è basato su md5”.

Vero o no, un hashing password forte è fondamentale per un grande ecosistema come quello di WordPress, che è sempre stato un bersaglio succosa per gli hacker. Così, ho deciso di dare un’occhiata più da vicino al sistema di hashing e cercare di rompere gli hash di WordPress da zero!

Comprensione degli hash delle password di WordPress

Ho iniziato a fare un po ‘ di googling e ho scoperto che la maggior parte delle informazioni là fuori è generica e confusa. Molti riferimenti alle librerie PHP utilizzate (hash portatile da phpass), ma niente di veramente concreto.

Ho deciso di adottare un approccio diverso partendo da un presupposto:

l’hashing è un processo a senso unico, ma WordPress è in qualche modo in grado di autenticare gli utenti che corrispondono all’input della password con l’hash memorizzato nel database

Da lì, ho iniziato a controllare il codice e ho trovato la prima funzione interessante: wp_check_password($password,$hash) che confronta la password di testo normale con l’hash e restituisce true

1// presume the new style phpass portable hash.
2if ( empty( $wp_hasher ) ) {
3 require_once ABSPATH . WPINC . '/class-phpass.php';
4 // By default, use the portable hash from phpass.
5 $wp_hasher = new PasswordHash( 8, true );
6}
7
8$check = $wp_hasher->CheckPassword( $password, $hash );
9
10/** This filter is documented in wp-includes/pluggable.php */
11return apply_filters( 'check_password', $check, $password, $hash, $user_id );

Passando attraverso il codice, ci porta rapidamente a CheckPassword, crypt_private e encode64 che fondamentalmente è dove avviene la magia.

Per farla breve, crypt_private($password, $stored_hash) ri-hash la password prima che venga confrontata con l’hash memorizzato. Se corrispondono, la password è corretta e l’autenticazione continua. Il che significa che possiamo anche usare quella funzione per rompere l’hash.

Hash anatomy

Questo è un hash di WordPress:

1$P$BnPVO4gP9JUMSAM1WlLTHPdH6EDj4e1

Per semplicità, assumeremo che il sito usi PHP > 5 e il più recente hash portatile phpass, che è la configurazione più comune.

I primi 3 caratteri $P$ sono un ID, che dice al sistema quale tipo oh hash abbiamo.

Il numero di caratteri 3 (contando da 0) viene utilizzato per determinare quante volte md5 () deve elaborare la stringa di input.

I caratteri da 4 a 12 nPVO4gP9 sono il sale, che è una stringa casuale aggiunta alla password prima dell’hashing, per dargli più casualità. Ad esempio, se la tua password è admin, viene attivata su nPVO4gP9admin e quindi hash.

La parte rimanente dell’hash JUMSAM1WlLTHPdH6EDj4e1 è la casualità reale, generata dalla password salt+passata in una funzione encode64 non documentata, che esegue alcune operazioni bit a bit sulla stringa di input e restituisce un output di 22 caratteri.

Non è così chiaro, uh? Resta con me.

Finora sappiamo:

  • la prima parte dell’hash è un fisso id
  • il secondo è un singolo carattere usato come contatore, anche fisso
  • il terzo è il sale, legato alla password
  • l’ultimo è casuale, generato da “sale+pass’ trattati da encode64 funzione
1

Così, siamo in grado di ri-scrivere la logica di sale+password hash X volte e passato nel encode64 – per eseguire un dizionario o un attacco bruteforce, e ottenere lo stesso ‘ultimo tratto’ di hash, e che sarebbe un successo hash crack!

In uno scenario di vita reale, e gli hacker sarebbero più interessati a trovare le password deboli perché sono più probabilità di essere riutilizzati, invece di quelli casuali che sono spesso generati da un gestore di password e così site-specific.

Riscrivendo encode64 usando golang

Ho deciso di andare con golang perché è molto veloce e abbiamo bisogno di tutta quella velocità per calcolare dizionari di password di grandi dimensioni.

Proprio come nella procedura di crittografia di WordPress, lo script prende l’hash e isola il sale, quindi compone la password (salt+pass) tentando ogni password nel dizionario e md5-hashing X numero di volte, e abbiamo visto come X è determinato.

1itoa64 := "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
2hashloop := 1 << strings.Index(itoa64, string(hash)); // char n. 4 in the hash

Fatto ciò, esegue una serie di operazioni bit a bit su byte ottenuti usando ord () in PHP, di cui non abbiamo bisogno in golang in quanto abbiamo già valori di byte:

1itoa64 & 0x3f]

A questo punto, mi sono reso conto che non abbiamo nemmeno bisogno di trovare l’intera stringa. È sufficiente abbinare alcuni caratteri per abbinare l’intera password e rendere lo script più performante! Quindi, a causa della natura del processo di hashing, se char n. 0 / 4 / 8 … corrisponde, la password passata come input è corretta.

E BOOM, abbiamo rotto l’hash:

1wphashcrash '$P$BnPVO4gP9JUMSAM1WlLTHPdH6EDj4e1' Dev/wphashcrash/dict.txt
2$P$BnPVO4gP9JUMSAM1WlLTHPdH6EDj4e1 admin
32020/05/30 12:44:15 Executed in 0.000221

Il codice è come al solito su GitHub – https://github.com/francescocarlucci/wphashcrash – e al momento, lo script è un POC e ottiene solo un singolo hash della password come input e il percorso del dizionario della password.

Ho già delineato nel readme alcuni miglioramenti che sarebbe bello avere e probabilmente aggiungerò in futuro.

Se vuoi davvero provare a hackerare un elenco di hash, puoi biforcarlo o semplicemente avvolgere lo script in un ciclo bash for.

Considerazioni di sicurezza

A questo punto, penso che sia abbastanza chiaro che se un utente malintenzionato ottiene l’accesso al database su un sito WordPress, lui/lei può fondamentalmente rompere ogni password debole.

Questo sfortunato, soprattutto perché:

  • SQL Injection non è raro in WordPress plugins
  • RCE sarà anche più probabile concedere l’accesso al DB
  • WordPress è un ecosistema di un territorio enorme per freelancer lavoro ed è molto comune trovare vecchi/inutilizzati wp-admin e account FTP, creato per temporanee esigenze

Quest’ultimo punto, combinato con enumerazione degli utenti che WordPress problema comune, lascia aperta la porta per accedere al DB usando furto/dato in pegno le credenziali di amministratore.

In cima a questo, molti siti web non impongono password complesse per non danneggiare l’esperienza utente, e ho esperienza diretta in uno qualsiasi dei punti menzionati.

Una volta che un sito web è compromesso, avere hash deboli memorizzati consente agli aggressori di compromettere altri account utente su altri siti, se tendono a riutilizzare le password e sappiamo che lo fanno.

Abbiamo soluzioni?

La mia ricerca non è andata così lontano, volevo solo vedere come rompere gli hash di WordPress.

Bcrypt è noto per essere un forte metodo di hashing rispetto al md5, e c’è un plug-in esistente che utilizza bcrypt e sostituisce tutte le principali funzioni necessarie a gestire le password:

  • wp_check_password()
  • wp_hash_password()
  • wp_set_password()

E, naturalmente, è possibile scrivere la vostra propria soluzione come sviluppatore, ma credo che questo sia un problema da risolvere a livello di base per puntare ad un grande adozione.

Nota finale

Ci sono molti strumenti per decifrare gli hash, come Hashcat e John The Ripper che possono essere ancora più performanti, ma ancora una volta, lo scopo di questa ricerca è capire la struttura di hash di WordPress e cracking da zero.

Grazie per la lettura.

frenxi

Write a Comment

Il tuo indirizzo email non sarà pubblicato.