The wikis are now using the new authentication system.
If you did not migrate your account yet, visit https://idp-portal-info.suse.com/

ARTIGOS:Retornando a lista de usuários de uma aplicação vulnerável usando o SQL Injection

Ir para: navegação, pesquisa

Descrição do problema

O ataque de Injeção de SQL (SQL Injection em inglês) é uma das principais vulnerabilidades das aplicações web segundo o OWASP Top 10 2017. Explorando essa vulnerabilidade, um usuário malicioso pode, por exemplo, ler dados sensíveis de uma aplicação, manipular informações e até executar operações administrativas no banco de dados.

O principal meio utilizado para este tipo de ataque é a entrada de dados que o usuário utiliza para enviar informações para a aplicação. Nele, comandos SQL são enviados como parâmetro da aplicação ou valores de campos de formulários para confundir a aplicação e fazer com que ela execute com sucesso os comandos enviados.

NOTA: O objetivo deste artigo está na transferência de conhecimento sobre o funcionamento do ataque SQL injection. O uso indevido do conteúdo deste artigo fica sobre a responsabilidade do leitor, isentando o autor de qualquer problema ou danos causados.

A seguir, vamos preparar um ambiente LAMP usando o openSUSE Leap 42.2 para realizar os testes de injeção SQL.

Instalando o Apache, o PHP e o mysql server no openSUSE Leap 42.2

Para preparar o ambiente, devemos instalar o apache, o módulo PHP e o mysql server usando o comando a seguir:

opensuse-test:~ # zypper in apache2 apache2-mod_php5 mysql-community-server php5-pear-MDB2_Driver_mysqli

Após a instalação dos pacotes, vamos preparar o banco de dados:

opensuse-test:~ # rcmysql start

opensuse-test:~ # mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.6.38 openSUSE package

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

mysql> CREATE DATABASE testdb;
Query OK, 1 row affected (0.00 sec)

mysql> USE testdb
Database changed

mysql> CREATE USER 'testm'@'localhost' IDENTIFIED BY 'passwdm';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON * . * TO 'testm'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> exit
Bye

opensuse-test:~ # mysql -u testm -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.6.38 openSUSE package

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use testdb
Database changed
mysql>

mysql> CREATE TABLE users (
    -> name     VARCHAR(30) NOT NULL PRIMARY KEY,
    -> password VARCHAR(30) NOT NULL
    -> );

Query OK, 0 rows affected (0.01 sec)

mysql> describe users;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| name     | varchar(30) | NO   | PRI | NULL    |       |
| password | varchar(30) | NO   |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+

2 rows in set (0.00 sec)

mysql> insert into testdb.users values('JOAO','123456');
Query OK, 1 row affected (0.00 sec)


mysql> insert into testdb.users values('JORGE','345678');
Query OK, 1 row affected (0.00 sec)

mysql> insert into testdb.users values('JOSE','234567');
Query OK, 1 row affected (0.00 sec)

mysql> select * from users;

+-------+----------+
| name  | password |
+-------+----------+
| JOAO  | 123456   |
| JORGE | 345678   |
| JOSE  | 234567   |
+-------+----------+

3 rows in set (0.00 sec)

Nesse ponto, devemos habilitar o módulo php no apache e iniciá-lo usando o comando a seguir:

opensuse-test:~ # a2enmod php5

opensuse-test:~ # rcapache2 start

Com o banco e o apache prontos, vamos criar uma página php que recebe como parâmetro o nome do usuário e retorna os dados cadastrados para o usuário informado:

opensuse-test:~ # vi /srv/www/htdocs/index.php

<?php
    //CONEXAO COM O BANCO DE DADOS
    $SERVERNAME = "localhost";
    $USERNAME   = "testm";
    $PASSWORD   = "passwdm";
    $DBNAME     = "testdb";
    
    $CONN = new mysqli($SERVERNAME, $USERNAME, $PASSWORD, $DBNAME);
    
    //ARMAZENA O PARAMETRO PASSADO
    $USER = "";
    
    if (isset($_GET["param"]))
    {
        $USER = $_GET["param"];
    }
    
    //MONTA A CONSULTA
    $SQL = "SELECT   name, password FROM users WHERE name = '" . $USER . "'";
    //EXECUTA
    $RESULT = $CONN->query($SQL);
    
    //APRESENTA O RESULTADO
    if ($RESULT->num_rows > 0)
    {
        while ($ROW = $RESULT->fetch_assoc())
        {
            echo "name: " . $ROW["name"] . " pass:" . $ROW["password"] . "<br>";
        }
    }
    else
        echo $USER . " nao esta cadastrado";
    
    $CONN->close();
    
?>


Iniciando os testes

Usando o browser, vamos tentar pesquisar os dados do usuário JOAO acessando a URL a seguir:

http://localhost/index.php?param=JOAO

Dados retornados:

name: JOAO pass:123456

Agora, vamos tentar pesquisar os dados do usuário CARLOS:

http://localhost/index.php?param=CARLOS

Dados retornados:

CARLOS nao esta cadastrado


Testando o SQL Injection

Para testar a injeção de SQL, vamos passar como parâmetro um trecho de comando SQL que mantenha a sintaxe correta e consiga retornar os dados desejados:

http://localhost/index.php?param= ' or 1=1 or '

Dados retornados:

name: JOAO pass:123456
name: JORGE pass:345678
name: JOSE pass:234567

Como o parâmetro informado pelo usuário está sendo concatenado numa string junto com o comando SQL, o parser não conseguirá diferenciar o código SQL do dado informado como parâmetro. Dessa forma, conseguimos manipular a aplicação para retornar os dados desejados. O comando SQL que foi executado ficou da seguinte forma:

SELECT name, password FROM users WHERE name = ' ' or 1=1 or ' ';

Agora que o ambiente está pronto, faça novos testes para entender de vez o funcionamento da injeção de SQL!

Referências

OWASP Top 10 2017. Disponível em: https://www.owasp.org/images/b/b0/OWASP_Top_10_2017_RC2_Final.pdf. Acesso em: 18 Dez. 2017.
OWASP SQL Injection. Disponível em: https://www.owasp.org/index.php/SQL_Injection. Acesso em: 18 Dez. 2017.
OWASP Code Review Guide. Disponível em: https://www.owasp.org/images/5/53/OWASP_Code_Review_Guide_v2.pdf. Acesso em: 18 Dez. 2017.

Autor: Fernando Galves (galves.fernando@gmail.com)
Publicado em 20 de Dezembro de 2017