- GPT5.6 Sol Ultra analizó la última versión estable de WordPress y, en poco más de 10 horas, completó una cadena de ataque que va desde una inyección SQL previa a la autenticación hasta la creación de una cuenta de administrador y la ejecución remota de código (RCE)
- El punto de partida fue una discrepancia en los índices de arreglos de la Batch API, disponible desde WordPress 5.6, que al combinar solicitudes Batch recursivas permite evadir restricciones de GET y validación de parámetros
- Tras provocar una inyección UNION con una cadena
author_excludeno validada, insertó una publicación manipulada en la caché en memoria y abusó en cadena de caché oEmbed, changeset, referencias circulares y hooks - Con
user_id: 1encustomize_changesetobtuvo privilegios temporales de administrador y, mediante el hookparse_request, volvió a ejecutar la solicitud Batch para crear un nuevo administrador; luego subió un ZIP con un plugin backdoor para llegar a ejecución de código - El costo proporcional de usar el 50% del cupo semanal de una suscripción de 200 dólares mensuales fue de unos 25 dólares, y es cada vez más probable que el rol humano se desplace hacia la dirección de investigación de alto nivel, como elegir el producto y la superficie de ataque y ajustar prompts
Proceso de descubrimiento y condiciones del experimento
- Se modificó para investigación de seguridad el prompt que OpenAI dijo haber usado para resolver la conjetura Cycle Double Cover, y se lo entregó a GPT5.6 Sol Ultra
- Se clonó la última versión estable de WordPress en
main/, se eliminó el directorio.gity se preparó un directorio vacíothird_party/para que pudiera investigar código dependiente - El prompt indicaba usar hasta 4 agentes en paralelo y mantener diversas rutas de ataque durante al menos 6 horas
- Exploraba parsing de entradas, conjuntos de caracteres, subida de archivos, manejo de errores, rutas integradas, serialización, caché, condiciones de carrera, cifrado, tipos, asignación masiva, etc.
- Registraba familias de enfoques y, si los agentes se concentraban en una estrategia concreta, los reubicaba hacia áreas menos exploradas
- Los bugs concretos eran revalidación por agentes adversarios, y las rutas fallidas se reabrían si aparecía un mecanismo nuevo
- Se restringió la búsqueda a encontrar vulnerabilidades nuevas en el propio código fuente, sin usar historial de cambios, diferencias con versiones parcheadas ni pistas de Internet
- Para evitar configuraciones poco realistas o prerrequisitos que un atacante no pudiera cumplir, se explicitó el objetivo como “RCE previa a la autenticación en una implementación de producción típica que use MySQL”
- Unas 6 horas después, el modelo encontró una inyección SQL previa a la autenticación, y se reprodujo en minutos extrayendo el email del administrador desde un servidor remoto WordPress por defecto
- Al pedirle además una escalada a RCE, unas 4 horas después completó una cadena que subía desde una inyección SQL de solo lectura hasta privilegios de administrador, sin crackeo de contraseñas ni cálculos offline
- El tiempo total de trabajo fue de poco más de 10 horas y consumió el 50% del cupo semanal. El costo proporcional sobre una suscripción mensual de 200 dólares fue de unos 25 dólares
- Antes de la publicación se dio tiempo durante el fin de semana para que los operadores actualizaran WordPress y, mientras tanto, Calif y Hacktron reprodujeron de forma independiente la cadena completa antes que otros PoC de GitHub
- Las instancias en operación pueden verificar si son vulnerables en wp2shell.com
Discrepancia de validación en la Batch API
- La Batch API, introducida en WordPress 5.6, procesa varias solicitudes API virtuales en una sola solicitud. Al endpoint en sí se puede acceder sin autenticación, pero a cada subsolicitud se le pasa la información de autenticación
- Una solicitud REST normal se procesa en este orden
- Revisa valores obligatorios y validez con
has_valid_params() - Sanitiza valores con
sanitize_params() - Ejecuta el callback de permisos
- Ejecuta el callback del endpoint
- Revisa valores obligatorios y validez con
- Por rendimiento, la Batch API separa la validación y la ejecución en dos bucles
- En el primer bucle valida y sanitiza todas las solicitudes
- En el segundo bucle revisa los resultados de validación y ejecuta callbacks de permisos y de endpoints
- La implementación asume que el resultado de matching de rutas,
$matches, y el resultado de validación,$validation, corresponden por el mismo índice - Cuando una solicitud inválida entra en la rama
is_wp_error($single_request), agrega un elemento a$validation, pero por elcontinueno lo agrega a$matches- Después, todos los elementos de
$matchesse desplazan una posición - Se pueden validar los parámetros de una solicitud con las reglas de otra y luego ejecutarlos en un handler de endpoint que no era el previsto
- Después, todos los elementos de
- Esta discrepancia de índices permite aplicar a un endpoint compatible con Batch el resultado de validación de otro endpoint que no sanitiza parámetros
Inyección SQL en author__not_in
GET /wp/v2/postsusa internamente la variable de consultaauthor__not_inpara excluir ciertos autores de los resultados- Si el valor es un arreglo, aplica
absinta cada elemento para convertirlo a entero, pero si es un valor escalar lo pasa tal cual aimplodey lo inserta en la cláusula SQLNOT IN - En una llamada normal, el parámetro público
author_excludedebe ser un arreglo de enteros, por lo que el problema no queda expuesto - Con la discrepancia de índices de Batch, se puede validar una cadena
author_excludecon las reglas deDELETE /wp/v2/posts/1, que no la reconocen, y luego pasarla aGET /wp/v2/posts - La restricción de que la Batch API no permite subsolicitudes GET también se evade con llamadas Batch recursivas
- En el Batch externo se provoca la discrepancia de índices para saltar la validación del
methodde la solicitud interna - En el Batch interno se vuelve a provocar la discrepancia de índices para evadir la validación de
author_exclude
- En el Batch externo se provoca la discrepancia de índices para saltar la validación del
- Al insertar un valor como
0) OR 1=1 --, se devuelven todas las filas de publicaciones y se puede confirmar la inyección - Luego, con inyección basada en UNION, se pueden construir filas con la misma forma que
wp_postsy filtrar valores arbitrarios de la base de datos - Como contraseñas, tokens de restablecimiento, claves de API, etc. están hasheados en la base de datos, si la contraseña del administrador no es débil, la fuga de datos por sí sola no alcanza para tomar la cuenta
Manipulación de caché de publicaciones dentro de una solicitud
- WordPress guarda en caché en memoria los objetos
WP_Postreferenciados repetidamente dentro de una solicitud para reducir viajes a la base de datos - Si se devuelve una fila falsa de publicación mediante inyección UNION, el atacante puede poner en caché muchos campos bajo su control, como ID de publicación, tipo, estado, relación padre y cuerpo
- La respuesta de la API también posprocesa el cuerpo de la publicación, por lo que un cuerpo manipulado puede ejecutar rutas de código adicionales
- Esta caché desaparece al terminar la solicitud y la publicación falsa no existe en la base de datos, así que la manipulación de caché por sí sola no logra persistencia entre solicitudes
Creación de filas de base de datos con caché oEmbed
- La función embeds de WordPress inserta contenido remoto compatible mediante la sintaxis
[embed]...[/embed]en el cuerpo de una publicación - Para no enviar una solicitud HTTP cada vez, guarda los resultados en la base de datos como publicaciones de tipo
oembed_cacheenwp_posts - Al embeber una publicación local de WordPress con una ruta relativa, omite la solicitud HTTP y no verifica si el ID de la publicación referenciada realmente existe
- Incluso al embeber una publicación local inexistente como
/?p=10, puede crearse una filaoembed_cachepara esos datos - Si la fila creada se consulta de nuevo mediante inyección SQL y se manipula el tipo de publicación en memoria a algo como
post, la representación en base de datos y en caché queda distinta - Al conciliar ambas representaciones, WordPress llama a
wp_update_post()y, salvo los campos especificados explícitamente comoIDypost_content, prefiere los valores en memoria creados por el atacante - Así se puede convertir una fila
oembed_cacheen una publicación normal, pero en esta llamadapost_contentse sobrescribe con el resultado del embed, por lo que el atacante no llega a controlar también el cuerpo
Privilegios temporales de administrador mediante customize_changeset
- Los borradores de personalización de temas se guardan en
wp_postscomo publicaciones especiales de tipocustomize_changeset post_contentcontiene JSON con los cambios por clave de configuración, el tipo y el ID de usuario que realizó el cambio- Al aplicar un changeset, WordPress lee el
user_idde cada elemento y cambia temporalmente el usuario actual conwp_set_current_user() - Si un atacante aplica un changeset con
user_id: 1, puede usar por un momento la identidad del administrador incluso dentro de una solicitud anónima - Como la llamada de conciliación oEmbed anterior sobrescribe
post_content, se necesita una ruta separada de llamada awp_update_post()que preserve el JSON malicioso del changeset
Preservar el cuerpo mediante un ciclo en el padre de la publicación
- Las publicaciones de WordPress pueden tener un padre, pero no se permiten estructuras circulares donde el padre sea la propia publicación o una publicación hija
- El filtro
wp_insert_post_parentrecorre la jerarquía de padres para detectar ciclos y, si encuentra uno, llama awp_update_post()para cambiar elpost_parentde esa publicación a 0 - Esta segunda llamada solo especifica
IDypost_parent, y no sobrescribepost_content - Si mediante inyección SQL se adorna la publicación en memoria como un
customize_changesetque se tiene a sí misma como padre, el proceso de reparación del ciclo registra en la base de datos el JSON malicioso del changeset especificado por el atacante - Si se crea un changeset con fecha pasada y estado
future, WordPress lo aplica y realiza los cambios de configuración indicados con privilegios de administrador segúnuser_id: 1 - Los privilegios de administrador solo se mantienen durante la operación del changeset y al completarse se vuelve a permisos de invitado
Reejecución completa de la solicitud con un hook dinámico
- Los hooks de WordPress se dividen en acciones (actions) y filtros (filters), y permiten a los plugins intervenir en diversos puntos del ciclo de vida, como login, publicación o registro de scripts
- Cuando cambia el estado de una publicación, WordPress ejecuta una acción dinámica con la forma
"{$new_status}_{$post->post_type}"- En una publicación normal sería un nombre como
publish_post - En una publicación falsa en memoria, el estado y el tipo se pueden definir arbitrariamente, así que se puede construir el nombre de una acción deseada con al menos un guion bajo
- En una publicación normal sería un nombre como
- Los argumentos del hook están limitados al ID de publicación y al objeto
WP_Postque el atacante elige, por lo que es difícil llamar directamente a una acción arbitraria de forma útil - La cadena de ataque manipula el estado como
parsey el tipo comorequestpara llamar al hookparse_request parse_requestes un hook que se ejecuta al inicio del ciclo de vida de una solicitud, así que llamarlo de nuevo hace que la solicitud Batch API original se reprocese desde el principio- El reprocesamiento ocurre mientras se mantiene la identidad temporal de administrador configurada por el changeset, por lo que las solicitudes solo para administradores que fallaron en la primera ejecución tienen éxito en la segunda
Cadena RCE completa en dos solicitudes
- El exploit final usa dos solicitudes HTTP y asigna a las publicaciones falsas IDs lo bastante grandes como para no chocar con publicaciones reales
-
Primera solicitud: preparar filas persistentes
- Mediante inyección SQL devuelve una publicación falsa con tres embeds locales para crear 3 filas
oembed_cachecorrespondientes aO,CyD - Los tres embeds apuntan a la misma publicación
S, pero usan query strings distintas para generar hashes separados de caché oEmbed
- Mediante inyección SQL devuelve una publicación falsa con tres embeds locales para crear 3 filas
-
Segunda solicitud: ensamblar seis publicaciones
- Construye las siguientes seis publicaciones falsas en la caché en memoria
O: caché antigua con estado/tipopublish/oembed_cachey padreCC: estado/tipofuture/customize_changeset, se tiene a sí misma como padre e incluye el JSON malicioso del changesetP:draft/pagecon padreDD: estado/tipoparse/requesty se tiene a sí misma como padreS:publish/postque provee los datos del embedT:publish/postque contiene el embed externo- El embed de
TconsultaO, y por la fecha de modificación antigua hace que se renueve la caché deS - Cuando durante la renovación de
Ose detecta el ciclo del padreC, se cambia el padre deCa 0 y se escribe en la base de datos elcustomize_changeseten memoria junto con el JSON malicioso - Al aplicarse el changeset
futurecon fecha pasada, se publicaPcon la identidad de administrador deuser_id: 1 - La actualización de
Pdetecta el ciclo del padreD, registraDy, con el estado y tipo manipulados, llama a la acciónparse_request - La solicitud Batch incluye desde el principio una solicitud para crear un nuevo administrador
- En el primer procesamiento falla por estar con permisos de invitado
- Al reejecutarse mediante
parse_request, aún quedan privilegios temporales de administrador, así que tiene éxito - Tras iniciar sesión con la nueva cuenta de administrador y subir un ZIP con un plugin backdoor, finalmente se llega a ejecución remota de código
Roles cambiantes en la investigación de seguridad con IA
- Las etapas especialmente creativas de toda la cadena fueron evadir la restricción de GET con llamadas Batch recursivas, combinar caché y changeset para obtener privilegios de administrador, y llamar a
parse_requestcon publicaciones falsas para reejecutar la solicitud - Aunque no se puede afirmar una superioridad general, la evaluación es que habría sido imposible que un investigador de seguridad descubriera y completara la misma cadena en 10 horas sin IA
- Incluso si se proporcionara de antemano el bug original de Batch, se considera difícil estar seguro de poder construir el RCE en ese tiempo
- Se juzga que GPT5.6 Sol Ultra avanzó mucho respecto de GPT5.5 en la capacidad de encontrar varios gadgets de código separados y conectarlos en una sola cadena
- A medida que el modelo se encargue de más desarrollo técnico de exploits, las personas se enfocarán en decidir qué productos y superficies de ataque investigar, cuánto tiempo dedicar, qué rumbo dar a la investigación y cómo corregir al modelo cuando se desvíe
- Estas capacidades de metainvestigación aún no son algo que la IA maneje bien, y se prevé que se vuelvan más importantes conforme aumenten las capacidades técnicas de los modelos
1 comentarios
Opiniones de Hacker News
No hay base para afirmar que se hayan pagado, o se vayan a pagar, 500.000 dólares por este exploit. Como el artículo dice que ajustan el prompt con el cuidado de si fuera una escritura sagrada, quizá mejor podrían vender ese prompt por 500.000 dólares.
El autor trabaja en https://www.assetnote.io/, que ofrece un producto de escaneo automático con IA.
Estos intermediarios normalmente no pagan grandes sumas de una sola vez; venden el acceso a actores estatales y luego pagan en partes mientras el bug siga sin parchearse. Como es una estructura pensada para evitar la reventa o que se agote demasiado pronto, probablemente casi nadie pueda confirmar si realmente recibió el monto completo por una vulnerabilidad similar.
El ejemplo más cercano son unos adolescentes de Florida que metieron malware en un juego de Steam para robar cuentas y terminaron detenidos. Igual los habrían atrapado, pero si no hubieran presumido en redes sociales, la investigación habría tardado mucho más.
Al ver https://github.com/WordPress/WordPress/commit/3a640e1c5e39aa..., aparece una inyección SQL por concatenación de strings incluso en 2026.
En lugar de ejecutar SQL directamente, dicen que hay que usar
dbDelta, pero exigen reglas de formato extremadamente quisquillosas: separar cada campo en una línea, poner dos espacios entrePRIMARY KEY, usarKEYen vez deINDEX, etc. No se deben usar comillas ni backticks en los nombres de campos, los tipos de datos deben ir en minúscula, las palabras clave SQL en mayúscula y todos los parámetros de longitud deben especificarse.sprintf.Las solicitudes
POSTyGETincluían payloads como/wp/v2/widgets?author_exclude=1%29+AND+1%3D0+UNION+ALL+SELECT....Principal Software Engineer @ Bluehost,WordPress Core Committer; con código así, la palabra “principal” suena bastante extraña.Estoy cansado de la escritura estilo FOMO. No lo descubrió solo con 25 dólares: tenía conocimiento especializado de la industria sobre dónde mirar y cómo investigar, además de años de material acumulado.
Hay que dejar de difundir narrativas de apuesta y la ilusión de que todo el mundo se está perdiendo una oportunidad.
Lo sorprendente es el alto precio de una vulnerabilidad ya conocida, y puede que ni siquiera sea cierto. WordPress suele llamarse una shell root remota con funciones de blog.
Entiendo que para un usuario común es más fácil guiarlo con arrastrar y soltar que pedirle que haga commits a un repositorio de GitHub y compile con Hugo. Pero desde el punto de vista de seguridad, es una estructura que solo espera a que aparezca una vulnerabilidad en el core o en alguno de miles de plugins para abrir una ejecución remota de código como servicio.
Es un artículo interesante, y el descubrimiento y la divulgación de exploits basados en LLM son una preocupación real. Alguna vez hice que un modelo generara con relativa rapidez código de escape de contenedores a partir de una vulnerabilidad de escalamiento local de privilegios en Linux.
Aun así, sorprende que GPT-5.6 no haya bloqueado el prompt con sus salvaguardas. GPT-5.5 y superiores tienden a evitar el trabajo ofensivo de seguridad, como Opus 4.7+/Fable, así que parece posible que el autor haya recibido una aprobación de ciberseguridad de OpenAI que relaja las salvaguardas.
Incluso las herramientas de pruebas estáticas de seguridad de aplicaciones (SAST) no basadas en IA anteriores a 2020 detectaban muchas de estas inyecciones SQL, y como mínimo deberían haberse encontrado en una revisión de código. Me pregunto si WordPress no usa revisión de código ni SAST
Uno de mis sitios web fue hackeado con esta vulnerabilidad, pero por suerte era uno sin usuarios
El atacante creó dos cuentas de administrador en la base de datos e instaló en
wp-content/plugins/wp-coreun web shell de ejecución remota de comandos llamadowp-core-[12 caracteres aleatorios].php. Enmu-pluginsdejó un backdoorfirewall.phpque crea un administrador conGET ?sergei, también agregó un backdoorcache-seo-helper.php, y confixer.phpcambió el número de versión de WordPress para que pareciera una versión parcheada. Al final decidí dejar de usar WordPressHacia el final del artículo empezó a llamar a las publicaciones con nombres raros y se volvió difícil de entender. Me pregunto por qué hizo que un ID fuera
Oy otro0, y por qué usó un solo carácter yOCPDST, que parece aleatorio, en vez deEMBED_01oABCDEFOsignificapublish/oembed_cache,Csignificafuture/customize_changeset,Psignificadraft/page,Dsignificaparse/request,Ssignificapublish/postque proporciona datos de embed, yTsignificapublish/postque contiene un embed externoMe pregunto si están suponiendo que las personas que pagarían 500 mil dólares no tienen la capacidad de usar GPT-5.6 directamente
Yo también uso LLM para encontrar vulnerabilidades de seguridad, pero no puedo simplemente enviar el resultado tal cual y darlo por terminado; hay mucha gente que intenta hacerlo
Si GPT-5.6 Sol es sobrehumano no es una pregunta simple de sí o no. Las computadoras superan a los humanos en ajedrez desde hace décadas, y por este artículo parece que ahora también han superado a los humanos en comprensión de código