An SQL injection consists of executing SQL statements on a database, statements that should not be allowed by the application in the first place. This is because the programmer did not take the necessary precautions to filter user input variables. In this way, a variety of results can be achieved, from finding out the database engine used to executing commands on the operating system itself. In this article, I will explain in a very simple way how to exploit a web vulnerability in an application designed for this purpose, so we will see with real code the functioning of this type of attacks.
Our web interface will serve as an access point to the company’s database that relates the code names of the agents with their real names and addresses. Therefore, a leak of information from this database can be catastrophic. The web will be composed of several files: header, footer, functions, and login.
The files in question are:
Header:
<!DOCTYPE html>
<html lang="es_ES">
<head>
<title>CIA ultra secret webpage</title>
<meta charset="utf-8">
<meta name="description" content="CIA ultra secret webpage">
<meta name="author" content="Kr0m">
<meta name="robots" content="all">
<meta name="cache" content="cache">
<style>
body { padding-top: 60px; }
</style>
<link href="/bootstrap/css/bootstrap.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
Footer:
</body>
</html>
Functions:
<?php
function conecta($host, $user, $pass, $db) {
$conexion = mysqli_connect($host, $user, $pass, $db) or die(mysqli_error($conexion));
return $conexion;
}
function consulta($id, $query){
$resultado = mysqli_query($id, $query) or die(mysqli_error($id));
return $resultado;
}
Login:
<?php
require("/var/www/ciaweb/cabecera.html");
require("/var/www/ciaweb/dbfunctions.php");
if (isset($_POST['username'])) {
$id_conexion = conecta('localhost', 'ciadb_user', 'XXXXXXXXXXXXXXXXX', 'ciadb');
$resultado = consulta($id_conexion, "SELECT * FROM usuarios WHERE nombre='$_POST[username]' && password='$_POST[password]'", $id_conexion);
$N = mysqli_num_rows($resultado);
if ($N >0){
$fila = mysqli_fetch_assoc($resultado);
$resultado = consulta($id_conexion, "SELECT * FROM noc", $id_conexion);
?>
<div class="well">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>ID</th>
<th>Nombre en clave</th>
<th>Nombre real</th>
<th>Domicilio</th>
<th style="width: 36px;"></th>
</tr>
</thead>
<tbody>
<?php
while ($fila = mysqli_fetch_assoc($resultado)) {
?>
<tr>
<td><?php echo $fila['id']?></td>
<td><?php echo $fila['nombre_en_clave']?></td>
<td><?php echo $fila['nombre_real']?></td>
<td><?php echo $fila['domicilio']?></td>
</tr>
<?php
}
} else {
?>
<section>
<div class="container login">
<div class="row ">
<div class="center span4 well">
<legend>Ultra secret Cia Database</legend>
<form method="POST" action="/login.php" accept-charset="UTF-8">
<input type="text" id="username" class="span4" name="username" placeholder="Nombre de usuario" />
<input type="password" id="password" class="span4" name="password" placeholder="Password" />
<button type="submit" name="submit" class="btn btn-primary btn-block">Sign in</button>
</form>
</div>
</div>
</div>
<p class="text-center muted ">Ultra secret Cia Database</p>
</section>
<?php
}
} else {
?>
<section>
<div class="container login">
<div class="row ">
<div class="center span4 well">
<legend>Ultra secret Cia Database</legend>
<form method="POST" action="/login.php" accept-charset="UTF-8">
<input type="text" id="username" class="span4" name="username" placeholder="Nombre de usuario" />
<input type="password" id="password" class="span4" name="password" placeholder="Password" />
<button type="submit" name="submit" class="btn btn-primary btn-block">Sign in</button>
</form>
</div>
</div>
</div>
<p class="text-center muted ">Ultra secret Cia Database</p>
</section>
<?php
}
require("/var/www/ciaweb/pie.html");
NOTE: To make the interface attractive, bootstrap has been used.
Now we create the database:
CREATE DATABASE ciadb DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE ciadb;
CREATE TABLE noc ( id int(11) NOT NULL, nombre_en_clave varchar(80) NOT NULL, nombre_real varchar(80) NOT NULL, domicilio varchar(80) NOT NULL);
CREATE TABLE usuarios ( id int(11) NOT NULL, nombre varchar(80) NOT NULL, password varchar(80) NOT NULL);
We insert users:
INSERT INTO usuarios (id, nombre, password) VALUES ('0','maxsnake','123');
INSERT INTO usuarios (id, nombre, password) VALUES ('1','lolman','321');
INSERT INTO noc (id, nombre_en_clave, nombre_real, domicilio) VALUES ('0', 'maxsnake', 'jhon', 'calle salamandra 123');
INSERT INTO noc (id, nombre_en_clave, nombre_real, domicilio) VALUES ('1', 'lolman', 'logic', 'calle margarita 321');
We assign permissions:
USE mysql
GRANT ALL PRIVILEGES ON ciadb.* to ciadb_user@'localhost' IDENTIFIED BY 'XXXXXXXXXXXXXXXXX';
FLUSH PRIVILEGES;
We configure the vhost as follows:
<VirtualHost *:80>
ServerAdmin kr0m@alfaexploit.com
DocumentRoot /var/www/ciaweb
ServerName www.ciaweb.com
SuexecUserGroup ABC DEF
ErrorLog /var/log/apache2/error_ciaweb.log
CustomLog /var/log/apache2/access_ciaweb.log combined
DirectoryIndex login.php
ScriptAlias /local-bin /var/www/cgi-bin/ABC
AddHandler application/x-httpd-php5 php
Action application/x-httpd-php5 /local-bin/php-cgi
<Directory "/var/www/cgi-bin/ABC">
Options -Indexes ExecCGI
Order allow,deny
Allow from all
</Directory>
<Directory "/var/www/ciaweb">
options -Indexes ExecCGI FollowSymLinks
AllowOverride All
order allow,deny
Allow from all
</Directory>
</VirtualHost>
Now we edit our hosts file so that
www.ciaweb.com
resolves to the IP of our server:
A.B.C.D www.ciaweb.com
To be able to see clearly what happens behind the scenes, we enable the MySQL log:
set global general_log='ON';
set global general_log_file='/var/run/mysqld/mysqld.log';
exit
We access the web from a browser and our app should appear:
http://www.ciaweb.com/
If we log in with any user, we can see the data of all agents:
Now we proceed with the injection:
What happened, but how is it possible if the code checks the user and password against the database?
As we can see, all the security of the application lies in:
$resultado = consulta($id_conexion, "SELECT * FROM usuarios WHERE nombre='$_POST[username]' && password='$_POST[password]'", $id_conexion);
$N = mysqli_num_rows($resultado);
if ($N >0){
The problem is that the user input is not parsed in any way, so it is possible to enter ’ or ‘1 = 1’; – as the user, which makes the select condition always true for all rows by means of 1 = 1. In this way, the select will offer as a result all the records of the table, thus fulfilling the requirement imposed by the N>0 code. Finally, the SQL query ends correctly and indicates that what comes after the ; are comments, so the query executed by the database would be as follows:
SELECT * FROM users WHERE name='' or '1 = 1'; -- ' && password=''
The code would check that the previous query actually returns results, leaving the agents exposed :)