SQLi in a Thick Client Authentication Endpoint
Thick client assessments surface vulnerabilities that web-only scoping misses. The application here was a Windows .NET desktop tool for card payments management — installed on teller workstations, communicating with a SQL Server backend over a REST API. The authentication form submitted a JSON body to the API. The API constructed a SQL query from the submitted username without parameterisation. A single-quote in the username field produced a 500 response with the full .NET exception detail in the response body, including the library name, query fragment, and SQL Server error message.
Single quote, full exception
Burp's Proxy intercepts HTTPS from the thick client after installing the CA certificate in the Windows cert store. The login request was found and a single-quote appended to the username value. The response was a 500 with verbose error detail from the SQL Server driver:
POST /api/auth/login HTTP/1.1
Host: payments.acme-lab.test
Content-Type: application/json
{"username":"lab_user'","password":"<lab-password>"}
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": "System.Data.SqlClient.SqlException",
"message": "Incorrect syntax near '\\''.",
"source": "AuthLib",
"detail": "Unclosed quotation mark after the character string '<lab-password>'.",
"stackTrace": "at System.Data.SqlClient.SqlConnection.OnError..."
}
# unparameterised query confirmed — username injected directly into SQL string
# exception reveals: library name, query context, and password value in error message
The error reveals the library name (AuthLib) and, in the
detail string, the plaintext password submitted in the request — the SQL query was
structured such that the password appears in the error output when the username injection
breaks the syntax. This means any exception logged server-side also contains cleartext
credentials.
The companion finding: cleartext credential storage in logs
The verbose error logging to the application server's log files means credentials submitted to the broken authentication endpoint are stored in plaintext in logs. The cleartext credential storage and the verbose error detail are companion findings from the same assessment.
The test timeline
Burp CA installed in Windows cert store. Thick client HTTPS traffic proxied. Authentication request identified — JSON body with username and password fields.
Single quote produces 500 with SqlException. System.Data.SqlClient.SqlException: Incorrect syntax near "'". Full stack trace, library name, and query context returned.
Plaintext password appears in SQL error detail. Query construction places password value in error context — any logged exception contains the submitted credential in cleartext.
Boolean-based injection confirmed. lab_user' AND 1=1-- vs lab_user' AND 1=2-- produce different responses. Authentication bypass and schema enumeration paths established.
Full injection chain documented. Authentication bypass PoC, error-logged credential path, and verbose error exposure all captured with evidence.
Fixing the injection
- Replace all string-concatenated SQL with parameterised queries or stored procedures. Every value from any external input — username, password, account ID — must be passed as a parameter, never interpolated into a query string. In .NET, this means
SqlCommandwithParameters.Add(). Search for all string concatenation adjacent to SQL strings in the codebase. - Move credentials from plain configuration to a secure credential store. Database connection strings and API keys stored in app.config or as plaintext environment variables should be replaced with a secrets manager (Azure Key Vault, Vault by HashiCorp, or Windows DPAPI-protected configuration).
- Disable verbose error responses in production. Set
customErrors mode="On"in web.config and configure a generic error handler that returns a reference ID without stack trace, query context, or internal class names. Log the full exception server-side with the reference ID for debugging. - Include thick clients in assessment scope explicitly. The .NET application had never been assessed — only the web portal sharing the same backend had been tested. Thick clients communicate with the same API endpoints and often bypass controls designed for the web flow.
The takeaway
A single-quote in the username field produced a 500, a stack trace, the password value in plaintext, and a confirmed injection point into the authentication query. The fix is one pattern change — parameterisation — applied consistently across the codebase.