There was a trivially exploitable SQL injection vulnerability wsdot.wa.gov, which hadn’t been fixed for over six months after reporting the issue to US-CERT under incident 2021-USCERTv347NNFM. Due to the PII it exposed about WSDOT contractors (appears to be the last four digits of SSN), I initially did not release full data about the vulnerable endpoint, only releasing some less-sensitive data publicly to urge WSDOT to apply a fix.

Through the tight-knit security community, a partial public disclosure helped get this information surfaced to the right people even through my small circle of college pals, former coworkers, and Twitter followers. All parties that assisted with this have elected to remain private, but I will say there were three of them in total, and I appreciate their unexpected and generous help throughout.

As of January 4th, this issue has been resolved, and I am releasing the remainder of this public disclosure. Thank you to WSDOT for resolving this so quickly, even after an exhausting December and fresh out of the holiday season.

Now, on to the fun stuff!

What was the vulnerability?

The vulnerability itself was a trivially exploitable SQL injection in WSDOT’s website. The manufacturer_id parameter (an integer) in an API present at https://www.wsdot.wa.gov/biz/mats/QPL/QPLLocations.cfm was vulnerable to SQL injection via inline querying. No fancy techniques needed - any “SQLi for beginners guide” would have been plenty - but for convenience I just used sqlmap to manipulate the endpoint automatically.

In theory, this could have been prevented by any common method of SQL injection prevention. In practice, it’s understandable why this wasn’t - the API is legacy software, where modern injection-prevention techniques were not implemented as defaults. Worse yet, leen observers will notice that the .cfm filetype indicates this is a ColdFusion application, where modern inkection-prevention techniques practically don’t seem to exist even in the most recent versions of ColdFusion.

Oddly, not all tables could be read via inline queries, and sqlmap would occasionally revert to time-based queries (which substantially increased the time required). I was unable to access schema information for other tables entirely. I decided not to pursue tables that I was struggling to access, as frankly, there was enough information here to make the decision to avoid complete public disclosure while this issue was live.

This is a ColdFusion problem, not a WSDOT problem.

To follow up on calling ColdFusion the “worse yet” factor in this vulnerability, initially upon reviewing this I was disappointed that such a trivial case was missed. After doing some research, I don’t blame WSDOT! While it might seem like a trivial case to manage - even casting the manufacturer_id to an integer before inserting it into a query - ColdFusion was designed in the 1990s and has not received the same security or usability care as other web languages or frameworks.

I don’t say that lightly or kindly.

ColdFusion expects users to manually sanitize each parameter in a query using special cfqueryparam (archived page) tags to sanitize data by type, and the most detail about injection attacks given by ColdFusion docs for this special tag are:

Adobe recommends that you use the cfqueryparam tag within every cfquery tag, to help secure your databases from unauthorized users. For more information, see Accessing and Retrieving Data in Developing ColdFusion Applications.

That link leads to a sparse directory, with one relevant article titled “retrieving data.” This article covers the cfquery tag (archived page)- used to actually begin and execute SQL queries - has not even a single reference to injection attacks or even the fucking cfqueryparam tag that you’d need to use to prevent it! The only passable resources for mitigating SQLi in ColdFusion are outdated StackOverflow threads with a bunch of dead links and mostly-complete answers. That’s unacceptable.

WSDOT confirmed they are working on moving away from ColdFusion and I hope this has lent some urgency to that.

What was the impact of this vulnerability?

Whilt it was active, this vulnerability granted substantial but non-administrative access to a database, which is used for the WSDOT website, permit registration and management using eSNOOPI, internal material management and test logs, ferry bulletins and schedules, some things to do with MATLAB, and more.

The database itself ran Microsoft SQL Server 2016 (SP3) (KB5003279) on Windows Server 2016 standard, and its hostname was “HQOLYMSQLHA01P” which seems to imply that it’s the primary SQL server in a HA pair. The user that was being manipulated is named “webserver” and does not have administrative permissions to the database server. While I confirmed that arbitrary data could be read, I did not check for write permissions or access to the filesystem. Given that there is only one other user visible - “sa” (the administrator) - it seems likely that the “webserver” user could have write permissions, but I’d expect (or hope?) it doesn’t have filesystem access.

As you might imagine from ferry bulletins or concrete sample logs, a lot of this data is pretty boring, but there’s some data which is more sensitive, and yet other data which should have never been accessible to the webserver user. I poked through the database manually so this is definitely not a complete list, but I was able to find:

  • 829 plaintext passwords - these seem to be mostly outdated or internal (ex. from various MATLAB-related tables). Perennial favorites include wsdot, wsdot123, wsdot1234, and wsdot[year] (as well as all-caps versions of these).
  • 72,949 user records used for web-based vehicle permit management. This included full name, email, and hashed passwords (SHA256 with a 256-bit salt, hashcat mode 1440: sha256($salt.utf16le($pass))).

Most concerningly to me, there are 4,659 records with four digits in a column titled social_security_num. While I have no way to validate this, it seems to be the last four digits of SSNs. These are in database CCIS, table Trainee, which based on the helpful WSDOT acronyms list is probably the database for the Construction Contract Information System. These records are current to 2021, but stretch back as far as 1986 - so I was concerned these may be the last 4 SSN of every contractor hired by WSDOT CCIS.

This increased the impact of publicly disclosing this, and even though there didn’t appear to be total SSNs, I was worried that fraud would be committed against innocent people using this information (ex. bank account takeover). This is the primary reason why I went for a partial disclosure first, but am now publicly disclosing because the issue has been resolved.

There were other potentially-sensitive tables I was not able to check as well. For example, the WebFerries database had tables which appeared to be related to credit card transactions, but I was not able to enumerate this table with sqlmap.

Why did you publicly disclose this vulnerability?

I didn’t feel like I had good options to pursue this further privately. Neither the state of Washington nor the specific impacted branch of WA has a vulnerability disclosure policy which I could find - both when disclosing privately, and checking again while writing this public disclosure.

Therefore, I made this disclosure to US-CERT (incident 2021-USCERTv347NNFM), and included all necessary information to understand and replicate the issue - even including complete sqlmap commands and what I knew at the time about the data present in this database. There has been no followup on that case. Due to the lack of options available to me, I even used some favors through my network to see if this could be actioned without public notification. Nada.

Since there had been no action in a beyond-reasonable timeframe, and this issue is trivial enough to find and exploit, keeping quiet about this forever would just allow an attacker to find and abuse it. This was the last option I believe I have to get this resolved.

This is a suboptimal experience and highlights every single component referenced in the background of BOD 20-01 describing why federal agencies must publish a VDP:

  • The reporter cannot determine how to report: As the reporter, I needed to lean on an industry contact to verify that US-CERT (albeit suboptimal) is where my report should go.
  • The reporter has no confidence the vulnerability is being fixed: Even having contacted US-CERT which should have been equipped to communicate this out to WA and communicate back to me as the reporter, I have received no confirmation that this was received, much less worked on. Given the lack of VDP I have no other good options that I’m aware of to follow up on this issue.
  • The reporter is afraid of legal action: The United States government’s history of cudgeling people with the CFAA, with notable high-profile cases even during my adolescent years, makes me uncomfortable even while trying to do the right thing in disclosing this.

While I’m glad that the federal government is making major steps forward due to BOD 20-01, and we can watch federal civilian executive branch agencies fulfill their obligation to start a VDP on CISA’s GitHub, there is no similar mandate that I can find at a state level. While some states or departments therein (such as Iowa - nice job Iowa!) have a VDP, progress at a state level on this particular front seems like it will be piecemeal.

How did you find this vulnerability?

I didn’t! It was reported to me, and I reported it to WSDOT as a proxy, because the orignal person who discovered the issue was that concerned about legal action (for this vulnerability and others that we privately disclosed together).

I’m weighing whether to write more about this while preserving their anonymity because, frankly, it was a unique situation to be put into. I am very privileged to have the financial resources and professional connections that I do which help insulate me from risk when disclosing issues. All it takes is one moron in power to make someone’s life hell with any state or federal law they can. If they don’t have the resources to fight back, what happens?

While I’m glad I could step up to help get this issue fixed, I have to reiterate that without someone acting as a shield here, this issue wouldn’t have been disclosed or fixed on the same timeline. Maybe it wouldn’t have ever been fixed! That’s a definite problem for InfoSec as a whole (but especially in possibly-hostile verticals such as government, law, etc.) and it’s one that we’ll be struggling to assess the impact of for years.

How did partial public disclosure help resolve this issue?

After publicly disclosing and posting on Twitter, my network was able to make some connections to the right people. A pal from college pinged another pal from college working for New York State, who was able to get this surfaced to a similar branch in Washington State (even while they were on vacation - legend). Twitter Verified contacts reached out to WSDOT’s Twitter staff. Friends and acquaintances lent me likes and retweets to help more people see this and make more connections.

In under 12 hours, this page got hits from WSDOT IPv4 addresses. Within a couple days, security staff from WSDOT and I were chatting about the issue. Why the second delay? That was on me - their LinkedIn message had gone to my spam folder. :/

While I do wish the process had worked here without relying on networking (and I’d love to hear from US-CERT/CISA why it didn’t, so I can improve in the future!) I am still glad that the tight-knit InfoSec community was able to come together in a little way to leverage our networks and personal reputation when getting this surfaced to the right people. Despite occasionally getting caught up in the InfoSec Twitter beef, it is wonderful to be reminded that there are so many excellent people who are in this field to help, not to clout-chase.

What are the key takeaways from this?

For anyone managing ColdFusion applications, you and I probably already knew that ColdFusion wasn’t setting the gold standard in security, but I’d go far enough to suggest that you should assume by default that ColdFusion applications in 2021 have trivial injection vulnerabilities. Unless you taught every developer anti-SQLi in ColdFusion and wrote a tool to enforce use of cfqueryparam tags on every new commit, I’d bet you are exposed to more risk right now than you originally thought. This should encourage one of:

  1. Migrating away from ColdFusion (honestly, strongly recommended), or
  2. If you can’t migrate away, insulate ColdFusion applications and their dependencies from any/all sensitive data, or
  3. If you can’t isolate sensitive resources, allocate resources to do a thorough pentest/audit/etc. of any ColdFusion applications you run.

For policymakers, this opened my eyes to how state governments could be falling behind the federal government in cybersecurity practices, and therefore increasing risk exposure for their constituents. This case highlighted that states really need VDPs - possibly even VDPs with safe harbor clauses, such as those advocated for by disclose.io - but these are a small part of a broder cybersecurity strategy shift that will need to happen at a state level. Funding from H.R.3684 should help move this needle, but I’m still concerned that no bar is being set or raised that all states must attain.

Then again, I’m just some cybersecurity goon on the internet, and not a public policy expert. Maybe just stick to my ColdFusion recommendations :)

Disclosure Timeline

  • June 18-19 2021 - Vulnerability disclosed to me by external party. Started search for way to disclose this vulnerability, relying on Google and industry contacts.
  • June 20, 2021 - Filed 2021-USCERTv347NNFM with US-CERT.
  • Interim - No response from US-CERT and no option to update an incident with more details that I could find.
  • December 1-28 2021 - Preparing for public disclosure via assessing the exposed data and authoring this disclosure.
  • December 29, 2021 - Partial public disclosure (archived here) posted, then Tweeted to see if my network can help drive this. My network quickly reaches an engineer who can help surface this to the right people, and I see hits on this writeup from Washington State owned IPv4 addresses (ref).
  • January 1, 2022 - Made a minor contextual update to disclosure. Found a LinkedIn message sent to spam, which shouldn’t have been sent to spam, which was sent on December 29th from a WSDOT engineer. Confirmed receipt at 11:51pm EST.
  • January 2, 2022 - Sent email to my contact’s WSDOT email address at 12:17am EST with full details about the vulnerability (as a precaution against an unlikely phishing attack via LinkedIn, but still).
  • January 4, 2022 - WSDOT replies to my email confirming that they sent the information off to the development team, as well as confirming a couple suspicions I had. By the time I sit down to write a reply, the vulnerability has been resolved.
  • January 5, 2022 - Full public disclosure published.

I would like to commend the work of WSDOT engineers to escalate and resolve this issue quickly, even during the holiday season, to help protect the people of Washington. Thank you.