O script do lado do cliente verifica a extensão do arquivo. Antes de enviar qualquer dado para o servidor, o script JavaScript no cliente verifica se a extansão do arquivo selecionado é permitida.
function validarArquivo() {
var arquivo = document.getElementsByName('arquivo_upload')[0].value;
if (arquivo == null || arquivo == "") {
alert("Selecione um arquivo para upload!");
return false;
}
// Definir as extensões permitidas
var extensoesPermitidas = ".jpg|.png|.gif";
// Extrair a extensão do arquivo
var extensao = arquivo.substring(arquivo.lastIndexOf("."));
// Verificar se a extensão do arquivo está na lista permitida
if (extensoesPermitidas.indexOf(extensao + "|") == -1) {
var mensagemErro = "Este tipo de arquivo não é permitido. Por favor, envie arquivos dos tipos: " + extensoesPermitidas + ". A extensão atual é: " + extensao;
alert(mensagemErro);
return false;
}
}
Segunda Etapa: Filtro de Content-Type no Servidor
O código do servidor verifica o Content-Type do arquivo enviado antes de processar o upload.
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($DIRETORIO_UPLOAD)) {
if (($_FILES['arquivo_upload']['type'] == 'image/jpeg') || ($_FILES['arquivo_upload']['type'] == 'image/png') || ($_FILES['arquivo_upload']['type'] == 'image/gif')) {
if (move_uploaded_file($_FILES['arquivo_upload']['tmp_name'], $DIRETORIO_UPLOAD . '/' . $_FILES['arquivo_upload']['name'])) {
$caminho_imagem = $DIRETORIO_UPLOAD . $_FILES['arquivo_upload']['name'];
$is_upload = true;
}
} else {
$msg = 'Tipo de arquivo inválido, tente novamente!';
}
} else {
$msg = $DIRETORIO_UPLOAD . ' diretório não existe, crie manualmente!';
}
}
Terceira Etapa: Bypass de Extensão
Alterar a extensão do arquivo para .phtml ou php2, php3 e fazer o upload.
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($DIRETORIO_UPLOAD)) {
$extensoesNegadas = array('.asp', '.aspx', '.php', '.jsp');
$nome_arquivo = trim($_FILES['arquivo_upload']['name']);
$nome_arquivo = removerPontoFinal($nome_arquivo); // Remover ponto final
$extensao_arquivo = strrchr($nome_arquivo, '.');
$extensao_arquivo = strtolower($extensao_arquivo); // Converter para minúsculo
$extensao_arquivo = str_ireplace('::$DATA', '', $extensao_arquivo); // Remover ::$DATA
$extensao_arquivo = trim($extensao_arquivo); // Remover espaços em branco
if (!in_array($extensao_arquivo, $extensoesNegadas)) {
if (move_uploaded_file($_FILES['arquivo_upload']['tmp_name'], $DIRETORIO_UPLOAD . '/' . $_FILES['arquivo_upload']['name'])) {
$caminho_imagem = $DIRETORIO_UPLOAD . '/' . $_FILES['arquivo_upload']['name'];
$is_upload = true;
}
} else {
$msg = 'Extensões .asp, .aspx, .php, .jsp não são permitidas!';
}
} else {
$msg = $DIRETORIO_UPLOAD . ' diretório não existe, crie manualmente!';
}
}
Exemplos de extensões comuns para bypass:
Asp: .asa, .cer, .cdx
Aspx: .ashx, .asmx, .ascx
Php: .php3, .phtml
Jsp: .jspx, .jspf
Em servidores Windows, a extensão pode ser alterada para **".php."**. Para listas de permissão, o método de truncamento 00 pode ser usado. Este método explora uma vulnerabilidade em versões anteriores do PHP (<5.3.4), onde 0x00 é tratado como um caractere de terminação. Exemplo: **1.php%00.jpg**.
Quarta Etapa: Uso de .htaccess para Bypass
Se a lista negra ainda permite o upload de .htaccess, você pode configurá-lo para tratar todos os arquivos como PHP, então fazer o upload de um "imagem maliciosa" que será interpretada como PHP.
Conteúdo do .htaccess:
SetHandler application/x-httpd-php
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($DIRETORIO_UPLOAD)) {
$extensoesNegadas = array(".php", ".php5", ".php4", ".php3", ".php2", "php1", ".html", ".htm", ".phtml", ".pHp", ".pHp5", ".pHp4", ".pHp3", ".pHp2", "pHp1", ".Html", ".Htm", ".pHtml", ".jsp", ".jspa", ".jspx", ".jsw", ".jsv", ".jspf", ".jtml", ".jSp", ".jSpx", ".jSpa", ".jSw", ".jSv", ".jSpf", ".jHtml", ".asp", ".aspx", ".asa", ".asax", ".ascx", ".ashx", ".asmx", ".cer", ".aSp", ".aSpx", ".aSa", ".aSax", ".aScx", ".aShx", ".aSmx", ".cEr", ".sWf", ".swf");
$nome_arquivo = trim($_FILES['arquivo_upload']['name']);
$nome_arquivo = removerPontoFinal($nome_arquivo); // Remover ponto final
$extensao_arquivo = strrchr($nome_arquivo, '.');
$extensao_arquivo = strtolower($extensao_arquivo); // Converter para minúsculo
$extensao_arquivo = str_ireplace('::$DATA', '', $extensao_arquivo); // Remover ::$DATA
$extensao_arquivo = trim($extensao_arquivo); // Remover espaços em branco
if (!in_array($extensao_arquivo, $extensoesNegadas)) {
if (move_uploaded_file($_FILES['arquivo_upload']['tmp_name'], $DIRETORIO_UPLOAD . '/' . $_FILES['arquivo_upload']['name'])) {
$caminho_imagem = $DIRETORIO_UPLOAD . $_FILES['arquivo_upload']['name'];
$is_upload = true;
}
} else {
$msg = 'Este arquivo não é permitido!';
}
} else {
$msg = $DIRETORIO_UPLOAD . ' diretório não existe, crie manualmente!';
}
}