Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

SQL Injection Fix Basics

The whole lesson is here to read. Create a free account to run it in a live lab.

Container lab8 min read6 commands

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.

Command
curl -s -G --data-urlencode "q=pen" http://app:8000/search

Shown 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.

Command
curl -s -G --data-urlencode "q=x' OR 1=1 --" http://app:8000/search

Shown 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.

Command
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.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Command
docker restart app

Shown 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.

Command
curl -s -G --data-urlencode "q=x' OR 1=1 --" http://app:8000/search

Shown 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.

Command
docker exec app sh /tmp/app/lab-check

Shown 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.

About this lab and its source: SQL injection lab: attack a weak shop search, fix the query and prove the fix

Teaching a class? Set these lessons for your students with marking and a lab for every student.