Uncover Infected Website Visitors Using Content Security Policies
Security researcher Andrea Menin discovered that thousands of his website visitors were infected by using a content security policy.
Over the last thirty days I discovered thousands of our website users were infected by Adware.OtherSearch while they were browsing a customer's website which I had protected with a WAF by configuring a Content Security Policy (CSP) header. In this article I outline how I set this up so that you can reproduce it.
You may already know that a well configured "Content Security Policy" is a smart way to improve a user's security against content injection, like reflected or stored XSS. CSP usually blocks contents that are not supposed to be loaded by the user while browsing on a website. If you want to drill down deeper into this, you can find a lot of information on Scott Helme's blog, it won't let you down!
A feature of the browsers' policies is that they can send a log to a remote location when a block occurs. This makes you able to know when something is being blocked on your website. One of the most popular tools to collect these events is https://report-uri.com that, at the time that I'm writing, has a free plan which includes 10.000 reports per month, 3 sites monitored and 90 day retention. In my environment, I've created a couple of ModSecurity rules in order to intercept these events and transform them into ModSecurity audit logs.
The Side Effect
A nice side effect of CSP is that it blocks HTTP requests even if the browser itself tries to inject something on the response body. Now maybe you're thinking "why, for god sake, my browser should inject something on the response body?", this could be a classical behavior of a browser extension (but usually what is injected is local and not included from outside) OR Adware "software that generates revenue by automatically generating online advertisements"
Not all adware is outright horrible, most of the time it’s merely irritating, but at its worst, it can undermine your security settings to track your activities and display ads where it normally wouldn’t have access. These security breaches can then be exploited by more dangerous players. When this happens, the software is sometimes referred to as malvertising.
Malvertising is the use of online advertising to spread malware. It typically involves injecting malicious or malware-laden advertisements into legitimate online advertising networks and webpages. Online advertisements provide a solid platform for spreading malware because significant effort is put into them in order to attract users and sell or advertise the product.
Configuring the report-uri parameter lets you know whenever the CSP blocks something. When it happens, the user's browser makes a POST request to what you've configured in the "report-uri" parameter. In that request it sends a JSON string with all information about the blocked content.
In this case, I've configured my CSP with something like this:
Content-Security-Policy: \
script-src \
'self' \
https://www.googletagmanager.com \
https://maps.google.com \
https://maps.googleapis.com \
https://www.google.com \
https://www.google-analytics.com \
style-src \
'self' \
https://fonts.googleapis.com; \
font-src \
'self' \
https://fonts.gstatic.com; \
report-uri \
/csp-report
Now, when I've activated this CSP configuration, I've started to receive a lot of logs from users who were trying to include JavaScript contents from outside of my customer's website. It was strange at first because none of them was part of the website! Going a little bit deeper I discovered that this JavaScript was trying to include advertisements that were not supposed to be there...
Below are just a few URL's that the CSP has blocked while users were browsing the website (At the end of this post I have a complete list of hosts that I've collected):
https://data1.bevuak.com/scripts/js?k=5c0a865d86df1a41188b4567&s=ZXhhbXBsZS5jb20K
https://data1.glucmu.com/scripts/js?k=5b852daa83df1a444f8b4568&s=ZXhhbXBsZS5jb20K
https://data1.pletar.com/scripts/js?k=5c05847390cf762b5e8b4567&s=ZXhhbXBsZS5jb20K
https://data1.thetto.com/scripts/js?k=5bcb0e5787df1a7b038b4567&s=ZXhhbXBsZS5jb20K
All JavaScript above has almost the same content. They include some JavaScript functions from othersearch.info and then show you ugly ADV at the top of the page you're visiting. Below is an interesting extract:
Adware.OtherSearch is Malwarebytes’ detection name for a family of Windows installers that deliver adware to the affected system. The adware delivered by Adware.OtherSearch specializes in browser hijacks, mainly changing the default search engine of the user. The installer is typically delivered by bundlers, check out the Malwarebytes page below for more information.
https://blog.malwarebytes.com/detections/adware-othersearch/
Reflected XSS Everywhere!
In case you think that the people who created this adware are genius hackers, I would like to point out that they are not. Their injected JavaScirpt code is total crap!
As you can see in the URL list above, all they have two parameters: k
and s
. The last one "s" seems to be a base64 encoded string. Decoding it, I found the hostname of my costumer's website (that I've replaced with example.com for this article), and here comes the fun part: they don't sanitize it! 😂Indeed if you encode something like example.com", "wohoo
you can easily inject JavaScript contents like this:
How to log CSP blocks with ModSecurity
My WAF has a centralized console based on elasticsearch, where I collect ALL events from ModSecurity and Nginx. I love report-uri.com but I need something that can be easily collected by my parsers and that can be included on my dashboard... so, what better than a ModSecurity JSON log? Let's do it:
First we've to enforce ModSecurity to process the request body as JSON when the Content-Type is application/csp-report
. We can do it just by create a new rule that catch all "csp-report" content types using requestBodyProcessor=JSON
in order to tell to ModSecurity that the request body is a JSON string, for example:
SecRule REQUEST_HEADERS:Content-Type \
"application/csp-report|application/xss-auditor-report" \
"id:2000,\
phase:1,\
pass,\
nolog,\
t:none,t:lowercase,\
ctl:requestBodyProcessor=JSON"
Now we can access to any single values of the JSON body via the ModSecurity json
variable. The user's browser sends something like this:
POST /csp-report HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 ...
Content-Type: application/csp-report
Referer: https://www.example.com/bla
Origin: https://www.example.com
Content-Length: 893
Connection: close
{
"csp-report": {
"document-uri": "https://www.example.com/fr/fr",
"referrer": "https://www.google.com/",
"violated-directive": "script-src-elem",
"effective-directive": "script-src-elem",
"original-policy": "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.gstatic.com https://developers.google.com https://www.googletagmanager.com https://maps.google.com https://www.google.com https://www.google-analytics.com https://maps.googleapis.com data:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' 'unsafe-inline' data: https://fonts.gstatic.com; report-uri /csp-report",
"disposition": "enforce",
"blocked-uri": "https://data1.vemopi.com/assets/js/jquery.js?s...=&2019031",
"line-number": 84,
"column-number": 47,
"source-file": "https://www.example.com/etc/clientlibs/granite/jquery/granite.min.js",
"status-code": 0,
"script-sample": ""
}
}
it means that, if we want to get the value of blocked-uri
(which contains what the browser has blocked) we can get it by using %{ARGS:json.csp-report.blocked-uri}
Now, the rule:
SecRule REQUEST_HEADERS:Content-Type "application/csp-report" \
"id:2100,\
phase:2,\
pass,\
log,\
msg:'Content Security Policy Violation',\
logdata:'Violated Directive: %{ARGS:json.csp-report.violated-directive} - Blocked URI: %{ARGS:json.csp-report.blocked-uri} - Disposition: %{ARGS:json.csp-report.disposition}',\
t:none,\
tag:'browser-policy-violation',\
tag:'header/content-security-policy',\
tag:'application-multi',\
tag:'platform-multi',\
severity:'CRITICAL',\
setvar:'tx.msg=%{rule.msg}'"
Removal
If you need to learn how to remove this kind of adware, google is your friend and have lots of links in the subject: https://www.google.it/search?q=othersearch.info
Complete list of collected hosts
https://data1.app-fast.com
https://data1.bevuak.com
https://data1.bicelou.com
https://data1.cheklaby.com
https://data1.chrchaimoua.com
https://data1.dagedor.com
https://data1.eurosty.com
https://data1.fertoul.com
https://data1.fiktar.com
https://data1.glicalol.com
https://data1.glucmu.com
https://data1.greskof.com
https://data1.gribul.com
https://data1.janomirg.com
https://data1.kismuta.com
https://data1.macoulpa.com
https://data1.mio-percorso.com
https://data1.moipreso.com
https://data1.noegate.com
https://data1.papsinim.com
https://data1.pictdog.com
https://data1.platoks.com
https://data1.pletar.com
https://data1.pomrolo.com
https://data1.riploi.com
https://data1.sabuf.com
https://data1.selbamo.com
https://data1.stoploco.com
https://data1.super-rezepte.com
https://data1.teryom.com
https://data1.thetto.com
https://data1.ujdilon.com
https://data1.vemopi.com
https://data1.vulapo.com
https://data1.yutrec.com
https://data1.zorbil.com
https://data1.zunelrish.com