• Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе

    «Анализ защищенности веб-приложений»

    🔥 Записаться бесплатно!

  • CTF с учебными материалами Codeby Games

    Обучение кибербезопасности в игровой форме. Более 200 заданий по Active Directory, OSINT, PWN, Веб, Стеганографии, Реверс-инжинирингу, Форензике и Криптографии. Школа CTF с бесплатными курсами по всем категориям.

Статья Получение списка доменов на одном IP-адресе с помощью Python (VHOST)

2022-09-12_18-07.png

Зачастую на одном веб-сервере, особенно, если это крупный хостинг провайдер, может быть расположено множество виртуальных хостов. А значит, на одном IP-адресе могут соседствовать большое количество сайтов. Причины, по которым необходимо получить информацию о сайтах, которые расположены на одном IP, могут быть разные. Иногда это просто любопытство. Ведь интересно же, куда можно попасть, если попробовать вбить не адрес сайта, а его IP. Иногда данная информация может быть полезна во время пентеста, когда производится первоначальный сбор информации. Идея тут в том, что разные веб-приложения могут использовать разное программное обеспечение. Таким образом, если получается выяснить, что на тестируемом IP расположено еще несколько сайтов, можно попробовать найти уязвимость на другом сайте, если не получается на целевом. То есть, найти «слабое звено», тем самым есть вероятность того, что будет скомпрометирован весь сервер. Или это может помочь в атаке на целевой ресурс. Давайте с помощью Python создадим скрипт, с помощью которого попытаемся определить домены на одном IP-адресе, если они, конечно же, там присутствуют. И домен расположен на виртуальном хостинге.


Дисклеймер: Все данные, предоставленные в данной статье, взяты из открытых источников, не призывают к действию и являются только лишь данными для ознакомления, и изучения механизмов используемых технологий.


Что потребуется?

Давайте начнем с библиотек, которые необходимо установить для работы скрипта. Нам понадобится установить requests bs4 lxml. С их помощью мы будем делать запросы к разнообразным сайтам, а также получать информацию из результатов парсинга страниц. Для их установки пишем в терминале:

pip install requests bs4 lxml

Так же понадобятся две библиотеки, с помощью которых можно получить информацию WHOIS о домене и ip адресе домена. Это библиотеки python-whois и ipwhois. Для их установки используйте следующую команду:

pip install python-whois PySocks ipwhois

Для того, чтобы проверять доступность домена воспользуемся библиотекой ping3. Устанавливаем в терминале:

pip install ping3

И еще нам понадобится библиотека selenium и надстройка над данной библиотекой — selenium_stealth. С их помощью мы будем парсить поисковую выдачу Bing, которая касается получения информации о доменах на одном ip-адресе. Пишем в терминале для установки:

pip install selenium selenium_stealth


Ключ API от Virustotal

Так же, для работы скрипта необходимо получить ключ доступа к API на сайте Virustotal. Ничего сложного в этом нет. Идем на , авторизуемся или регистрируемся. У меня получилось авторизоваться с учетной записью Google. После этого заходим в личный кабинет, в раздел «API key».

01.png

Здесь, в разделе вы увидите поле, в котором за звездочками будет скрываться ваш API key. Копируем его.

02.png

После того, как ключ будет скопирован, можно создать файл .py, я назвал его api_total.py и поместить в него скопированный ключ:

api_total = 'ваш_ключ'

Его мы будем импортировать в скрипт для получения информации. Для чего нужно получать ключ Virustotal? Все достаточно просто. Для того, чтобы получить информацию по одному IP-адресу и располагающимся на нем доменам, нужно собрать достаточно большую статистику. Именно такая статистика есть у Virustotal, так как пользователи отправляют на проверку самые различные сайты, страницы и домены. Ну и Virustotal с помощью API делится данной статистикой с тем, кто ее запросит. При бесплатном использовании вам будет доступно 500 запросов в день и 15500 запросов в месяц.

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

Python:
import json
import os
import socket
import threading
import time
from ipaddress import ip_address, ip_network
from platform import system

import requests
import whois
from bs4 import BeautifulSoup
from ipwhois import IPWhois
from ping3 import ping
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium_stealth import stealth

from api_total import api_total

Теперь пропишем опции для браузера Chrome с использованием веб-драйвера Selenium, а также определим заголовки для запросов, которые будут выполнятся с помощью requests.

Python:
options = Options()
options.add_argument("--headless")
options.add_argument("start-maximized")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)

headers = {
    'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 '
                  'Safari/537.36',
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,'
              'application/signed-exchange;v=b3;q=0.9 '
}

Двигаемся дальше. Определим глобальные переменные, в которые будут помещаться различные значения во время работы скрипта. DOMAIN — тип множество. Сюда будут помещаться все найденные домены. И для того, чтобы исключить повторы, мы и будем его использовать, так как в множестве не может храниться двух одинаковых значений. CHECK — тип множество. Сюда мы будем складывать тоже домены, но уже после того, как выполним их проверку на доступность и соответствие искомому IP-адресу. ADDR_INFO — словарь, в который мы будем помещать значения полученные во время работы скрипта. Такие как информация о хостинг-провайдере, информация WHOIS, ну и в конце, после всех проверок, сюда же поместим информацию о найденных доменах. LIST_ADDR — тип список. Сюда мы поместим диапазоны IP-адресов, которые принадлежат Cloudflare. Определим переменную executable_path, она нужна здесь для того, чтобы поместить ее в область видимости функций.

Определим версию операционной системы, а следовательно, в зависимости от этого присвоим переменной executable_path путь в драйверу selenium.

Python:
DOMAIN = set()
CHECK = set()
ADDR_INFO = dict()
LIST_ADDR = []

executable_path = None

if system() == "Windows":
    executable_path = os.path.join(os.getcwd(), 'chromedriver', 'chromedriver.exe')
elif system() == "Linux":
    executable_path = os.path.join(os.getcwd(), 'chromedriver', 'chromedriver')


Загрузка диапазона адресов Cloudflare

Создадим функцию, которая будет загружать диапазоны адресов Cloudflare со страницы и помещать данные диапазоны в список. Я назвал ее load_range(). Так как LIST_ADDR определен глобально, мы можем сразу же присвоит полученный результат после того, как разобьем на строки в эту переменную. А также добавим еще один диапазон, которого нет на странице.

Python:
def load_range():
    """
    Загрузка диапазонов адресов Cloudflare.
    Помещение их в глобальный список диапазонов.
    """
    global LIST_ADDR

    print('\n[*] Получение диапазона адресов Cloudflare')
    LIST_ADDR = requests.get(url='https://www.cloudflare.com/ips-v4').text.splitlines()
    LIST_ADDR.append("104.16.0.0/12")


Получение IP-адреса по доменному имени

Создадим функцию get_ip(domain: str). На вход она получает доменное имя, для которого будет получать IP-адрес. Данная функция будет использоваться не только при определении первоначального адреса домена, но и в дальнейшем, с ее помощью мы будем определять IP-адреса найденных доменов, для того, чтобы сравнить их с искомым IP. Для чего это нужно? Дело в том, что информация которая получается с сайта Viurstotal могла устареть. А следовательно, домен может сменить IP-адрес. Может вовсе прекратить свое существование. Вот для этого и нужна проверка. Используем для этого функцию socket.gethostbyname, в которую передадим в качестве параметра доменное имя. Она преобразует доменное имя в формат IPv4 адреса и возвращает в виде строки. Если же получить (преобразовать) доменное имя не удалось, обработаем исключение и вернем False.

Python:
def get_ip(domain: str):
    """
    Выполняется получение ip-адреса по имени домена.
    Если адрес не найден, завершаем работу скрипта.
    Если найден, передаем его в функцию для проверки на
    принадлежность адреса к диапазону Cloudflare.
    :param domain: домен для получения ip-адреса по его имени.
    """
    try:
        ip = socket.gethostbyname(domain)
        return ip
    except socket.gaierror:
        return False


Определение принадлежности IP-адреса к CDN Cloudflare

Создадим функцию cloud_detect(ip: str, domain: str). На входе она принимает ip-адрес. Его мы будем проверять на принадлежность к CDN, а также переменную domain, в которой содержится доменное имя, по которому мы определяли ip-адрес. Оно нужно для передачи его в другую функцию, которая будет вызвана после окончания проверки.

Для чего нужно проверять ip-адрес? Дело в том, что с помощью данного скрипта мы пытаемся получить информацию о хостинг-провайдере домена. Соответственно, если адрес принадлежит Cloudflare, определять хостинг-провайдера не имеет смысла.

Создаем цикл, в котором пробегаемся по диапазонам адресов содержащихся в глобальной переменной LIST_ADDR. Проверяем с помощью функций ip_address и ip_network, входит ли адрес в какой-либо из диапазонов. Функция ip_address возвращает объект IPv4Address. То есть, мы проверяем уже не строку, а объект. Функция ip_network возвращает объект IPv4Network. С ее помощью создается сеть с диапазоном адресов, которые переданы в нее переменной в виде cidr.

Таким образом, если адрес принадлежит диапазону, добавляем значение в словарь, и запускаем функцию domain_on_ip. Если же адрес не принадлежит к диапазону адресов Cloudflare, запускаем функцию whois_domain(domain, ip), в которую передаем доменное имя и ip-адрес, для получения доступной информации.

Python:
def cloud_detect(ip: str, domain: str):
    """
    Проверка ip-адреса на принадлежность к CDN Cloudflare.
    Если адрес не принадлежит диапазону, передача имени домена
    в функцию whois_domain() для получения информации о хостинге.
    :param ip: адрес для проверки.
    :param domain: домен для передачи в функцию whois_domain().
    :return: выход из функции.
    """
    global LIST_ADDR
    print('\n[*] Проверка Cloudflare')
    for addr in LIST_ADDR:
        if ip_address(ip) in ip_network(addr):
            print('[**] Cloudflare обнаружен')
            ADDR_INFO[ip] = {"Cloudflare": "True"}
            domain_on_ip(ip)
            return
    print('[-] Cloudflare не обнаружен')
    whois_domain(domain, ip)
    return


Получение информации о хостинг-провайдере

Создадим функцию hosting_provider(ip: str). На вход она принимает ip-адрес в виде строки. С помощью данной функции мы получим информацию о хостинг провайдере. Именно для этих целей мы устанавливали библиотеку ipwhois. Создадим объект класса IPWhois, в который передадим ip-адрес. Теперь, как написано у разработчика данной библиотеки, используем для поиска информации функцию lookup_rdap и определим метод поиска asn. По умолчанию, если не указан метод, используется поиск по всем типам ‘dns’, ‘whois’, ‘http’.

asn = IPWhois(ip).lookup_rdap(asn_methods=["whois"])

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

Python:
def hosting_provider(ip: str):
    """
    Получение информации о хостинг-провайдере, диапазоне адресов
    хостинг-провайдера по ip-адресу домена.
    :param ip: ip-адрес домена.
    :return: имя хостинг-провайдера, диапазон адресов хостинг-провайдера.
    """
    try:
        asn = IPWhois(ip).lookup_rdap(asn_methods=["whois"])
        ADDR_INFO[ip].update({'Хостинг-провайдер': asn['asn_description'],
                              'Диапазон адресов провайдера': asn['asn_cidr']})
        print(f'\n[+] Хостинг-провайдер: {asn["asn_description"]}\n[+] Диапазон адресов провайдера: {asn["asn_cidr"]}')
    except Exception:
        return


Получаем информацию о домене

Для того, чтобы получить информацию о домене создадим функцию whois_domain(domain: str, ip: str). На вход она принимает домен, по которому нужно получить информацию и ip-адрес, который нужен будет для передачи в следующую функцию.
Для начала вызовем функцию, с помощью которой получим информацию о хостинг-провайдере.

hosting_provider(ip)

Затем создадим словарь, в котором содержатся значения ключей для замены в ответе на запрос.

Python:
list_field = {"domain_name": "Доменное имя", "registrar": "Регистратор", "updated_date": "Дата обновления",
                  "creation_date": "Дата создания", "expiration_date": "Дата истечения срока регистрации",
                  "name_servers": "Серверы NS", "dnssec": "dnssec", "name": "Владелец", "org": "Организация",
                  "address": "Адрес", "city": "Город", "state": "Штат", "zipcode": "Индекс", "country": "Страна"}

Создадим словарь, в который будем помещать найденные значения. Так как они для каждого домена могут различаться. В том смысле, что некоторых значений ключей в ответе может не быть. И выполним запрос.

Python:
    whois_dict = dict()
    wh = whois.whois(domain, flags=0)

Создаем цикл, в котором будем итерироваться по созданному нами ранее словарю. Забирать из него ключи и проверять, не равно ли значение ключа в ответе None. Если нет, забираем даты, добавляем их в словарь, а также все найденные значения. Почему даты проверяются отдельно? Дело в том, что в полученных значениях может содержаться не просто дата, а их список. И при добавлении данных дат в том виде, в котором они находятся в ответе, даты получаются в не особо читаемом формате. Именно поэтому мы каждое значение, в котором содержится дата, проверяем отдельно.

Python:
    for field in list_field:
        if wh.get(field) is not None:
            try:
                if field == 'updated_date':
                    date = [str(dat) for dat in wh.get(field)]
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = date
                elif field == 'creation_date':
                    date = [str(dat) for dat in wh.get(field)]
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = date
                elif field == 'expiration_date':
                    date = [str(dat) for dat in wh.get(field)]
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = date
                else:
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = wh[field]
            except TypeError:
                if str(wh[field]) not in whois_dict:
                    whois_dict[list_field[field]] = str(wh[field])

После того, как мы переберем все значения в ответе, проверяем длину словаря, в который мы складывали то, что нашли. Если длина больше 0, будем считать, что информация получена и добавим значения в результирующий глобальный словарь. Выведем в терминал содержимое словаря и запустим функцию domain_on_ip, в которой будем получать информацию от Virustotal. Если же словарь пуст, добавляем в глобальный словарь ADDR_INFO информацию о том, что WHOIS не получен и также запускаем функцию domain_on_ip.

Python:
    if len(whois_dict) > 0:
        print(f'[**] Информация WHOIS получена:\n{"-" * 31}')
        ADDR_INFO[ip].update(whois_dict)
        for item in whois_dict:
            print(f'  - {item}: {whois_dict[item]}')
        domain_on_ip(ip)
    else:
        ADDR_INFO[ip].update({'WHOIS': None})
        print('[-] Информация WHOIS не получена')
        domain_on_ip(ip)

Python:
def whois_domain(domain: str, ip: str):
    """
    Получаем информацию о домене. Добавляем полученную
    информацию в словарь. Если словарь не пуст, сохраняем
    информацию в текстовый файл.
    Вызываем функцию получения информации о доменах на ip-адресе.
    :param domain: домен для получения информации о домене.
    :param ip: адрес домена для передачи в функцию запроса доменов
    на ip-адресе.
    """
    hosting_provider(ip)
    print('\n[*] Получение информации WHOIS')
    list_field = {"domain_name": "Доменное имя", "registrar": "Регистратор", "updated_date": "Дата обновления",
                  "creation_date": "Дата создания", "expiration_date": "Дата истечения срока регистрации",
                  "name_servers": "Серверы NS", "dnssec": "dnssec", "name": "Владелец", "org": "Организация",
                  "address": "Адрес", "city": "Город", "state": "Штат", "zipcode": "Индекс", "country": "Страна"}

    whois_dict = dict()
    wh = whois.whois(domain, flags=0)
    for field in list_field:
        if wh.get(field) is not None:
            try:
                if field == 'updated_date':
                    date = [str(dat) for dat in wh.get(field)]
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = date
                elif field == 'creation_date':
                    date = [str(dat) for dat in wh.get(field)]
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = date
                elif field == 'expiration_date':
                    date = [str(dat) for dat in wh.get(field)]
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = date
                else:
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = wh[field]
            except TypeError:
                if str(wh[field]) not in whois_dict:
                    whois_dict[list_field[field]] = str(wh[field])

    if len(whois_dict) > 0:
        print(f'[**] Информация WHOIS получена:\n{"-" * 31}')
        ADDR_INFO[ip].update(whois_dict)
        for item in whois_dict:
            print(f'  - {item}: {whois_dict[item]}')
        domain_on_ip(ip)
    else:
        ADDR_INFO[ip].update({'WHOIS': None})
        print('[-] Информация WHOIS не получена')
        domain_on_ip(ip)


Получение информации о доменах на ip-адресе от Virustotal

Создадим функцию domain_on_ip(ip: str). На вход она получает ip-адрес для поиска. Определяем параметры API запроса, в которые помещаем ip-адрес и apikey. Затем выполняем запрос по специальному адресу, в котором передаем также параметры. В ответ мы получим json с информацией о доменах.

Python:
    param = {'ip': ip, 'apikey': api_total}
    resp = requests.get(url='https://www.virustotal.com/vtapi/v2/ip-address/report', params=param).json()

Проверяем ключ «response_code», который содержит значение 1 или 0. 1 — информация получена, 0 — не получена. Если значение равно 1, двигаемся дальше и в цикле пробегаемся по всем значениям ключа «resolutions», в котором забираем значение ключа «hostname». Именно в этом ключе содержится информация о домене. Добавляем все найденные домены в глобальное множество DOMAIN. Если же домены не найдены, сообщаем об этом и запускаем, в любом случае, функцию поиска информации об ip в поисковой системе Bing.

Python:
    if resp['response_code'] == 1:
        print('[**] Домены найдены')
        for dom in resp['resolutions']:
            DOMAIN.add(dom['hostname'])
    else:
        print('[-] Домены не найдены.')
    get_bing(ip)

Python:
def domain_on_ip(ip: str):
    """
    Выполняется запрос для получения информации о доменах,
    которые имеют один и тот же ip-адрес и находятся в базе
    проверок Virustotal. Для выполнения запроса нужно получить
    ключ API предварительно зарегистрировав аккаунт и скопировав
    его в личном кабинете.
    :param ip: адрес для запроса к API Virustotal.
    """
    print(f'\n[*] Запрос доменов на IP (Virustotal): {ip}')
    param = {'ip': ip, 'apikey': api_total}
    resp = requests.get(url='https://www.virustotal.com/vtapi/v2/ip-address/report', params=param).json()

    if resp['response_code'] == 1:
        print('[**] Домены найдены')
        for dom in resp['resolutions']:
            DOMAIN.add(dom['hostname'])
    else:
        print('[-] Домены не найдены.')
    get_bing(ip)


Поиск информации об IP в поисковой системе Bing

Выбор данной поисковой системы не случаен. В ней поддерживается поисковый оператор ip, с помощью которого можно попробовать найти домены или сайты на одном ip-адресе. Оператор имеет следующие параметры: «ip:<ip-адрес>». Запрос просто выдернут из поисковой строки. В нем мы меняем ip, а также страницы с результатами поиска. На каждой странице выводится по 10 результатов. Итерируемся по 5 страницам, так как дальше просматривать страницы не имеет большого смысла. Очень много повторов, а зачастую, если страниц по запросу мало, выводится одна и та же информация с последней страницы.

Для того, чтобы Bing нас не заблокировал, а также, чтобы забрать содержимое страницы, которая является динамической, будем использовать веб-драйвер selenium с браузером Google Chrome. Конечно, хорошо было бы использовать Firefox, но, так как мы будем использовать надстройку selenium_stealth, то про выбор браузера можно забыть. Так как стелс работает только с Chrome.

Создаем объект браузера и передаем в него параметры стелс.

Python:
    browser = webdriver.Chrome(options=options, service=Service(log_path=os.devnull, executable_path=executable_path))

    stealth(driver=browser,
            user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                       'Chrome/83.0.4103.53 Safari/537.36',
            languages=["ru-RU", "ru"],
            vendor="Google Inc.",
            platform="Win32",
            webgl_vendor="Intel Inc.",
            renderer="Intel Iris OpenGL Engine",
            fix_hairline=True,
            run_on_insecure_origins=True,
            )

Теперь определим два счетчика. Один, count, мы будем использовать в информационных целях, для того, чтобы сообщать пользователю, какую страницу мы в данный момент парсим. И второй, num, с помощью которого мы будем осуществлять переходы по страницам запроса.

Python:
    print('\n[*] Поиск информации о доменах в BING')
    num = 1
    count = 1

Создадим цикл while, выходом из которого будет служить превышение значения числа num. То есть, в данном случае, если num больше 51, что соответствует 5 странице, выходим из цикла. Ну, а далее все просто. Переходим на страницу в безголовом режиме, ждем секунду, чтобы прогрузилась информация, после чего, загружаем содержимое страницы в BeautifulSoup, ищем ссылки на сайты, добавляем найденное в глобальное множество DOMAIN. Ну, и соответственно, после того, как поиск выполнится, выходим из цикла и закрываем браузер.

Python:
    while num < 51:
        print(f'\r  - Получаю информацию со страницы: {count}', end='')
        browser.get(f'https://www.bing.com/search?q=ip%3a+'
                    f'{ip}&qs=HS&sc=1-0&cvid=E3A8381DCD48463B9D4FBFFC24B7C9B3&sp=1&first={num}&FORM=PERE')
        time.sleep(1)

        soup = BeautifulSoup(browser.page_source, 'lxml')
        links = soup.find('ol', id='b_results').find_all('li', class_='b_algo')
        for lin in links:
            DOMAIN.add(lin.find('div', class_='b_title').find('h2').find('a')['href'].split("/")[2])
        num += 10
        count += 1
        time.sleep(2)
    browser.quit()

Python:
def get_bing(ip: str):
    """
    Запрос в поиске Bing с параметром ip.
    Этот параметр позволяет находить в поиске домены
    на данном адресе. Итерируются 10 страниц поиска.
    Найденный домены сохраняются в глобальное множество
    DOMAIN.
    :param ip: адрес для запроса в поиске Bing.
    """
    browser = webdriver.Chrome(options=options, service=Service(log_path=os.devnull, executable_path=executable_path))

    stealth(driver=browser,
            user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                       'Chrome/83.0.4103.53 Safari/537.36',
            languages=["ru-RU", "ru"],
            vendor="Google Inc.",
            platform="Win32",
            webgl_vendor="Intel Inc.",
            renderer="Intel Iris OpenGL Engine",
            fix_hairline=True,
            run_on_insecure_origins=True,
            )

    print('\n[*] Поиск информации о доменах в BING')
    num = 1
    count = 1
    while num < 51:
        print(f'\r  - Получаю информацию со страницы: {count}', end='')
        browser.get(f'https://www.bing.com/search?q=ip%3a+'
                    f'{ip}&qs=HS&sc=1-0&cvid=E3A8381DCD48463B9D4FBFFC24B7C9B3&sp=1&first={num}&FORM=PERE')
        time.sleep(1)

        soup = BeautifulSoup(browser.page_source, 'lxml')
        links = soup.find('ol', id='b_results').find_all('li', class_='b_algo')
        for lin in links:
            DOMAIN.add(lin.find('div', class_='b_title').find('h2').find('a')['href'].split("/")[2])
        num += 10
        count += 1
        time.sleep(2)
    browser.quit()


Проверка доменов на доступность и соответствие искомому IP

Создадим функцию check_domain(dom: str, ip: str). На вход она принимает доменное имя и ip-адрес изначально определенный для домена, по которому проводится поиск. Для чего нужна данная проверка? Дело в том, что информация, которую мы получаем от Virustotal содержит множество доменных имен. Но, так как со временем домены могут попросту закрыться или у них изменится ip-адрес, информация не будет соответствовать текущей действительности.

Для проверки доступности домена будем использовать функцию ping из библиотеки ping3. Данная функция с помощью протокола ICMP делает запрос на домен и обрабатывает полученный ответ. Если ответ получен, возвращается время ответа в секундах. Если нет, функция возвращает None. Пишем условие, если получен ответ, двигаемся дальше. Запускаем цикл по списку, в котором содержатся наименования протоколов. Так как нам необходимо будет проверить ответ от сайта на одном из них. Конечно же, большинство сайтов в настоящее время работают по протоколу https, но, встречаются сайты, и таких довольно большое количество, протокол которых все еще http. Поэтому проверяем на обоих протоколах.

Python:
    if ping(dom):
        print(f'\r  - Проверка: {dom}', end='')
        for pref in ['https://', 'http://']:

Делаем запрос и если ответ получен и нас не выбросило в исключение, получаем ip-адрес домена. Сравниваем его с эталонным, то есть изначальным. Если они равны, добавляем в результирующее множество CHECK. Ну, а если сработало исключение, пробуем выполнить запрос по следующему протоколу.

Python:
            try:
                requests.head(f'{pref}{dom}', headers=headers, timeout=3)
                if get_ip(dom) == ip:
                    CHECK.add(dom)
            except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout):
                continue

Python:
def check_domain(dom: str, ip: str):
    """
    Проверка домена на существование. Если домен отвечает,
    выполняем запрос и пытаемся получить заголовки. Если заголовки
    получены, добавляем в множество CHECK.
    :param ip: ip-адрес для проверки текущего ip домена.
    :param dom: доменное имя для проверки на валидность.
    :return: выход из функции.
    """
    if ping(dom):
        print(f'\r  - Проверка: {dom}', end='')
        for pref in ['https://', 'http://']:
            try:
                requests.head(f'{pref}{dom}', headers=headers, timeout=3)
                if get_ip(dom) == ip:
                    CHECK.add(dom)
            except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout):
                continue

Так как доменов может быть довольно большое количество, проверка их, одного за другим, может длится довольно длительное время. Поэтому, создадим функцию thread_check(ip), которая на входе получает ip-адрес искомого домена, для передачи его в функцию проверки доменов. В данной функции мы будем запускать потоки для проверки доменов.

Создадим список, в который поместим потоки. В цикле проитерируемся по глобальному множеству DOMAIN. Создадим поток, который определим как daemon. Это означает, что данный поток автоматически остановит выполнение после завершения задачи. То есть, будет являться неблокирующим. Запустим его и добавим в список. И так для каждого домена. Поставим небольшую паузу между созданием потоков. Ну, а далее будем перебирать список потоков, пока каждый из них не завершит свою работу.

Python:
def thread_check(ip):
    """
    Запуск потоков для выполнения запросов для проверки доменов
    на существование.
    """
    threads = []
    for dom in DOMAIN:
        t = threading.Thread(target=check_domain, kwargs={'dom': dom, 'ip': ip}, daemon=True)
        t.start()
        threads.append(t)
        time.sleep(0.02)
    for thread in threads:
        thread.join()


Сохранение полученных значений

После того, как выполнятся все основные задачи, необходимо сохранить полученные значения в файлы. Так как мы создавали глобальный словарь ADDR_INFO, который содержит всю полученную нами информацию, для начала сохраним ее в файл json. А затем пробежимся по ключам данного словаря и сохраним информацию уже в текстовый документ.

Создадим функцию save_domain(domain: str). На входе она получает начальное имя домена, по которому был произведен поиск. Оно здесь нужно для того, чтобы присвоить соответствующее имя файлам. Для начала сохраняем глобальный словарь в файл json.

Python:
    with open(os.path.join(os.getcwd(), f'result_{domain}.json'), 'w', encoding='utf-8') as inf:
        json.dump(ADDR_INFO, inf, indent=4, ensure_ascii=False)

Затем создаем цикл, в котором итерируемся по ключам глобального словаря ADDR_INFO. Открываем файла на запись, в режиме «a», то есть append, чтобы не перезаписывать информацию, а добавлять ее в конец файла. Записываем первую строку.

Python:
    for it in ADDR_INFO:
        with open(os.path.join(os.getcwd(), f'result_{domain}.txt'), 'a', encoding='utf-8') as file:
            file.write(f'[+] Информация о хостинг-провайдере:\n{"-" * 36}\n')

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

Python:
            for itm in ADDR_INFO[it].keys():
                if itm == 'domains':
                    file.write(f'\n[+] Найдена информация о доменах:\n{"-" * 34}\n')
                    print(f'\n\n[+] Найдена информация о {len(ADDR_INFO[it][itm])} доменах')
                    for dom in ADDR_INFO[it][itm]:
                        file.write(f'{dom}\n')
                else:
                    file.write(f'{itm}: {ADDR_INFO[it][itm]}\n')

Python:
def save_domain(domain: str):
    """
    Сохраняем результат поисков в json и текстовый документ.
    :param domain: имя домена для сохранения результата.
    """
    with open(os.path.join(os.getcwd(), f'result_{domain}.json'), 'w', encoding='utf-8') as inf:
        json.dump(ADDR_INFO, inf, indent=4, ensure_ascii=False)

    for it in ADDR_INFO:
        with open(os.path.join(os.getcwd(), f'result_{domain}.txt'), 'a', encoding='utf-8') as file:
            file.write(f'[+] Информация о хостинг-провайдере:\n{"-" * 36}\n')
            for itm in ADDR_INFO[it].keys():
                if itm == 'domains':
                    file.write(f'\n[+] Найдена информация о доменах:\n{"-" * 34}\n')
                    print(f'\n\n[+] Найдена информация о {len(ADDR_INFO[it][itm])} доменах')
                    for dom in ADDR_INFO[it][itm]:
                        file.write(f'{dom}\n')
                else:
                    file.write(f'{itm}: {ADDR_INFO[it][itm]}\n')
    print(f'[+] Информация сохранена в файлы: result_{domain}.txt, result_{domain}.json')


Обработка полученного домена и запуск функций

Создадим функцию main(). Для начала запросим у пользователя доменное имя, информацию о котором нужно будет получить. Добавим его в глобальное множество. Запишем первую строку в текстовый файл с именем домена. Здесь же будем обрабатывать исключения. Так как при попытке записи в виде https: будет вызвана ошибка. А значит пользователь ввел домен с http или https.

Python:
    domain = input('Введите доменное имя: ')
    DOMAIN.add(domain)

    try:
        with open(os.path.join(os.getcwd(), f'result_{domain}.txt'), 'w', encoding='utf-8') as file:
            file.write(f'Информация о доменах на ip-адресе домена: {domain}\n\n')
    except (FileNotFoundError, OSError):
        print('Введите доменное имя')
        return

Запускаем функцию загрузки диапазона адресов Cloudflare.

load_range()

Получаем ip-адрес и создаем в словаре ADDR_INFO словарь с ключом равным ip.

Python:
    print('\n[*] Получение IP-адреса')
    ip = get_ip(domain)
    if ip:
        print(f'[**] IP-адрес получен: {ip}')
        ADDR_INFO[ip] = dict()
    else:
        print('[-] Невозможно получить IP-адрес')
        exit(0)

Запускаем функцию проверки на принадлежность IP к диапазону Cloudflare.

cloud_detect(ip, domain)

Далее, по цепочке, будут запускаться все остальные функции. И когда обработка адреса завершится, выполним проверку длины глобального множества DOMAIN. Если она не равна 0, значит информация получена и доступна для обработки. Запускаем потоки для проверки доменных имен.

Python:
    if len(DOMAIN) > 0:
        print('\n\n[*] Проверка доменов:')
        thread_check(ip)
    else:
        print('[-] Информация о доменах не найдена')

После того, как отработают потоки, проверяем длину глобального списка CHECK. Так как мало ли, может быть при проверке будут отсеяны все домены. Если длина множества больше 0, добавляем информацию о найденных доменах в глобальный словарь ADDR_INFO. Тут множество нужно перевести в список, чтобы не было ошибок при сохранении json. И запускаем функцию сохранения данных.

Python:
    if len(CHECK) > 0:
        ADDR_INFO[ip].update({'domains': list(CHECK)})
        save_domain(domain)
    else:
        print('\n[-] Информация найдена, но домены не отвечают на запросы')

Ну и собственно условие, в котором и будет запускаться весь скрипт.

Python:
if __name__ == "__main__":
    main()

Python:
def main():
    """
    Запрос имени домена для поиска информации.
    Запуск функции для загрузки диапазона адресов
    Cloudflare.
    Запуск функции для получения ip-адреса домена.
    Проверка не является ли множество пустым и запуск функции
    проверки доменов на существование.
    Запуск функции сохранения результатов.
    """
    domain = input('Введите доменное имя: ')
    DOMAIN.add(domain)

    try:
        with open(os.path.join(os.getcwd(), f'result_{domain}.txt'), 'w', encoding='utf-8') as file:
            file.write(f'Информация о доменах на ip-адресе домена: {domain}\n\n')
    except (FileNotFoundError, OSError):
        print('Введите доменное имя')
        return

    load_range()

    print('\n[*] Получение IP-адреса')
    ip = get_ip(domain)
    if ip:
        print(f'[**] IP-адрес получен: {ip}')
        ADDR_INFO[ip] = dict()
    else:
        print('[-] Невозможно получить IP-адрес')
        exit(0)

    cloud_detect(ip, domain)
    if len(DOMAIN) > 0:
        print('\n\n[*] Проверка доменов:')
        thread_check(ip)
    else:
        print('[-] Информация о доменах не найдена')
    if len(CHECK) > 0:
        ADDR_INFO[ip].update({'domains': list(CHECK)})
        save_domain(domain)
    else:
        print('\n[-] Информация найдена, но домены не отвечают на запросы')


if __name__ == "__main__":
    main()

Для примера, выполним проверку по домену proglib.io, так как этот домен является показательным примером, когда не используется виртуальный хостинг. Ну, или просто не находится доменов ))

03.png

Думаю, никакой конфиденциальной информации раскрыто не будет. Потому публикую данный скриншот. Здесь, как видно ниже, найдено всего два домена. А точнее домен и субдомен, которые хостятся на Selectel. Однако, Cloudflare здесь также используется, но не прячет реальный IP.

Python:
"""
Скрипт для поиска доменов на одном ip-адресе.
Для работы требует установки следующих модулей:
pip install python-whois PySocks requests bs4 lxml ping3 selenium selenium_stealth ipwhois

Для выполнения запросов к поисковому сервису Bing используется selenium_stealth,
который пытается скрыть факт использования автоматического выполнения запросов
от поисковой системы для того, чтобы можно было парсить результаты.
"""
import json
import os
import socket
import threading
import time
from ipaddress import ip_address, ip_network
from platform import system

import requests
import whois
from bs4 import BeautifulSoup
from ipwhois import IPWhois
from ping3 import ping
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium_stealth import stealth

from api_total import api_total

options = Options()
options.add_argument("--headless")
options.add_argument("start-maximized")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)

headers = {
    'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 '
                  'Safari/537.36',
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,'
              'application/signed-exchange;v=b3;q=0.9 '
}

DOMAIN = set()
CHECK = set()
ADDR_INFO = dict()
LIST_ADDR = []

executable_path = None

if system() == "Windows":
    executable_path = os.path.join(os.getcwd(), 'chromedriver', 'chromedriver.exe')
elif system() == "Linux":
    executable_path = os.path.join(os.getcwd(), 'chromedriver', 'chromedriver')


def load_range():
    """
    Загрузка диапазонов адресов Cloudflare.
    Помещение их в глобальный список диапазонов.
    """
    global LIST_ADDR

    print('\n[*] Получение диапазона адресов Cloudflare')
    LIST_ADDR = requests.get(url='https://www.cloudflare.com/ips-v4').text.splitlines()
    LIST_ADDR.append("104.16.0.0/12")


def get_ip(domain: str):
    """
    Выполняется получение ip-адреса по имени домена.
    Если адрес не найден, завершаем работу скрипта.
    Если найден, передаем его в функцию для проверки на
    принадлежность адреса к диапазону Cloudflare.
    :param domain: домен для получения ip-адреса по его имени.
    """
    try:
        ip = socket.gethostbyname(domain)
        return ip
    except socket.gaierror:
        return False


def cloud_detect(ip: str, domain: str):
    """
    Проверка ip-адреса на принадлежность к CDN Cloudflare.
    Если адрес не принадлежит диапазону, передача имени домена
    в функцию whois_domain() для получения информации о хостинге.
    :param ip: адрес для проверки.
    :param domain: домен для передачи в функцию whois_domain().
    :return: выход из функции.
    """
    global LIST_ADDR
    print('\n[*] Проверка Cloudflare')
    for addr in LIST_ADDR:
        if ip_address(ip) in ip_network(addr):
            print('[**] Cloudflare обнаружен')
            ADDR_INFO[ip] = {"Cloudflare": "True"}
            domain_on_ip(ip)
            return
    print('[-] Cloudflare не обнаружен')
    whois_domain(domain, ip)
    return


def hosting_provider(ip: str):
    """
    Получение информации о хостинг-провайдере, диапазоне адресов
    хостинг-провайдера по ip-адресу домена.
    :param ip: ip-адрес домена.
    :return: имя хостинг-провайдера, диапазон адресов хостинг-провайдера.
    """
    try:
        asn = IPWhois(ip).lookup_rdap(asn_methods=["whois"])
        ADDR_INFO[ip].update({'Хостинг-провайдер': asn['asn_description'],
                              'Диапазон адресов провайдера': asn['asn_cidr']})
        print(f'\n[+] Хостинг-провайдер: {asn["asn_description"]}\n[+] Диапазон адресов провайдера: {asn["asn_cidr"]}')
    except Exception:
        return


def whois_domain(domain: str, ip: str):
    """
    Получаем информацию о домене. Добавляем полученную
    информацию в словарь. Если словарь не пуст, сохраняем
    информацию в текстовый файл.
    Вызываем функцию получения информации о доменах на ip-адресе.
    :param domain: домен для получения информации о домене.
    :param ip: адрес домена для передачи в функцию запроса доменов
    на ip-адресе.
    """
    hosting_provider(ip)
    print('\n[*] Получение информации WHOIS')
    list_field = {"domain_name": "Доменное имя", "registrar": "Регистратор", "updated_date": "Дата обновления",
                  "creation_date": "Дата создания", "expiration_date": "Дата истечения срока регистрации",
                  "name_servers": "Серверы NS", "dnssec": "dnssec", "name": "Владелец", "org": "Организация",
                  "address": "Адрес", "city": "Город", "state": "Штат", "zipcode": "Индекс", "country": "Страна"}

    whois_dict = dict()
    wh = whois.whois(domain, flags=0)
    for field in list_field:
        if wh.get(field) is not None:
            try:
                if field == 'updated_date':
                    date = [str(dat) for dat in wh.get(field)]
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = date
                elif field == 'creation_date':
                    date = [str(dat) for dat in wh.get(field)]
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = date
                elif field == 'expiration_date':
                    date = [str(dat) for dat in wh.get(field)]
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = date
                else:
                    if str(wh[field]) not in whois_dict:
                        whois_dict[list_field[field]] = wh[field]
            except TypeError:
                if str(wh[field]) not in whois_dict:
                    whois_dict[list_field[field]] = str(wh[field])

    if len(whois_dict) > 0:
        print(f'[**] Информация WHOIS получена:\n{"-" * 31}')
        ADDR_INFO[ip].update(whois_dict)
        for item in whois_dict:
            print(f'  - {item}: {whois_dict[item]}')
        domain_on_ip(ip)
    else:
        ADDR_INFO[ip].update({'WHOIS': None})
        print('[-] Информация WHOIS не получена')
        domain_on_ip(ip)


def domain_on_ip(ip: str):
    """
    Выполняется запрос для получения информации о доменах,
    которые имеют один и тот же ip-адрес и находятся в базе
    проверок Virustotal. Для выполнения запроса нужно получить
    ключ API предварительно зарегистрировав аккаунт и скопировав
    его в личном кабинете.
    :param ip: адрес для запроса к API Virustotal.
    """
    print(f'\n[*] Запрос доменов на IP (Virustotal): {ip}')
    param = {'ip': ip, 'apikey': api_total}
    resp = requests.get(url='https://www.virustotal.com/vtapi/v2/ip-address/report', params=param).json()

    if resp['response_code'] == 1:
        print('[**] Домены найдены')
        for dom in resp['resolutions']:
            DOMAIN.add(dom['hostname'])
    else:
        print('[-] Домены не найдены.')
    get_bing(ip)


def get_bing(ip: str):
    """
    Запрос в поиске Bing с параметром ip.
    Этот параметр позволяет находить в поиске домены
    на данном адресе. Итерируются 10 страниц поиска.
    Найденный домены сохраняются в глобальное множество
    DOMAIN.
    :param ip: адрес для запроса в поиске Bing.
    """
    browser = webdriver.Chrome(options=options, service=Service(log_path=os.devnull, executable_path=executable_path))

    stealth(driver=browser,
            user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                       'Chrome/83.0.4103.53 Safari/537.36',
            languages=["ru-RU", "ru"],
            vendor="Google Inc.",
            platform="Win32",
            webgl_vendor="Intel Inc.",
            renderer="Intel Iris OpenGL Engine",
            fix_hairline=True,
            run_on_insecure_origins=True,
            )

    print('\n[*] Поиск информации о доменах в BING')
    num = 1
    count = 1
    while num < 51:
        print(f'\r  - Получаю информацию со страницы: {count}', end='')
        browser.get(f'https://www.bing.com/search?q=ip%3a+'
                    f'{ip}&qs=HS&sc=1-0&cvid=E3A8381DCD48463B9D4FBFFC24B7C9B3&sp=1&first={num}&FORM=PERE')
        time.sleep(1)

        soup = BeautifulSoup(browser.page_source, 'lxml')
        links = soup.find('ol', id='b_results').find_all('li', class_='b_algo')
        for lin in links:
            DOMAIN.add(lin.find('div', class_='b_title').find('h2').find('a')['href'].split("/")[2])
        num += 10
        count += 1
        time.sleep(2)
    browser.quit()


def check_domain(dom: str, ip: str):
    """
    Проверка домена на существование. Если домен отвечает,
    выполняем запрос и пытаемся получить заголовки. Если заголовки
    получены, добавляем в множество CHECK.
    :param ip: ip-адрес для проверки текущего ip домена.
    :param dom: доменное имя для проверки на валидность.
    :return: выход из функции.
    """
    if ping(dom):
        print(f'\r  - Проверка: {dom}', end='')
        for pref in ['https://', 'http://']:
            try:
                requests.head(f'{pref}{dom}', headers=headers, timeout=3)
                if get_ip(dom) == ip:
                    CHECK.add(dom)
            except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout):
                continue


def thread_check(ip):
    """
    Запуск потоков для выполнения запросов для проверки доменов
    на существование.
    """
    threads = []
    for dom in DOMAIN:
        t = threading.Thread(target=check_domain, kwargs={'dom': dom, 'ip': ip}, daemon=True)
        t.start()
        threads.append(t)
        time.sleep(0.02)
    for thread in threads:
        thread.join()


def save_domain(domain: str):
    """
    Сохраняем результат поисков в json и текстовый документ.
    :param domain: имя домена для сохранения результата.
    """
    with open(os.path.join(os.getcwd(), f'result_{domain}.json'), 'w', encoding='utf-8') as inf:
        json.dump(ADDR_INFO, inf, indent=4, ensure_ascii=False)

    for it in ADDR_INFO:
        with open(os.path.join(os.getcwd(), f'result_{domain}.txt'), 'a', encoding='utf-8') as file:
            file.write(f'[+] Информация о хостинг-провайдере:\n{"-" * 36}\n')
            for itm in ADDR_INFO[it].keys():
                if itm == 'domains':
                    file.write(f'\n[+] Найдена информация о доменах:\n{"-" * 34}\n')
                    print(f'\n\n[+] Найдена информация о {len(ADDR_INFO[it][itm])} доменах')
                    for dom in ADDR_INFO[it][itm]:
                        file.write(f'{dom}\n')
                else:
                    file.write(f'{itm}: {ADDR_INFO[it][itm]}\n')
    print(f'[+] Информация сохранена в файлы: result_{domain}.txt, result_{domain}.json')


def main():
    """
    Запрос имени домена для поиска информации.
    Запуск функции для загрузки диапазона адресов
    Cloudflare.
    Запуск функции для получения ip-адреса домена.
    Проверка не является ли множество пустым и запуск функции
    проверки доменов на существование.
    Запуск функции сохранения результатов.
    """
    domain = input('Введите доменное имя: ')
    DOMAIN.add(domain)

    try:
        with open(os.path.join(os.getcwd(), f'result_{domain}.txt'), 'w', encoding='utf-8') as file:
            file.write(f'Информация о доменах на ip-адресе домена: {domain}\n\n')
    except (FileNotFoundError, OSError):
        print('Введите доменное имя')
        return

    load_range()

    print('\n[*] Получение IP-адреса')
    ip = get_ip(domain)
    if ip:
        print(f'[**] IP-адрес получен: {ip}')
        ADDR_INFO[ip] = dict()
    else:
        print('[-] Невозможно получить IP-адрес')
        exit(0)

    cloud_detect(ip, domain)
    if len(DOMAIN) > 0:
        print('\n\n[*] Проверка доменов:')
        thread_check(ip)
    else:
        print('[-] Информация о доменах не найдена')
    if len(CHECK) > 0:
        ADDR_INFO[ip].update({'domains': list(CHECK)})
        save_domain(domain)
    else:
        print('\n[-] Информация найдена, но домены не отвечают на запросы')


if __name__ == "__main__":
    main()

А на этом, пожалуй, все.

Спасибо за внимание. Надеюсь данная информация будет вам полезна
 

Вложения

  • domaintoip.zip
    5,2 КБ · Просмотры: 167
Последнее редактирование модератором:

trushk2

Member
22.09.2022
5
0
BIT
0
В чём проблема ?

Код:
[*] Запрос доменов на IP (Virustotal): 192.254.236.136
[**] Домены найдены
Traceback (most recent call last):
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 340, in <module>
    main()
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 326, in main
    cloud_detect(ip, domain)
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 101, in cloud_detect
    whois_domain(domain, ip)
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 167, in whois_domain
    domain_on_ip(ip)
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 193, in domain_on_ip
    get_bing(ip)
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 205, in get_bing
    browser = webdriver.Chrome(options=options, service=Service(log_path=os.devnull, executable_path=executable_path))
  File "/home/megauser/.local/lib/python3.10/site-packages/selenium/webdriver/chrome/webdriver.py", line 69, in __init__
    super().__init__(DesiredCapabilities.CHROME['browserName'], "goog",
  File "/home/megauser/.local/lib/python3.10/site-packages/selenium/webdriver/chromium/webdriver.py", line 89, in __init__
    self.service.start()
  File "/home/megauser/.local/lib/python3.10/site-packages/selenium/webdriver/common/service.py", line 71, in start
    self.process = subprocess.Popen(cmd, env=self.env,
  File "/usr/lib/python3.10/subprocess.py", line 966, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/usr/lib/python3.10/subprocess.py", line 1842, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
OSError: [Errno 8] Exec format error: '/home/megauser/MyFolder/Dev/allHostFromIP/chromedriver/chromedriver'
 

Johan Van

Green Team
13.06.2020
350
655
BIT
119
В чём проблема ?

Код:
[*] Запрос доменов на IP (Virustotal): 192.254.236.136
[**] Домены найдены
Traceback (most recent call last):
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 340, in <module>
    main()
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 326, in main
    cloud_detect(ip, domain)
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 101, in cloud_detect
    whois_domain(domain, ip)
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 167, in whois_domain
    domain_on_ip(ip)
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 193, in domain_on_ip
    get_bing(ip)
  File "/home/megauser/MyFolder/Dev/allHostFromIP/domaintoip.py", line 205, in get_bing
    browser = webdriver.Chrome(options=options, service=Service(log_path=os.devnull, executable_path=executable_path))
  File "/home/megauser/.local/lib/python3.10/site-packages/selenium/webdriver/chrome/webdriver.py", line 69, in __init__
    super().__init__(DesiredCapabilities.CHROME['browserName'], "goog",
  File "/home/megauser/.local/lib/python3.10/site-packages/selenium/webdriver/chromium/webdriver.py", line 89, in __init__
    self.service.start()
  File "/home/megauser/.local/lib/python3.10/site-packages/selenium/webdriver/common/service.py", line 71, in start
    self.process = subprocess.Popen(cmd, env=self.env,
  File "/usr/lib/python3.10/subprocess.py", line 966, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/usr/lib/python3.10/subprocess.py", line 1842, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
OSError: [Errno 8] Exec format error: '/home/megauser/MyFolder/Dev/allHostFromIP/chromedriver/chromedriver'

Здесь проблема с хромдрайвером. Проверьте пути и версию хромдрайвера. Возможно, что у вас версия хрома и версия драйвера не совпадают. То есть, если вы использовали то, что находиться в папке архива, то это однозначно не драйвер. Это просто заглушка. Потому, посмотрите вашу версию хрома и скачайте драйвер для нее вот отсюда:
 

trushk2

Member
22.09.2022
5
0
BIT
0
Здесь проблема с хромдрайвером. Проверьте пути и версию хромдрайвера. Возможно, что у вас версия хрома и версия драйвера не совпадают. То есть, если вы использовали то, что находиться в папке архива, то это однозначно не драйвер. Это просто заглушка. Потому, посмотрите вашу версию хрома и скачайте драйвер для нее вот отсюда:
Спасибо, попробую
 

Dart Moore

Green Team
16.04.2022
16
6
BIT
3
Так мне это нравиться, давай еще, а точнее все что у тебя есть XD
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!