.:: Carlos Alberto Junior - Tecnologia e Informação ::.

Expressão regular para remover Iframe de arquivos PHP e HTML

Boa tarde a todos,

Tive alguns problemas de segurança referente à um script malicioso que fora executado e permitindo que em todos os arquivos (index.*) fosse adicionado uma tag IFRAME para fazer o carregamento de uma página de sei lá onde.

Bom, peço desculpas pelos usuários que tenham acessado a página na quinta-feira à noite e quero hoje compartilhar uma solução que utilizei além de dar algumas dicas de segurança para as configurações de um site.

Primeiramente, a permissão de escrita de um arquivo, é algo complicado nos servidores WEB, logo porque devem ser tomadas uma série de cuidados antes de deixar um diretório ou arquivo com permissão de escrita, logo porque qualquer furo de SCRIPT PHP (ou da linguagem do servidor) pode fazer com que todos os arquivos com permissão de escrita sejam alterados.

O recomendado é que nenhum diretório fique com permissão de escrita, assim como os seus arquivos, mas um diretório de imagens por exemplo pode ficar liberado, mas o arquivo INDEX desse diretório tem que ficar protegido, no caso sem permissão de escrita.

Quando se tem uma brecha de segurança em algum arquivo PHP por exemplo, o hacker/cracker pode fazer uma instrução que pode acabar com todo o servidor. Para isso é importante que todos os arquivos fiquem sem permissão de escrita.

Mas quando é tarde demais, e os arquivos do site, geralmente arquivos de índices do site (index.*) são os mais atacados, ou o atacante troca o conteúdo todo do arquivo por um determinado código ou ele inbute um trecho de códugo malicioso, no caso podem ser:

  • Iframes para forçar o download de algum arquivo;
  • Objects ou Embed para abrir propagandas e Flash;
  • Arquivos Javascripts, chamadas locais ou remotas;

Para resolver isso sem ter que ir alterar N milhões de arquivos PHP, HTML, etc. que tiveram um Iframe adicionado por exemplo, pode ser feita uma instrução recursiva para ler e alterar estes arquivos caso encontre uma determinada tag maliciosa.

Com a função PHP preg_match, é possível definir uma Expressão Regular para procurar dentro de um arquivo um determinado trecho, neste caso uma ou mais tags IFRAME.

'{(<iframe).*?(>).*?(<\/iframe>)}i'

Recomendo que seja utilizada a Expressão regular abaixo no caso de no seu site/código fonte a ser limpo, o mesmo faça o uso de IFRAMES para algum caso, upload em AJAX/IFRAME por exemplo.

'{(<iframe).*?src="http:.*?(>).*?(<\/iframe>)}i'

Para agilizar a leitura, vamos definir algumas extensões de arquivos que não precisam ser lidas, logo temos a seguinte Expressão regular:

"(jpg|jpeg|gif|bmp|png|zip|doc|docx|pdf|xml|exe|gz|tar|rar)";

Após que o arquivo seja lido, vamos "fechar" a escrita do mesmo, logo definimos uma variável com as permissões devidas para o arquivo.

$permissoes = 0755; (Estas permissões podem ser em modo string, por exemplo 'dr-x-x'...)

Agora a função que iremos fazer, utiliza uma classe para arquivos do PHP, no caso a RecursiveDirectoryIterator, que contém diversas informações sobre arquivos e diretórios pronta. Esta classe necessita que a sua execução esteja dentro de um laço protejido, ou seja, dentro de um TRY/CATCH.

function lista_arquivos_diretorio_recursivo($it, $permissoes = 0555, $extensoes_negadas)
{
$corrigidos = 0;
$ER_iframe = '{(<iframe).*?(>).*?(<\/iframe>)}i';
$modifica = false;
$string = null;
$fd = null;

while ($it->valid())
{
if($it->isDir() && !$it->isDot())
{
echo '<pre>Diretorio atual '.$it->current().'....................................</pre>';
if($it->hasChildren())
{
$bleh = $it->getChildren();
// Conta os próximos arquivos da iteração recursivamente.
$corrigidos += lista_arquivos_diretorio_recursivo($bleh, $permissoes, $extensoes_negadas);
}
}
elseif($it->isFile())
{
// Se tiver permissão faça os procedimentos necessários.
if($it->isReadable() && $it->isWritable())
{
if(!preg_match("/\.".$extensoes_negadas."$/i", $it->current()))
{
$string = null;
$fd = fopen($it->current(), "r+");
echo '<pre>Iniciando a leitura do conteúdo do arquivo '.$it->current().'..........................</pre>';
while($linha = fgets($fd))
{

if (preg_match($ER_iframe, $linha))
{
echo '<pre>Uma tag IFRAME encontrada no arquivo '.$it->current().'.............................</pre>';
$string .= preg_replace($ER_iframe, '', $linha);
$modifica = true;
} else
{
$string .= $linha;
}
}
echo '<pre>Salvando modificações no arquivo '.$it->current().'.................................</pre>';

if($modifica)
{
$corrigidos++;
// Vai voltar o ponteiro para o início
rewind($fd);
// Apagará todos as linhas
ftruncate($fd, 0);
// Vai reescrever o arquivo, com os iframes removidos
fwrite($fd, $string);
// Vai fechar o arquivo
fclose($fd);
}

$fd = null;
$string = null;
echo '<pre>Definindo o arquivo '.$it->current().' com permissões de leitura ('.$permissoes.').................................</pre>';
chmod ($it->current(), $permissoes);
}
else
{
echo '<pre>O arquivo '.$it->current().' não está na lista de Extensões de arquivos a serem verificados..........................</pre>';
}
}
else
{
echo '<pre>O arquivo '.$it->current().' não possui permissão de Leitura ou Escrita..........................</pre>';
}
}
// Vai para o próximo arquivo ou diretório.
$it->next();
}
return $corrigidos;
}

 

Feito isso, agora temos que fazer a chamada da nossa função, que segue no código abaixo:

try
{
// Caminho absoluto do diretório a ser lido.
$dir = "C:\\xampp\\htdocs\\carlosinf-17-09\\";
$permissoes = 0755;
$extensoes_negadas = "(jpg|jpeg|gif|bmp|png|zip|doc|docx|pdf|xml|exe|gz|tar|rar)";

echo '<pre>Iniciando leitura do diretório ('.$dir.')...............................</pre>';
$corrigidos = lista_arquivos_diretorio_recursivo(new RecursiveDirectoryIterator($dir), $permissoes, $extensoes_negadas);
echo '<pre>Leitura dos arquivos finalizada, foram corrigidos ('.$corrigidos.') arquivos(s).....................</pre>';
}
catch (Exception $e)
{
var_dump($e);
}

Lembre-se de definir o diretório que irá ser lido, recomendo que execute em um diretório por vez, para ter uma maior segurança e controle.

Ao andar da execução, a função irá imprimindo informações sobre a leitura e modificação dos arquivos.

Para fazer o download do código fonte clique no link abaixo:

http://www.carlos.inf.br/files/www.carlos.inf.br.remove-iframe.zip

Abraços e até a próxima.

Comentarios (4)

RSS feed Comments
Problema na execução
Carlos,
Parabéns pelo artigo
Ao executar no meu servidor, retorna o seguinte código, pode me ajudar ?

"Parse error: syntax error, unexpected '{' in /var/www/remove-frame.php on line 90"
Jésus R , maio 14, 2010
Parabéns
Parabéns Carlos, muito boa a solução smilies/smiley.gif
Wildeney Rigo , setembro 21, 2009
Alteração do artigo
Olá Cleber,
Modifiquei a expressão regular do artigo para apenas buscar as tags IFRAME que tenham um SRC externo ao site. No caso IFRAMES com SRC igual a '/dados/algum_caminho/exemplo.php' serão mantidos.
Carlos Alberto , setembro 21, 2009 | url
...
Nos sites que faço usando o Drupal, só fica um arquivo sem pemissão de escrita, o settings.php, que define as configurações do site (banco de dados, usuário etc.). Mas vou passar a me preocupar mais com essa parte das permissões, antes que eu tenha alguma surpresa desagradável.
Cleber , setembro 21, 2009 | url

Escreva seu Comentario

smaller | bigger

busy