;

Si te gusta ir a WordCamps como a mí, probablemente ya hayas escuchado esto :» WordPress password hashing no es seguro», o en la versión más técnica:»…porque está basado en md5″.

Verdadero o no, un hash de contraseña seguro es crucial para un gran ecosistema como el de WordPress, que siempre ha sido un objetivo jugoso para los hackers. Por lo tanto, decidí echar un vistazo más de cerca al sistema de hashing y tratar de descifrar los hashes de WordPress desde cero.

Entendiendo los hashes de contraseñas de WordPress

Comencé a buscar en Google y descubrí que la mayor parte de la información que hay es genérica y confusa. Muchas referencias a las bibliotecas PHP utilizadas (hash portátil de phpass), pero nada realmente concreto.

Decidí adoptar un enfoque diferente a partir de una suposición:

el hash es un proceso unidireccional, pero WordPress es capaz de autenticar a los usuarios que coinciden con su entrada de contraseña con el hash almacenado en la base de datos

A partir de ahí, comencé a verificar el código y encontré la primera función interesante: wp_check_password($password,$hash) que compara la contraseña de texto plano con el hash y devuelve true si coinciden.

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

Pasando por el código, rápidamente nos lleva a CheckPassword, crypt_private y encode64, que básicamente es donde ocurre la magia.

En resumen, crypt_private($password, $stored_hash) cambia el hash de la contraseña antes de que se compare con el hash almacenado. Si coinciden, la contraseña es correcta y la autenticación continúa. Lo que significa que también podemos usar esa función para descifrar el hash.

Anatomía del hash

Este es un hash de WordPress:

1$P$BnPVO4gP9JUMSAM1WlLTHPdH6EDj4e1

Para simplificar, asumiremos que el sitio utiliza PHP> 5 y el hash portátil phpass más reciente, que es la configuración más común.

Los primeros 3 caracteres $P$ son un ID, que indica al sistema qué tipo de hash oh tenemos.

El número de caracteres 3 (contando desde 0) se usa para determinar cuántas veces la md5 () tiene que procesar la cadena de entrada.

Los caracteres de 4 a 12 nPVO4gP9 son la sal, que es una cadena aleatoria anexa a la contraseña antes del hash, para darle más aleatoriedad. Por ejemplo, si su contraseña es admin, se convierte en nPVO4gP9admin y luego se pasa a hash.

La parte restante del hash JUMSAM1WlLTHPdH6EDj4e1 es la aleatoriedad real, generada por la contraseña salt + pasada en una función encode64 indocumentada, que realiza algunas operaciones de bits en la cadena de entrada y devuelve una salida de 22 caracteres.

No está tan claro, ¿eh? Quédate conmigo.

Hasta ahora lo sabemos:

  • la primera parte del hash es un id fijo
  • la segunda es un solo carácter utilizado como contador, también fijo
  • la tercera es la sal, vinculada a la contraseña
  • la última es aleatoria, generada por ‘salt + pass’ procesada por la función encode64
1

Por lo tanto, podemos volver a escribir la lógica-salt+contraseña con hash X veces y pasada en encode64 – para realizar un diccionario o un ataque de fuerza bruta, y obtener la misma ‘última parte’ del hash, ¡y eso sería un crack de hash exitoso!

En un escenario de la vida real, y los hackers estarían más interesados en encontrar contraseñas débiles porque es más probable que se reutilicen, en lugar de las aleatorias que a menudo genera un administrador de contraseñas y, por lo tanto, específicas del sitio.

Reescribir code64 usando golang

Decidí ir con golang porque es muy rápido, y necesitamos toda esa velocidad para calcular diccionarios de contraseñas grandes.

Al igual que en el procedimiento de cifrado de WordPress, el script toma el hash y aísla la sal, luego compone la contraseña (salt+pass) intentando cada contraseña en el diccionario y md5-hashing X número de veces, y hemos visto cómo se determina X.

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

Hecho esto, realiza una serie de operaciones a bit sobre bytes obtenidos usando ord () en PHP, que no necesitamos en golang ya que tenemos valores de bytes:

1itoa64 & 0x3f]

En este punto, me di cuenta de que ni siquiera necesitamos encontrar la cadena completa. ¡Basta con que coincida con unos pocos caracteres para que coincida con toda la contraseña y haga que el guion sea más eficiente! Por lo tanto, debido a la naturaleza del proceso de hash, si char n. 0 / 4 / 8 … coincidencias, la contraseña pasada como entrada es correcta.

Y BOOM, desciframos el hash:

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

El código es como de costumbre en GitHub – https://github.com/francescocarlucci/wphashcrash – y por el momento, el script es un POC y obtiene solo un hash de contraseña como entrada, y la ruta al diccionario de contraseñas.

Ya he esbozado en el léame algunas mejoras que sería bueno tener y probablemente añadiré en el futuro.

Si realmente quieres intentar hackear una lista de hashes, puedes bifurcarla o simplemente envolver el script en un bucle bash for.

Consideraciones de seguridad

En este punto, creo que está suficientemente claro que si un atacante obtiene acceso a la base de datos en un sitio de WordPress, básicamente puede descifrar todas las contraseñas débiles.

Este desafortunado, especialmente porque:

  • La inyección SQL no es tan rara en complementos de WordPress
  • RCE también probablemente otorgará acceso a la base de datos
  • El ecosistema de WordPress es un gran territorio para el trabajo de freelancer y es muy común encontrar cuentas wp-admin y FTP antiguas/no utilizadas, creadas para necesidades temporales

Este último punto, combinado con la enumeración de usuarios que un problema común de WordPress deja la puerta se abre para obtener acceso a la base de datos utilizando credenciales de administrador robadas/empeñadas.

Además de esto, muchos sitios web no aplican contraseñas seguras para no dañar la experiencia del usuario, y tengo experiencia directa en cualquiera de los puntos mencionados.

Una vez que un sitio web está comprometido, tener hashes débiles almacenados permite a los atacantes comprometer otras cuentas de usuario en otros sitios, si tienden a reutilizar contraseñas y sabemos que lo hacen.

¿Tenemos soluciones?

Mi investigación no fue tan lejos, solo quería ver cómo romper los hashes de WordPress.

Bcrypt es conocido por ser un método de hash más fuerte en comparación con md5, y hay un complemento existente que usa bcrypt y reemplaza todas las funciones básicas necesarias para manejar contraseñas:

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

Y, por supuesto, puede escribir su propia solución como desarrollador, pero creo que este es un problema que debe solucionarse a nivel central para apuntar a una gran adopción.

Nota final

Hay muchas herramientas para descifrar hashes, como Hashcat y John El Destripador, que pueden ser aún más eficientes, pero de nuevo, el alcance de esta investigación es comprender la estructura de hash de WordPress y descifrarla desde cero.

Gracias por leer.

frenxi

Write a Comment

Tu dirección de correo electrónico no será publicada.