User-controlled input $_REQUEST['id'] is concatenated directly into a SQL query with no sanitisation or parameterisation. Classic first-order SQL injection.
Exploitation
GET /vulnerabilities/sqli/?id=1' UNION SELECT user,password FROM users-- - dumps every password hash in the database. Boolean / time-based blind variants also work.
Impact
Full database compromise: user credentials, PII, application secrets. Attacker can pivot to authentication bypass and (via INTO OUTFILE on misconfigured MySQL) write a webshell for RCE.
Fix
Use mysqli_prepare with bound parameters. Never concatenate user input into SQL. Apply principle of least privilege to the DB user (no FILE permission).
Suggested Patch
$stmt = mysqli_prepare($conn, "SELECT first_name, last_name FROM users WHERE user_id = ?");
mysqli_stmt_bind_param($stmt, "i", $id);
mysqli_stmt_execute($stmt);
Attack Chains
Critical
Full Application Takeover via SQLi → Auth Bypass → RCE
Attacker uses union-based SQLi in /vulnerabilities/sqli/?id= to dump users table and password hashes
Cracks weak MD5 password hash for admin account (no salt, fast hash)
Logs into admin panel; session cookie lacks HttpOnly/Secure flags
Uses Command Injection in /vulnerabilities/exec/ to run arbitrary shell commands as web user
Writes PHP webshell to writable upload directory; obtains persistent RCE