
PoC para CVE-2026-73847 - Asistente de IA de emlog: CSRF a ejecución SQL y toma de control del administrador (CVSS 6.8)
PoC de la falta de protección CSRF en el endpoint execute_tool del Asistente de IA de emlog pro, que permite a un atacante aprovechar la sesión autenticada de un administrador para ejecutar SQL arbitrario contra la base de datos del sitio — incluida la toma de control total de una cuenta de administrador.
| CVE | CVE-2026-73847 |
| CNA | GitHub |
| Aviso | GHSA-v6wr-4x55-7qp5 |
| CVSS 3.1 | 6.8 Media — AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N |
| CWE | CWE-352 (CSRF), CWE-1275 (SameSite inadecuado), CWE-798 (Cadena de confirmación de escritura hardcodeada) |
| Afectado | emlog pro hasta 2.6.23 |
| Crédito | Dostxodjayev Abdullox (@squeeze440) — corrección pendiente en el registro CVE, ver más abajo |
El panel de administración de emlog pro incluye un asistente de IA que puede ejecutar SQL en nombre del administrador mediante POST /admin/ai.php?action=execute_tool. Varios problemas se acumulan en este único endpoint:
admin/ llaman a LoginAuth::checkToken() primero (p. ej. admin/media.php:140). admin/ai.php nunca lo hace.admin/ai.php:152, User::isAdmin()) — sin comprobación de Origin/Referer.include/service/ai.php:594: if (trim($confirm_code) !== 'confirm'). Cualquier solicitud falsificada simplemente envía confirm_code=confirm.include/service/ai.php:578,589) — una solicitud autenticada simple puede hacer SELECT de cualquier tabla.blog está protegida contra escritura (include/service/ai.php:591) — user y todas las demás tablas son totalmente escribibles.password (include/service/ai.php:822-828) — SELECT password AS pwd_hash FROM user devuelve el hash en bruto.SameSite (include/lib/loginauth.php:99), dejando la ventana de gracia "Lax+POST" predeterminada de Chrome (aproximadamente los primeros dos minutos después del inicio de sesión) como la única barrera entre esto y una entrega cross-site fiable.Encadenados: una sola solicitud falsificada desde el navegador de un administrador lee todas las tablas (incluidos los hash de contraseñas) y escribe en todas las tablas excepto blog, incluida la sobrescritura directa de user.password.
poc_raw_impact.sh)Aísla la primitiva de bypass de SQL/autenticación de la cuestión de la entrega CSRF. Ejecutar contra una instancia local que controles:
./poc_raw_impact.sh http://TARGET admin '<adminpass>'
Esto inicia sesión como admin, extrae los hash de contraseñas mediante el bypass de alias de columna, sobrescribe la contraseña del administrador directamente a través de la tabla user, y luego vuelve a iniciar sesión con la contraseña elegida por el atacante desde un almacén de cookies nuevo — demostrando la toma de control total de la cuenta una vez que una solicitud autenticada llega al endpoint.

poc_csrf.html)Resuelve la cuestión de SameSite con un navegador real en lugar de asumirlo. Sirve poc_csrf.html desde cualquier origen distinto al objetivo (una IP diferente es suficiente — Chrome trata IPs literales distintas como sitios separados) y consigue que un administrador con sesión iniciada lo abra dentro de aproximadamente dos minutos después de iniciar sesión:
python3 -m http.server 8888
# luego apunta la acción del formulario de poc_csrf.html a tu objetivo y haz que lo abran
El formulario se autoenvía al cargar, enviando una llamada falsificada query_database con confirm_code=confirm de forma cross-site.

Verificado en vivo: el POST cross-site falsificado llevaba la cookie de autenticación real del administrador (sec-fetch-site: cross-site, cookie adjunta), devolvió 200 {"code":0,"msg":"ok",...}, y la fila inyectada se confirmó presente mediante una lectura autenticada de seguimiento. Repetir la solicitud idéntica ~48 minutos después contra el mismo almacén de cookies, ahora envejecido, falló — no se adjuntó cookie y el servidor devolvió una redirección no autenticada, confirmando que la ventana Lax+POST de aproximadamente dos minutos es la restricción real (reflejada en AC:H).
emlog_options (credenciales SMTP, claves API, etc.).blog, incluida user — sobrescritura de rol/contraseña/correo, demostrada de extremo a extremo como toma de control de cuenta.role=admin; writer/editor están bloqueados por User::checkRolePermission(). No es escalada de privilegios desde un rol inferior — convierte un clic en un enlace malicioso por parte de un administrador con sesión iniciada en un compromiso total y silencioso del sitio.Añadir LoginAuth::checkToken() a execute_tool, establecer SameSite=Strict en la cookie de autenticación, y reemplazar la cadena estática confirm_code por un token real de sesión única y de un solo uso. Detalle completo de la remediación en el aviso.
Nota sobre el crédito: GitHub-como-CNA publicó el registro CVE sin una entrada credits, a pesar de que el propio GHSA acredita y acepta al reportante. Se envió una solicitud de corrección a [email protected] el 2026-08-16; este README se actualizará si se corrige el registro.
Publicado después de que el aviso fuera público y se asignara un CVE, para uso defensivo/educativo. No ejecutes esto contra una instancia de emlog que no poseas o para la que no tengas autorización explícita de pruebas.