Antes de atacar un sitio, un atacante necesita saber a quién atacar. El primer paso casi siempre es conseguir nombres de usuario válidos — porque con un usuario real, el trabajo de fuerza bruta se reduce a la mitad.
WordPress tiene una REST API moderna que introdujo en la versión 4.7. Es útil para desarrolladores. Pero por defecto expone el listado completo de usuarios del sitio a cualquiera que haga un GET — sin autenticación, sin dejar rastro en los logs de intentos de login.
01 / La REST API de WordPress y el endpoint de usuarios
La REST API de WordPress está disponible en /wp-json/wp/v2/
y expone distintos recursos del sitio como posts, páginas, categorías — y usuarios.
El endpoint /wp-json/wp/v2/users devuelve
por defecto el listado de autores del sitio. La intención original era permitir
que aplicaciones externas mostraran información de los autores.
El problema es que incluye el nombre de usuario real — el mismo
que se usa para iniciar sesión.
A diferencia de xmlrpc.php que requiere un POST con payload XML, este endpoint funciona con un simple GET desde cualquier navegador. No requiere herramientas especializadas ni conocimiento técnico previo.
02 / Cómo funciona — request y respuesta
La verificación es inmediata. Un GET al endpoint devuelve la lista de usuarios en formato JSON:
$ curl -s https://target.com/wp-json/wp/v2/users # O simplemente abrí esta URL en el navegador: # https://target.com/wp-json/wp/v2/users
Si el endpoint está activo, la respuesta se ve así:
{
"id": 1,
"name": "Jeremías",
"slug": "adminvilla", ← nombre de usuario real
"link": "https://target.com/author/adminvilla/",
"avatar_urls": { ... }
},
{
"id": 2,
"name": "Editor",
"slug": "editor_principal",
"link": "https://target.com/author/editor_principal/"
}
]
El campo slug es el nombre de usuario exacto que se usa para login.
Con esto, un atacante tiene la mitad del trabajo hecho — solo le falta la contraseña.
03 / Por qué es un problema real
La enumeración de usuarios por sí sola no es un ataque — es el primer paso que habilita otros ataques mucho más peligrosos:
Fuerza bruta dirigida
Sin conocer el usuario, un ataque de fuerza bruta tiene que probar combinaciones de usuario + contraseña. Con el usuario confirmado, el atacante solo necesita encontrar la contraseña. El espacio de búsqueda se reduce drásticamente. Combinado con xmlrpc.php activo — como vimos en el artículo anterior — el ataque se vuelve altamente eficiente.
Credential stuffing
Si el mismo usuario usa el mismo nombre en otros servicios (Gmail, LinkedIn, otros WordPress), una base de datos de contraseñas filtradas puede dar acceso inmediato. El usuario expuesto por /wp-json es el punto de entrada.
Si el sitio tiene xmlrpc.php activo + /wp-json expuesto + contraseña débil o reutilizada, el acceso completo al panel de administración es cuestión de tiempo y recursos computacionales. Los tres problemas juntos los encontramos en múltiples sitios de la región.
04 / Lo que encontramos en la región
Durante los análisis de infraestructura que realizamos en organizaciones del NOA,
el endpoint /wp-json/wp/v2/users estaba activo
y devolviendo usuarios reales en múltiples sitios. En algunos casos el usuario
expuesto era directamente admin o variantes obvias como
adminvilla — patrones que son lo primero que prueba
cualquier herramienta automatizada.
$ curl -s https://target-regional.com.ar/wp-json/wp/v2/users \ | python3 -m json.tool | grep slug [!] "slug": "adminvilla" ← usuario ID 1 expuesto [!] "slug": "redaccion" ← usuario ID 2 expuesto [!] "slug": "admin_web" ← usuario ID 3 expuesto [✗] 3 usuarios válidos identificados sin autenticación
05 / Cómo deshabilitarlo
Opción A — functions.php (recomendado)
Agregá este código al archivo functions.php de tu tema activo
o, mejor aún, creá un plugin simple para no perder el cambio al actualizar el tema:
// Deshabilitar enumeración de usuarios via REST API add_filter( 'rest_endpoints', function( $endpoints ) { if ( isset( $endpoints['/wp/v2/users'] ) ) { unset( $endpoints['/wp/v2/users'] ); } if ( isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ) ) { unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ); } return $endpoints; } );
Opción B — Plugin
Si no tenés acceso al código, el plugin Disable REST API o WP Hide & Security Enhancer permiten bloquear el endpoint sin tocar código.
Verificación post-cierre
"code": "rest_no_route",
"message": "No route was found matching the URL and request method.",
"data": { "status": 404 }
}
Después de aplicar el fix, el endpoint debe devolver 404 o un error de ruta no encontrada. Si sigue devolviendo una lista de usuarios, el código no se aplicó correctamente o hay otro plugin que está re-registrando los endpoints.
06 / Conclusión
La REST API de WordPress es una funcionalidad legítima y útil. El problema no es la API en sí — es que el endpoint de usuarios no debería ser público por defecto en la mayoría de los sitios.
Si tu sitio WordPress no es una plataforma que necesita exponer usuarios públicamente (un directorio de autores, por ejemplo), este endpoint debería estar deshabilitado. El fix tarda menos de 5 minutos y elimina uno de los vectores más usados en ataques automatizados contra WordPress.
¿Querés saber qué más tiene expuesto tu sitio WordPress?
Revisamos xmlrpc.php, REST API, wp-login y más — sin costo, sin compromiso.
Solicitar evaluación gratuita →