Как я НЕ просканировал Белорусский интернет

в 20:00, , рубрики: web, безопасность, интернет, информационная безопасность, сети, сканирование

Предисловие

Данная статья не совсем похожа на те, что публиковались ранее про сканирования интернетов определенных стран, потому как я не преследовал целей массового сканирования конкретного сегмента интернета на открытые порты и наличие самых популярных уязвимостей ввиду того, что это противоречит законодательству.

У меня был скорее немного другой интерес — попробовать определить все актуальные сайты в доменной зоне BY разными методиками, определить стек используемых технологий, через сервисы вроде Shodan, VirusTotal и др. выполнить пассивную разведку по IP и открытым портам ну и в довесок собрать немного другой полезной информации для формирования некой общей статистики по уровню защищенности относительно сайтов и пользователей.

Вводная и наш инструментарий

План в самом начале был простой — обратиться к местному регистратору за списком актуальных зарегистрированных доменов, далее все проверить на доступность и начинать изучать функционирующие сайты. В реальности всё оказалось куда сложнее — такого рода информацию естественно, никто предоставлять не захотел, за исключением официальной странички статистики актуальных зарегистрированных доменных имен в зоне BY (порядка 130 тысяч доменов). Если такой информации нет, значит придется собирать самостоятельно.

Как я НЕ просканировал Белорусский интернет - 1

По инструментарию на самом деле все довольно просто — смотрим в сторону open source, что-то всегда можно дописать, допилить какие-то минимальные костыли. Из наиболее популярного, использовались следующие тулзы:

Начало активностей: Отправная точка

В качестве вводной как я уже говорил — в идеале подходили доменные имена, но где их взять? Стартовать нужно с чего-то попроще, в данном случае нам подойдут IP адреса, но опять же — при реверс лукапах не всегда можно словить все домены, а при сборе хостнеймов — не всегда корректный домен. На данном этапе я стал думать о возможных сценариях сбора такого рода информации, опять же — во внимание еще брался тот факт, что наш бюджет это 5$ на аренду VPS, остальное все должно быть бесплатным.

Наши потенциальные источники информации:

  • IP адреса (ip2location сайт)
  • Поиск доменов по второй части email адреса (но где их взять? Разберемся чуть ниже)
  • Некоторые регистраторы/хостинг провайдеры могут предоставить нам такую информацию в форме поддоменов
  • Сабдомены и их последующий реверс (тут могут помочь Sublist3r и Aquatone)
  • Брутфорс и ручной ввод (долго, муторно, но можно, хотя этот вариант я не использовал)

Забегу немного вперед и скажу, что с таким подходом у меня получилось собрать около 50 тысяч уникальных доменов и сайтов соответственно (не все успел обработать). Если бы и дальше продолжал активно собирать информацию, то наверняка за менее чем месяц работы мой конвейер осилил бы всю базу, либо большую ее часть.

Переходим к делу

В предыдущих статьях информацию об IP адресах брали с IP2LOCATION сайта, я на эти статьи по понятной причине не натыкался (т.к. все действия происходили намного раньше), но тоже пришел к данному ресурсу. Правда, в моем случае подход отличался — я решил не забирать к себе локально базу и не извлекать информацию из CSV, а решил мониторить изменения непосредственно на сайте, на постоянной основе и в качестве основной базы откуда все последующие скрипты будут брать цели — сделал таблицу с IP адресами в разных форматах: CIDR, список «от» и «до», пометка страны (на всякий случай), AS Number, AS Description.

Как я НЕ просканировал Белорусский интернет - 2

Формат не самый оптимальный, но для демки и разовой акции меня вполне устраивал, а дабы на постоянной основе не обращаться за вспомогательной информацией вроде ASN, я решил ее дополнительно логировать у себя. Для получения этой информации я обращался к сервису IpToASN, у них есть удобное API (с ограничениями), которое по сути надо просто к себе интегрировать.

Код для парсинга IP

function ipList() {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://lite.ip2location.com/belarus-ip-address-ranges");
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_USERAGENT,'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    $ipList = curl_exec($ch);
    curl_close ($ch);
    preg_match_all("/(d{1,3}.d{1,3}.d{1,3}.d{1,3}</td>s+<td>d{1,3}.d{1,3}.d{1,3}.d{1,3})/", $ipList, $matches);
    return $matches[0];
}

    function iprange2cidr($ipStart, $ipEnd){
        if (is_string($ipStart) || is_string($ipEnd)){
            $start = ip2long($ipStart);
            $end = ip2long($ipEnd);
        }
        else{
            $start = $ipStart;
            $end = $ipEnd;
        }
 
        $result = array();
 
        while($end >= $start){
            $maxSize = 32;
            while ($maxSize > 0){
                $mask = hexdec(iMask($maxSize - 1));
                $maskBase = $start & $mask;
                if($maskBase != $start) break;
                $maxSize--;
            }
            $x = log($end - $start + 1)/log(2);
            $maxDiff = floor(32 - floor($x));
 
            if($maxSize < $maxDiff){
                $maxSize = $maxDiff;
            }
 
            $ip = long2ip($start);
            array_push($result, "$ip/$maxSize");
            $start += pow(2, (32-$maxSize));
        }
        return $result;
    }

$getIpList = ipList();
foreach($getIpList as $item) {
    $cidr = iprange2cidr($ip[0], $ip[1]);
}

После того, как мы разобрались с IP, нам нужно прогнать всю нашу базу через сервисы reverse lookup, увы без каких либо ограничений — это невозможно, разве что, за деньги.

Из сервисов которые для этого замечательно подходят и удобны в использовании я хочу отметить целых два:

  1. VirusTotal — лимит но частоте обращений с одного API ключа
  2. Hackertarget.com (их API) — лимит по количеству обращений с одного IP

По обходу лимитов получились следующие варианты:

  • В первом случае один из сценариев это выдерживать таймауты в 15 секунд, итого у нас будет 4 обращения в минуту, что сильно может сказаться на нашей скорости и в данной ситуации будет кстати использование 2-3 таких ключей, при этом я бы рекомендовал так же прибегнуть к proxy и менять user-agent.
  • Во втором случае, я писал скрипт для автоматического парсинга базы proxy на основании публично доступной информации, их валидации и последующего использования (но позже от этого варианта отошел т.к. хватало по сути и VirusTotal)

Идем далее и плавно переходим к email адресам. Они так же могут быть источником полезной информации, но где же их собирать? Решение не пришлось искать долго, т.к. в нашем сегменте персональных сайтов пользователи держат мало, а в основной массе это организации — то нам подойдут профильные сайты вроде каталогов интернет магазинов, форумов, условных маркетплейсов.

К примеру беглый осмотр одной из таких вот площадок показал, что очень много пользователей добавляют свои email прямо к себе в публичный профиль и соответственно — это дело можно аккуратно спарсить для последующего использования.

Один из парсеров

#!/usr/bin/env python3

import sys, threading, time, os, urllib, re, requests, pymysql
from html.parser import HTMLParser
from urllib import request
from bs4 import BeautifulSoup

# HEADERS CONFIG
headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11.9; rv:42.0) Gecko/20200202 Firefox/41.0'
      }

file = open('dat.html', 'w')

def parseMails(uid):
	page = 'https://profile.onliner.by/user/'+str(uid)+''
	cookie = {'onl_session': 'YOUR_SESSION_COOOKIE_HERE'}
	r = requests.get(page, headers = headers, cookies = cookie)
	data = BeautifulSoup(r.text)
	userinfo = data.find_all('dl', {'class': 'uprofile-info'})
	find_email = []
	for item in userinfo:
		find_email += str(item.find('a'))
	get_mail = ''.join(find_email)
	detect_email = re.compile(".+?>(.+@.+?)</a>").search(get_mail)
	file.write("<li>('"+detect_email.group(1)+"'),</li>")

for uid in range(1, 10000):
	t = threading.Thread(target=parseMails, args=(uid,))
	t.start()
	time.sleep(0.3)

В подробности парсинга каждой из площадок вдаваться не буду, где-то удобнее угадывать ID пользователя методом перебора, где-то проще распарсить карту сайта, получить из нее информацию о страницах компаний и далее уже собирать адреса из них. После сбора адресов, нам остается выполнить несколько простых операций сразу отсортировав по доменной зоне, сохранив для себя «хвостики» и прогнать для исключения дубликатов по имеющейся базе.

На этом этапе я считаю, что с формированием скоупа мы можем заканчивать и переходить к разведке. Разведка как мы уже знаем, может быть двух видов — активной и пассивной, в нашем случае — наиболее актуальным будет пассивный подход. Но опять же, просто обращение к сайту на 80 или 443 порт без вредоносной нагрузки и эксплуатации уязвимостей — вполне себе легитимное действие. Наш интерес — это ответы сервера на единственный запрос, в некоторых случаях запросов может быть два (перенаправление с http на https), в более редких — целых три (когда используется www).

Разведка

Оперируя такой информацией как домен, мы можем собрать следующие данные:

  • Записи DNS (NS, MX, TXT)
  • Заголовки ответов
  • Определить используемый стек технологий
  • Понять по какому протоколу работает сайт
  • Попробовать определить открытые порты (по базе Shodan / Censys) без прямого сканирования
  • Попробовать определить уязвимости исходя из корреляции информации из Shodan / Censys с базой Vulners
  • Находится ли он в базе вредоносных Google Safe Browsing
  • По домену собрать email адреса, а так же сопоставить уже найденные и проверить по Have I Been Pwned, в дополнение — привязку к социальным сетям
  • Домен — это в некоторых случаях не только лицо компании, но и продукт ее деятельности, email адреса для регистрации на сервисах и т.п., соответственно — можно поискать информацию которая с ними ассоциируется на ресурсах вроде GitHub, Pastebin, Google Dorks (Google CSE)

Всегда можно пойти напролом и воспользоваться как вариант masscan или nmap, zmap, настроив их предварительно через Tor с запуском в рандомное время или даже с нескольких инстансов, но у нас другие цели и из названия следует, что таки прямых сканирований я не делал.

Собираем DNS записи, проверяем возможность амплификации запросов и ошибки конфигурации вроде AXFR:

Пример сбора записей NS серверов

dig ns +short $domain | sed 's/.$//g' | awk '{print $1}'

Пример сбора записей MX (см. в NS, просто заменить 'ns' на 'mx'

Проверка на AXFR (тут солюшенов существует много, вот еще один костыльный, но не секьюрный, использовал для просмотра аутпутов)

	$digNs = trim(shell_exec("dig ns +short $domain | sed 's/.$//g' | awk '{print $1}'"));
	$ns = explode("n", $digNs);
	foreach($ns as $target) {
		$axfr = trim(shell_exec("dig -t axfr $domain @$target | awk '{print $1}' | sed 's/.$//g'"));
		$axfr = preg_replace("/;/", "", $axfr);
		if(!empty(trim($axfr))) {
		$axfr = preg_replace("/;/", "", $axfr);
		$res = json_encode(explode("n", trim($axfr)));

Проверка на DNS Amplification

dig +short test.openresolver.com TXT @$dns

В моем случае NS сервера брались из БД, по тому на конце переменная, туда можно подставить просто любой сервер по сути. По поводу корректности результатов данного сервиса — не могу быть уверен, что там прям на 100% все ровно работает и результаты всегда валидны, но, надеюсь, что большинство результатов — реальны.

Если нам для каких либо целей нужно сохранять у себя полноценный конечный URL к сайту, для этого я воспользовался cURL:

curl -I -L $target | awk '/Location/{print $2}'

Он сам перейдет по всем редиректом и выведет финальный, т.е. актуальный URL сайта. В моем случае это было крайне полезно при последующем использовании такой тулы как WhatWeb.

Для чего нам использовать его? Дабы определить используемую OS, веб-сервер, CMS сайта, какие-то заголовки, дополнительные модули вроде JS / HTML библиотек/фреймворков, а так же тайтл сайта по которому впоследствии можно попробовать отфильтровать к тому же и по сфере деятельности.

Очень удобным вариантом в данном случае будет экспорт результатов работы тула в формате XML для последующего разбора и импорта в БД если есть цель это все в последствии обрабатывать.

whatweb --no-errors https://www.mywebsite.com --log-xml=results.xml

Для себя я на выходе делал по итогу JSON и его уже складывал в БД.

К слову о заголовках, можно почти тоже самое выполнять и обычным cURL выполняя запрос вида:

curl -I https://www.mywebsite.com

В заголовках отлавливать самостоятельно информацию о CMS и веб-серверах с помощью регулярных выражений к примеру.

Кроме стека из полезного, мы так же можем выделить возможность сбора информации об открытых портах с помощью Shodan и далее уже используя полученные данные — выполнить проверку по базе Vulners с помощью их API (ссылки на сервисы приведены в шапке). Конечно же, с точностью при таком раскладе могут быть проблемы, все же это не прямое сканирование с ручной валидацией, а банальное «жонглирование» данными из сторонних источников, но лучше хотя бы так чем совсем ничего.

PHP функция для Shodan

function shodanHost($host) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://api.shodan.io/shodan/host/".$host."?key=<YOUR_API_KEY>");
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_USERAGENT,'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    $shodanResponse = curl_exec($ch);
    curl_close ($ch);
    return json_decode($shodanResponse);
}

Пример такого сравнительного анализа #1

Как я НЕ просканировал Белорусский интернет - 3

Пример #2

Как я НЕ просканировал Белорусский интернет - 4

Да, раз уж заговорили за API, то у Vulners есть ограничения и наиболее оптимальным решением будет — использование их скрипта на Python, там без кручений-верчений все будет отлично работать, в случае с PHP столкнулся с некоторыми небольшими трудностями (опять же — доп. таймауты спасли ситуацию).

Одним из последних тестов — будем изучать информацию по используемым firewall с помощью такого скрипта как «wafw00f». При тестировании этой замечательной тулы заметил одну интересность, не всегда с первого раза получалось определить тип используемого файрвола.

Чтобы посмотреть какие типы файрволов потенциально может определить wafw00f можно ввести следующую команду:

wafw00f -l

Для определения типа файрвола — wafw00f анализирует заголовки ответа сервера после отправки стандартного запроса к сайту, в случае если данной попытки не достаточно, он формирует дополнительный простой тестовый запрос ну и если этого в очередной раз не достаточно — то третья методика оперирует данными после первых двух попыток.

Т.к. нам для статистики по сути весь ответ не нужен, то все лишнее мы обрезаем регулярным выражением и оставляем лишь название firewall:

/issbehindsas(.+?)n/

Ну и как я ранее писал — кроме информации о домене и сайте, так же в пассивном режиме актуализировалась информация о email адресах и социальных сетях:

Статистика по email определенных на базе домена

Как я НЕ просканировал Белорусский интернет - 5

Пример определения привязки социальных сетей к email адресу

Как я НЕ просканировал Белорусский интернет - 6

Самым простым было разобраться с валидацией адресов в Twitter (2 способа), с Facebook (1 способ) в этом плане оказалось немного сложнее из-за чуть более замысловатой системы генерации сессии реального пользователя.

Перейдем к сухой статистике

Статистика по DNS

Как я НЕ просканировал Белорусский интернет - 7

Провайдер — сколько сайтов
ns1.tutby.com: 10899
ns2.tutby.com: 10899
ns1.neolocation.com: 4877
ns2.neolocation.com: 4873
ns3.neolocation.com: 4572
ns1.activeby.net: 4231
ns2.activeby.net: 4229
u1.hoster.by: 3382
u2.hoster.by: 3378

Уникальных DNS обнаружено: 2462
Уникальных MX (почтовых) серверов: 9175 (кроме популярных сервисов, есть достаточное количество администраторов которые используют собственные почтовые службы)
Подвержены DNS Zone Transfer: 1011
Подвержены DNS Amplification: 531
Немного любителей CloudFlare: 375 (основываясь на используемых записях NS)

Статистика по CMS

Как я НЕ просканировал Белорусский интернет - 8

CMS — Количество
WordPress: 5118
Joomla: 2722
Bitrix: 1757
Drupal: 898
OpenCart: 235
DataLife: 133
Magento: 32

  • Потенциально уязвимых установок WordPress: 2977
  • Потенциально уязвимых установок Joomla: 212
  • При помощи сервиса Google SafeBrowsing получилось выявить потенциально опасных или зараженных сайтов: около 10.0000 (в разное время, кто-то фиксил, кого-то видимо ломали, статистика не совсем объективная)
  • Про HTTP и HTTPS — последним пользуется менее половины сайтов от найденного объема, но с учетом того, что моя база не полная, а являешься лишь 40% от всего количества, то вполне возможно, что большая часть сайтов из второй половины могут и общаются по HTTPS.

Статистика по Firewall:

Как я НЕ просканировал Белорусский интернет - 9

Firewall — Количество
ModSecurity: 4354
IBM Web App Security: 126
Better WP Security: 110
CloudFlare: 104
Imperva SecureSphere: 45
Juniper WebApp Secure: 45

Статистика по веб серверам

Как я НЕ просканировал Белорусский интернет - 10

Веб-сервер — Количество
Nginx: 31752
Apache: 4042
IIS: 959

Устаревших и потенциально уязвимых установок Nginx: 20966
Устаревших и потенциально уязвимых установок Apache: 995

Несмотря на то, что лидером по к примеру доменам и хостингу в целом у нас является hoster.by, отличится смогли и Открытый контакт, но правда по количеству сайтов на одном IP:

Как я НЕ просканировал Белорусский интернет - 11

IP — Сайтов
93.84.119.243: 556
93.125.99.83: 399
193.232.92.25: 386

Как я НЕ просканировал Белорусский интернет - 12

По email детальную статистику совсем уж решил не дергать, по доменной зоне не сортировать, скорее интерес был посмотреть расположение пользователей к конкретным вендорам:

  • На сервисе TUT.BY: 38282
  • На сервисе Yandex(by|ru): 28127
  • На сервисе Gmail: 33452
  • Привязаны к Facebook: 866
  • Привязаны к Twitter: 652
  • Фигурировали в утечках по информации HIBP: 7844
  • Пассивная разведка помогла выявить более 13 тысяч email адресов

Как видим, в целом картинка довольно позитивная, особенно порадовало активное использование nginx со стороны хостинг провайдеров. Возможно, это в большей степени связано с популярным среди рядовых пользователей — shared типом хостинга.

Из того, что не очень понравилось — есть достаточное количество хостинг провайдеров средней руки, у которых были замечены ошибки вроде AXFR, использовались устаревшие версии SSH и Apache ну и некоторые другие мелкие проблемки. Тут конечно же, больше света на ситуацию смог бы пролить ресерч с активной фазой, но на данный момент в силу нашего законодательства это как мне кажется — невозможно, а записываться ради таких дел в ряды вредителей не особо и хотелось бы.

Картина по email в целом довольно радужная, если это можно так назвать. Ах да, там где указан провайдер TUT.BY — это имелось ввиду использование домена, т.к. данный сервис работает на базе Яндекса.

Заключение

В качестве заключения могу сказать одно — даже с имеющимися результатами, можно быстро понять, что существует большой объем работ для специалистов которые занимаются очисткой сайтов от вирусов, настройкой WAF и конфигурацией/допиливанием разных CMS.

Ну, а если серьезно — то как и в предыдущих двух статьях мы видим, что проблемы существуют абсолютно на разных уровнях в абсолютно всех сегментах сети интернет и странах, и всплывают некоторые из них даже при отдаленном изучении вопроса, без использования offensive методик, т.е. оперируя публично доступной информацией для сбора которой особых навыков и не требуется.

Автор: sm0k3net

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js