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

Free lesson

Naming the common kinds of web vulnerability

After this lesson: I can match a vulnerable page to the flaw class it shows.

55 min lesson3 commandsMutillidae lab: practise SQL injection and XSS on a vulnerable PHP web application

Twelve findings, six names

A firm tests a client's website and writes up twelve findings. They look unrelated: an error page, a strange link, a file name in an address.

A good tester reads the list and sees six families. Each family has one cause and one fix. This lesson teaches you to sort findings into families.

The one rule

Warning

This lab is a website that is insecure on purpose. Attack your own private copy and nothing else. It has no way out to the internet. Never try these things on a site that is not yours: in the UK that is a crime under the Computer Misuse Act 1990.

By the end of this lesson

Note

I can match a vulnerable page to the flaw class it shows.

Key words

WordWhat it meansExample
Flaw classa family of weaknesses that share one cause
Injectiontyped text read as part of a command or query
Path traversala file name that climbs out of the folder it should stay in../
Open redirecta link that sends visitors to any address it is given
Inputanything a visitor types or sends to a page
Sinkthe place in a program where a value is finally used

The cells students fill in are left blank in this preview.

Follow the input to its sink

Most flaws share one pattern. A value comes in from a visitor. It travels through the program. It arrives at a sink, where it is used.

The class of flaw depends on the sink. Ask one question of any page: where does what I type end up?

Worked example: sink and class

Where the value ends upFlaw classThe fix in one line
Inside a database querySQL injectionSend it as a parameter
Inside the page the browser drawsCross-site scriptingEscape it on output
Inside a file name the server opensPath traversalAllow only names from a list
Inside a command the server runsCommand injectionNever build commands from text
Inside an address the visitor is sent toOpen redirectAllow only your own addresses
As an id with no owner checkBroken access controlCheck the owner every time

The cells students fill in are left blank in this preview.

Each class leaves a sign in a request

You can often tell the class from a single request. A file name with ../ in it points at path traversal. A tag in a value points at XSS. A redirect= value holding a full address points at an open redirect.

You do not need to run anything to classify. You read the request and ask what the value is for.

Worked example: five invented requests

RequestClass
/view?file=../../etc/hostsPath traversal
/greet?name=<i>Bo</i>Cross-site scripting
/go?redirect=http://other.exampleOpen redirect
/lookup?id=5 UNION SELECT 1SQL injection
/tools?host=a.example; cat notesCommand injection

The cells students fill in are left blank in this preview.

Look at the lab's website

Your lab runs Mutillidae, a website with many flaws on purpose. Start it, then run these three in order. The first signs in with the lab's own account and keeps the sign-in in a file. The second looks up that one account by its name and password. The third looks up a name the site does not hold. All three are ordinary use.

Sign in as the lab's own account

Command
curl -s -c jar -d "username=admin&password=adminpass&login-php-submit-button=Login" -o /dev/null -w "%{http_code} %{redirect_url}\n" "http://www/index.php?page=login.php"

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

Look up one account

Command
curl -s -b jar -c jar -G "http://www/index.php" --data-urlencode "page=user-info.php" --data-urlencode "username=admin" --data-urlencode "password=adminpass" --data-urlencode "user-info-php-submit-button=View Account Details" | grep -o "[0-9]* records found"

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

Look up a name that is not there

Command
curl -s -b jar -c jar -G "http://www/index.php" --data-urlencode "page=user-info.php" --data-urlencode "username=nobody" --data-urlencode "password=nothing" --data-urlencode "user-info-php-submit-button=View Account Details" | grep -o "[0-9]* records found"

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

What the three answers tell you

The first prints 302 and an address ending AU1, so the site accepted the sign-in. The second prints 1 records found. The third prints 0 records found.

So the page counts the rows its query returns. That makes it a sink: the name you type goes into a database query. Which class would you test it for? Check your answer against the table above.

A common mistake

Warning

Many people think one list of bad words can stop every class. It cannot. Each class has a different sink, so each needs the right fix at its own sink. A filter for script tags does nothing for a file name. Fix each sink the way its class needs.

One cause sits under most classes

Injection, XSS, traversal and the rest share one cause. A program mixes data with instructions, and the next layer cannot tell them apart.

The cure is the same idea each time. Keep data in its own lane: parameters, escaping, allowed lists. Mutillidae has security levels 0, 1 and 5, so you can see the same page with and without the cure.

Going further: a disguised traversal

An attacker can write each dot as %2e, so ../ becomes %2e%2e/. The rules in the assignment miss /view?file=%2e%2e/secret and call it normal.

Once your assignment passes, copy classify into a code block of your own. Add the one swap that catches it. Then explain why a real server decodes the whole address once, before any check.

About this lab and its source: Mutillidae lab: practise SQL injection and XSS on a vulnerable PHP web application

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.