Recently my server has been a target for a series php exploit attacks and using ClamAV I was able to identify many infected files.

The catch here is that there are legitimate files that are infected along with some that are utterly malicious code.

Fortunately the infected files are in the following format:

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

So I though I could use sed to remove only the first occurrence of the php tag. This way the legitimate code stays intact and malicious part gets deleted.

For that I have used the following command:

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

This has 2 problems:

  1. It replaces every single occurrence instead of the first
  2. It fails for multi-line occurrences

I have used many forms but they have all failed at a point.

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

So I thought maybe you guys can give me a hint on how to make this sed command work or suggest any better tool for the task at hand.


Sorry that I use perl oneliner expresion instead sed, but somehow I cant learn/remember sed's regex. So you can try this:

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

First tr is for changing multiline string in oneline string. The '@@@' string is just an example, it can be any string that does not exist in any files you want to edit (grep it first just to be sure).
Next the perl command is doing the actual work: using regex groups it is spliting string on three parts - first everything before first occurence of php block, next php block itself and last everything after first php block. Please notice that ? character is used to make wildcard expression .* non greedy, and the other question marks has to be escaped.
The last tr brings newlines back (it has to use the same string which was used in first tr - in this example '@@@').


Your problem is that sed is a single-line tool; it looks at files one line at a time. It is possible to tell it to retain context across lines and have it vary its actions based on that, but this is a rather obscure and difficult, and therefore rarely used, feature of sed. Instead, I would do this with 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) {
        } else {
            print OUTPUT $line;
    close INPUT;
    close OUTPUT;

call with the list of files you want it to edit as command-line arguments. It will dump the filtered output into files with an additional .new extension.

Having said that though, best practice when your server is compromised is to wipe it and restore from backups. There's no telling what other bad things might have happened.

  • It will not work with multiline PHP block. It just cuts the begining of that block leaving rest of it. The other problem is when the begining of PHP block is not the only content in the line (it cuts off full line).
    – alcik
    Sep 30 '15 at 8:31
  • @alcik That's correct. The above code is written in the assumption that the malware writes just one line to the file, which is what the question seems to ask. It's malware, it's broken, it wouldn't surprise me. It shouldn't be too hard to change, if the OP asks... Sep 30 '15 at 12:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.