Learn by Directing AI
Unit 5

Fix and Harden

Step 1: Read the Remediation Guidance

Open materials/remediation-guidance.md. This document describes the SQL injection vulnerability you confirmed in Unit 3 and the approach for fixing it. The fix targets the PHP code that builds database queries from user input — the same code path sqlmap exploited.

Read it carefully, but understand what it is: guidance, not a script. It tells you what needs to change and why. The actual implementation — modifying the PHP code in the DVWA container — is work you will direct Claude to do.

This is a perspective shift. You exploited this vulnerability two units ago. You saw it in the defender's logs. Now you are fixing it, using what you learned from both sides. The person directing the fix knows what the attack looks like, what it extracts, and what log pattern it leaves behind. That knowledge informs whether the fix is adequate.

Step 2: Direct Claude to Fix the Vulnerability

Direct Claude to fix the SQL injection vulnerability in the DVWA booking page based on the remediation guidance:

Read materials/remediation-guidance.md. Fix the SQL injection vulnerability in the DVWA PHP code that handles the booking search parameter. The fix should prevent the injection I confirmed with sqlmap earlier. Show me the code change you made.

Claude will make a change and report back. Do not assume the fix is correct because Claude says it is.

Step 3: Re-test with sqlmap

Run the same sqlmap command that succeeded in Unit 3. The exact same target URL, the exact same parameter. This is not a new test — it is the same test, and the expected result has changed.

Run the same sqlmap command we used in Unit 3 against the booking search parameter. I want to see if the SQL injection still works after the fix.

If sqlmap reports that the parameter is still injectable, the fix failed. This is not unusual. Claude's default fix for SQL injection is often mysqli_real_escape_string() — a function that escapes special characters in user input before passing it to the query. It looks like a fix. It addresses the symptom. But for numeric injection points, the escape function is bypassable because the injection does not require special characters that would be escaped.

The category of risk to watch for with AI-generated fixes: the convenient solution rather than the correct one. AI reaches for what appears most often in its training data, not what is most appropriate for the specific vulnerability. The re-test catches this. Your coding knowledge does not need to catch it. The tool that proved the vulnerability is the same tool that proves whether the fix works.

Step 4: Apply the Correct Fix

If sqlmap still succeeded, the fix is insufficient. Direct Claude to replace the approach with a prepared statement using mysqli_prepare():

The sqlmap re-test shows the injection still works. The escape-based fix is not sufficient. Implement a prepared statement using mysqli_prepare() instead — parameterize the user input so it is never interpreted as SQL. Show me the updated code.

Re-run sqlmap again. This time, the injection should fail.

That output — sqlmap reporting that the parameter is not injectable — is the verification. Not Claude's confirmation. Not the code looking correct. The same tool that proved the vulnerability now proves the fix. The evidence that breaks the finding is the evidence that validates the remediation.

Step 5: Verify the Application Still Works

A fix that breaks the application is not a fix. Direct Claude to verify that the DVWA booking form still functions normally after the prepared statement change:

Test the DVWA booking form with a normal search query — a legitimate guest name or booking reference. Make sure the form still returns results correctly after the SQL injection fix.

The prepared statement separates user input from SQL structure, but the query itself still needs to work. If Claude's prepared statement has a binding error or the parameterized query returns no results for legitimate input, the fix is functionally broken. The booking page needs to serve Jean-Marc's guests. A vulnerability fix that stops the booking system from working gives him a different problem, not a solved one.

Step 6: Apply the Hardening Checklist

Open materials/hardening-checklist.md. This is different from remediation. Remediation responded to a specific finding — the SQL injection you exploited and fixed. Hardening responds to a baseline — a set of configuration standards that apply regardless of whether anyone found a specific vulnerability.

The checklist includes items like closing ports, disabling defaults, and verifying permissions. Closing a port means blocking network access to a service -- if port 3306 (MySQL) is open, anyone on the network can try to connect directly to the database. Disabling default credentials means replacing the factory-set usernames and passwords that ship with the software -- attackers try these first because they're publicly documented. Verifying permissions means checking that each service runs with only the access it needs, so a compromised service cannot reach beyond its own scope. Direct Claude to work through each item:

Read materials/hardening-checklist.md. Apply each hardening item to the DVWA environment. For each change, tell me what you changed and why it reduces risk. Start with closing the exposed MySQL port and disabling default credentials.

The checklist encodes decisions someone already made about what "secure enough" looks like. Following it without understanding produces a system you cannot explain. For each item Claude applies, make sure you understand the rationale. Why is an exposed MySQL port a problem? Because anyone on the network can attempt to connect directly to the database — bypassing the web application entirely. Port 80 stays open because the booking page needs it. Port 3306 closes because no external user needs direct database access.

A service running as root can do anything once compromised. Restricting the database user's permissions limits what an attacker gains even if they find another way in. Least privilege is not a checklist item to tick off. It is a design principle — every permission that is not required is a permission that could be exploited.

Step 7: Verify the Hardening

Run Nmap again against the same target. Compare the results with what you saw in Unit 2.

Run the same Nmap scan we used in Unit 2 against the DVWA target. I want to compare the results with the earlier scan to verify the hardening changes took effect — specifically that port 3306 is no longer exposed.

The before-and-after comparison is the proof. Port 80 should still be open — the booking page is running. Port 3306 should be closed or filtered — the MySQL port is no longer exposed to the network. If port 3306 is still showing as open, the hardening did not work. Claude may have modified a configuration file without restarting the service, or the firewall rule may not have applied. Do not accept Claude's report that the port is closed. The Nmap scan is the verification.

Document what was hardened and why. A change log that says "closed port 3306" is a configuration record. A change log that says "closed port 3306 because external MySQL access allows direct database connection bypassing application-layer controls" is a security communication. Jean-Marc's next developer — whoever maintains this system after you — needs to understand the rationale, not just the action.


✓ Check

Check: sqlmap fails after fix. Port 3306 closed after hardening. DVWA still functions.