Limpeza de explorações PHP de arquivos infectados usando sed

1

Recentemente, meu servidor foi alvo de uma série de ataques de exploração do php e, ao usar o ClamAV, consegui identificar muitos arquivos infectados.

A pegadinha aqui é que existem arquivos legítimos que estão infectados junto com alguns que são códigos totalmente maliciosos.

Felizmente, os arquivos infectados estão no seguinte formato:

<?php //malicious code ?>
<?php //legitimate part ?>

Então, eu poderia usar sed para remover apenas a primeira ocorrência da tag php. Dessa forma, o código legítimo permanece intacto e a parte maliciosa é excluída.

Para isso, usei o seguinte comando:

sed 's/<?php.*?>//' file.php

Isso tem dois problemas:

  1. Substitui todas as ocorrências em vez da primeira
  2. Falha para ocorrências de várias linhas

Eu usei muitas formas, mas elas falharam em algum momento.

sed '0,/<?php.*?>/{s/<?php.*?>//}' //this has also failed

Então, pensei que talvez vocês pudessem me dar uma dica de como fazer esse comando sed funcionar ou sugerir uma ferramenta melhor para a tarefa em questão.

    
por Hamed Momeni 30.09.2015 / 08:27

2 respostas

1

Desculpe por usar a expressão perl oneliner em vez de sed, mas de alguma forma eu não consigo aprender / lembrar o regex de sed. Então você pode tentar isso:

  $ cat somefile.php | tr '\n' '@@@' | perl -p -e 's/^(.*?)(<\?php.*?\?>)(.*$)/$1$3/' | tr '@@@' '\n' > somefile_1.php

Primeiro tr é para alterar string de múltiplas linhas na string oneline. A string ' @@@ ' é apenas um exemplo, pode ser qualquer string que não exista em nenhum arquivo que você queira editar (grep-lo primeiro apenas para ter certeza). Em seguida, o comando perl está fazendo o trabalho real: usando grupos regex é spliting string em três partes - primeiro tudo antes da primeira ocorrência do bloco php, próximo bloco php em si e durar tudo depois do primeiro bloco php. Observe que o caractere ? é usado para tornar a expressão curinga .* non greedy e os outros pontos de interrogação devem ser ignorados.
O último tr traz novas linhas de volta (ele tem que usar a mesma string que foi usada no primeiro tr - neste exemplo ' @@@ ').

    
por 30.09.2015 / 10:01
0

Seu problema é que sed é uma ferramenta de linha única; ele olha para arquivos de uma linha por vez. É possível dizer a ele para reter o contexto através de linhas e fazer com que ele varie suas ações com base nisso, mas esse é um recurso bastante obscuro e difícil, e portanto raramente usado, do sed. Em vez disso, eu faria isso com o Perl:

#!/usr/bin/perl -w
use strict;
use warnings;

foreach my $file (@ARGV) {
    open INPUT, "<$file";
    open OUTPUT, ">$file.new";
    my $found = 0;
    while (my $line=<INPUT>) {
        if ($line =~ /<\?php/ && !$found) {
            $found=1;
        } else {
            print OUTPUT $line;
        }
    }
    close INPUT;
    close OUTPUT;
}

chame a lista de arquivos que você deseja editar como argumentos da linha de comando. Isso despejará a saída filtrada em arquivos com uma extensão .new adicional.

No entanto, a melhor prática quando o servidor está comprometido é limpá-lo e restaurá-lo a partir de backups. Não há como dizer que outras coisas ruins podem ter acontecido.

    
por 30.09.2015 / 10:12