What you will do
SQL injection is what happens when a program builds a database question by pasting what a visitor typed into the text of the question. The visitor can then end the question early and write their own. You will search a small shop, make its search page hand over things it should not, fix the one line of code that allows it, and show the attack no longer works.
The one rule
Warning
This lab runs a website that is insecure on purpose. Attack it, and nothing else. It is your own private copy with no way out to the internet, so nobody else can be affected. Never try these things on a site that is not yours: in the UK that is a crime under the Computer Misuse Act 1990.
Before you start
Note
Press Start the lab on the bar at the top of this lesson and wait until it says it is running. The shop is the service called app, and the terminal reaches it by that name. Each Run button below types its command into your lab's terminal, one after another in the same session. To watch them, or to type your own, press Open terminal on the bar.
1. Search the shop
The shop's search is a web address. curl -s asks for it, and -G --data-urlencode puts what you search for after the address with any quotes and spaces made safe. Searching for pen prints one line, Pen 1.2: the name and the price.
curl -s -G --data-urlencode "q=pen" http://app:8000/searchShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
2. Break out of the question
Inside the program your search is pasted between two quote marks. A quote mark in your search ends them early, OR 1=1 is true for every row, and -- makes the rest of the question a comment. The shop lists seven products, including Staff discount card and Unreleased drone, which are not for sale and should never be shown. The same trick with UNION SELECT can ask for another table altogether. Try that yourself: the shop has a users table.
curl -s -G --data-urlencode "q=x' OR 1=1 --" http://app:8000/searchShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
3. Fix the line
The program is in the container, and the weak line is the one that starts rows =. It joins your search into the question with +. A parameterised query sends the question and your search to the database separately, so what you typed can only ever be a value and never part of the question. The ? marks where the value goes, and the search is passed beside it. To do it by hand, open the program with docker exec -it app vi /tmp/app/app.py and replace that line (i to type, Esc then :wq to save). The next command makes the same change for you, with this line:
rows = db.execute("SELECT name, price FROM products WHERE public = 1 AND name LIKE ?", ("%" + term + "%",)).fetchall()
4. Make the change and restart
This replaces that one line. The shop reads its program once when it starts, so docker restart runs the new version. It takes about ten seconds and then prints app: if its box says it is still running, wait for app in the terminal before you go on.
docker exec app sed -i 's|^ rows = .*| rows = db.execute("SELECT name, price FROM products WHERE public = 1 AND name LIKE ?", ("%" + term + "%",)).fetchall()|' /tmp/app/app.pyShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
docker restart appShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
5. Attack it again
The same attack as step 2 now prints nothing at all: the database looked for a product whose name contains the whole of x' OR 1=1 --, and there is none.
curl -s -G --data-urlencode "q=x' OR 1=1 --" http://app:8000/searchShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
6. Check normal use still works
A fix that breaks the shop is not a fix. lab-check tries a normal search, a search for Baker's (a product with a quote mark in its name, which made the weak program fail with a database error), the OR and the UNION, and prints PASS or FAIL for each. All four say PASS and the last line is All checks pass. Press Stop the lab and then Start the lab on the lab bar and run it again: your fix is still there, because the program lives in a named volume and the platform saves volumes.
docker exec app sh /tmp/app/lab-checkShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
For teachers
Tip
This lesson is a small example of a lesson worked in a lab: the steps and the Run buttons are the lesson, and the lab is each student's own copy. Nothing here marks itself: the student hands in the attack before and after, the last lab-check and the line they changed with their own sentence on why it is safe, and you mark the evidence. Copy it into your own module and change it, or build one from scratch with the Lab menu in the lesson builder.