Esta web utiliza cookies, puedes ver nuestra política de cookies, aquí Si continuas navegando estás aceptándola

Introducción a las inyecciones SQL


Nuestra interfaz web servirá como punto de acceso a la base datos de la cia que relaciona los nombre en clave de los agentes con sus nombres reales y sus domicilios por lo tanto una fuga de información de esta base de datos puede ser catastrófica, la web la compondrán varios ficheros, cabecera, pie, funciones y login.

 

Los ficheros en cuestión son.

Cabecera:

vi /var/www/ciaweb/cabecera.html
<!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>

 

Pie:

vi /var/www/ciaweb/pie.html
  </body>
</html>

 

Funciones:

vi /var/www/ciaweb/dbfunctions.php
<?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:

vi /var/www/ciaweb/login.php
<?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");

NOTA: Para darle atractivo a la interfaz se ha utilizado bootstrap.

 

Con esto ya tenemos la parte web, ahora creamos la base de datos:

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, role varchar(80) NOT NULL);

 

Insertamos agentes y usuarios:

INSERT INTO usuarios (id, nombre, password, role) VALUES ('1','maxsnake','123','agent');
INSERT INTO usuarios (id, nombre, password, role) VALUES ('2','lolman','321','agent');
INSERT INTO usuarios (id, nombre, password, role) VALUES ('0','admin','alfaexploit','admin');
INSERT INTO usuarios (id, nombre, password, role) VALUES ('1','maxsnake','123','agente');
INSERT INTO usuarios (id, nombre, password, role) VALUES ('2','lolman','321','agente');

 

Asignamos permisos:

USE mysql
GRANT ALL PRIVILEGES ON ciadb.* to [email protected]'localhost' IDENTIFIED BY 'XXXXXXXXXXXXXXXXX';
FLUSH PRIVILEGES;

 

Configuramos el vhost tal que así:

<VirtualHost *:80>
        ServerAdmin [email protected]
        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>

 

Ahora editamos nuestro fichero de hosts para que www.ciaweb.com resuelva a la ip de nuestro servidor:

vi /etc/hosts
A.B.C.D     www.ciaweb.com

 

Para poder ver con claridad lo que ocurre entre bambalinas habilitamos el log de MySQL:

set global general_log='ON';
set global general_log_file='/var/run/mysqld/mysqld.log';
exit

 

tail -f /var/run/mysqld/mysqld.log

 

Accedemos a la web desde  un navegador y debería de aparecer nuestra app:

http://www.ciaweb.com/

 

 

 

 

 

 

 

 

Si hacemos login con el usuario admin podemos ver los datos de todos los agentes:

 

 

 

 

 

 

En cambio si realizamos el login con uno de los agentes solo puede consultar sus propios datos:

 

 

 

 

 

Ahora procedemos con la inyección:

 

Que ha ocurrido, pero como es posible si en el código se comprueba el usuario y password contra la base de datos?

Como podemos ver toda la seguridad de la aplicación radica en:

$resultado = consulta($id_conexion, "SELECT * FROM usuarios WHERE nombre='$_POST[username]' && password='$_POST[password]'", $id_conexion);
    $N = mysqli_num_rows($resultado);
    if ($N >0){

 

El problema está en que no se parsea de ningún modo la entrada del usuario pudiendo introducir como usuario ' or '1 = 1'; --  lo que está haciendo es hacer que la condición del select sea siempre verdadera para todas las filas mediante el 1 = 1, de este modo el select ofrecerá como resultado todos los registros de la tabla, cumpliendo así el requisito impuesto por código de N>0 , finalmente termina la query sql de forma correcta e indica que lo que hay después del ; son comentarios, de este modo la query ejecutada por la base de datos quedaría así:

SELECT * FROM usuarios WHERE nombre='' or '1 = 1'; -- ' && password=''

 

En el código se comprobaría que efectivamente la query anterior devuelve resultados dejando a los agentes al descubierto :)


Autor: Kr0m -- 04/11/2014 23:11:53