Image Upload Gone Wild: Blind SQLi to Superadmin in Disguise
Published: November 20, 2024
๐ง TL;DR
"It's just an image upload form. What's the worst that could happen?"
Turns out: quite a lot. Blind SQL injection through the filename of an uploaded image led to a stored update, which allowed me to take over a superadmin account and exfiltrate DB metadata via a second endpoint.
๐ฏ Discovery: Where Curiosity Kicked In
I started by fuzzing the image upload endpoints and watching how the server used the filename parameter.
Observed request (multipart/form-data; filename param):

Request capture showing the filename field inside multipart form-data.
Initial payload attempts and basic variations exposed interesting server behavior (the app tried to treat the filename as SQL-relevant in some DB update flow):

A selection of initial attempts โ typical filename-based injection strings.
๐ First Barrier: Forced .jpg Extension
The server appended .jpg to filenames, which initially broke naive payloads (they became syntactically invalid in the constructed SQL statements).
Example of how the forced extension caused malformed SQL:

Server response showing the constructed SQL and how the appended .jpg affected parsing.
๐ง Round Two: Bypass the Extension with SQL Functions
The workaround was to use SQL functions: concat() and char() to reconstruct dots and email addresses so the appended .jpg didn't break the payload logic.
Filename-based SQL injection example (using char(46) to insert dots):

Screenshot showing the filename field containing concat/char constructs to bypass forced .jpg behavior.
๐ฃ Payload Mechanics (what I injected)
The final payload pattern closed the original SQL literal, injected an UPDATE that set the target user's email / fname, and commented out the rest. Example (conceptual):
Rocky', email=concat('dilip',char(46),'prasad@'security,char(46),'io'), fname='dilip' where email=concat('fapatrick1230@gmail',char(46),'com')#Below is a request snapshot of the crafted payload being sent in the filename parameter and the server response reflecting the UPDATE action.

Same capture shown again for emphasis on the actual SQL UPDATE call constructed server-side.
๐ Adding Account Attempts & Interesting Server Responses
Some attempts caused server-side errors or redirects โ those responses helped refine where the DB update was happening and what fields were affected.

Response capture showing a server error/redirect after a particular filename payload.
๐ฃ Step into Superadmin Shoes (post-exploit)
After I successfully updated the target user's email to one I control, I authenticated and found the account had escalated privileges.

Profile page showing the compromised superadmin account details.
Full admin interface and user management were accessible:

Superadmin dashboard & user list demonstrating privileges obtained.
๐ Second-Order Injection & Data Exfiltration
I then planted a value (e.g. (select @@version)) into a field and retrieved it via another endpoint โ classic second-order SQLi.

Endpoint response showing DB/server metadata leaked back (version etc.).
๐จ Impact Summary
- โ Superadmin account takeover via filename-based stored SQL UPDATE
- โ Second-order injection allowed metadata exfiltration (DB version, server info)
- โ Persistent risk โ uploaded filenames are stored and used by other flows
๐ ๏ธ Tools & Skills
Burp Suite for capturing requests, careful SQL function composition (concat/char) to bypass forced extension, and logic-driven testing to discover second-order sinks.
๐ Recommendations
๐ Use parameterized queries for all DB operations (including filenames)
๐งน Sanitize & normalize filenames on server-side
๐ Audit all places that consume uploaded filenames (second-order sinks)
๐ Final Thoughts
This exploit is a reminder that even seemingly harmless metadata โ filenames โ can become powerful attack vectors when they cross application logic boundaries.