Пишем простой скрипт на Python

  • На форуме работает ручное одобрение пользователей. Это значит, что, если Ваша причина регистрации не соответствует тематике форума, а также Вы используете временную почту, Ваша учётная запись будет отклонена без возможности повторной регистрации. В дальнейшем - пожизненная блокировка обоих аккаунтов за создание мультиаккаунта.
  • Мы обновили Tor зеркало до v3!
    Для входа используйте следующий url: darkv3nw2...bzad.onion/
  • Мы вновь вернули telegram чат форуму, вступайте, общайтесь, задавайте любые вопросы как администрации, так и пользователям!
    Ссылка: https://t.me/chat_dark_time

AnGel

Администратор
Команда форума

AnGel

Администратор
Команда форума
27 Авг 2015
3,411
2,025
Здарова, щеглы, сегодня мы своими руками будем писать скрипт на Python. Нам понадобятся: интерпретатор
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!
под "какая-там-у-вас-ОС", текстовый редактор с
Код:
import argparse
import logging
import coloredlogs
import ssl
 
import concurrent.futures
import urllib.request
 
from netaddr import IPNetwork
from collections import deque
 
 
VERSION = 0.1
 
 
def setup_args():
    parser = argparse.ArgumentParser(
        description = 'Domain Seeker v' + str(VERSION) + ' (c) Kaimi (kaimi.io)',
        epilog = '',
        formatter_class = argparse.ArgumentDefaultsHelpFormatter
    )
    parser.add_argument(
        '-d',
        '--domains',
        help = 'Domain list to discover',
        type = str,
        required = True
    )
    parser.add_argument(
        '-i',
        '--ips',
        help = 'IP list (ranges) to scan for domains',
        type = str,
        required = True
    )
    parser.add_argument(
        '--https',
        help = 'Check HTTPS in addition to HTTP',
        action = 'store_true'
    )
    parser.add_argument(
        '--codes',
        help = 'HTTP-codes list that will be considered as good',
        type = str,
        default = '200,301,302,401,403'
    )
    parser.add_argument(
        '--separator',
        help = 'IP/Domain/HTTP-codes list separator',
        type = str,
        default = ','
    )
    parser.add_argument(
        '--include',
        help = 'Show results containing provided string',
        type = str
    )
    parser.add_argument(
        '--exclude',
        help = 'Hide results containing provided string',
        type = str
    )
    parser.add_argument(
        '--agent',
        help = 'User-Agent value for HTTP-requests',
        type = str,
        default = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1'
    )
    parser.add_argument(
        '--http-port',
        help = 'HTTP port',
        type = int,
        default = 80
    )
    parser.add_argument(
        '--https-port',
        help = 'HTTPS port',
        type = int,
        default = 443
    )
    parser.add_argument(
        '--timeout',
        help = 'HTTP-request timeout',
        type = int,
        default = 5
    )
    parser.add_argument(
        '--threads',
        help = 'Number of threads',
        type = int,
        default = 2
    )
 
    args = parser.parse_args()
 
    return args
 
 
if __name__ == '__main__':
    main()
Ни одного комментария, какие-то import, непонятные аргументы командной строки и еще эти две последние строчки... Но будьте спокойны, все нормально, это я вам как мастер программирования на Python с 30-минутным стажем говорю. Тем более, как известно, Google не врет, а
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!
- это вообще неоспоримая истина.
Так что же мы все-таки сделали в вышеописанном фрагменте кода? Мы подключили модули для работы с аргументами коммандной строки, модули для логирования (
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!
между прочим!), модуль для работы с SSL (для одной мелочи, связанной с HTTPS-запросами), модуль для создания пула потоков, и, наконец, модули для совершения HTTP-запросов, работы с IP-адресами и двухсторонней очередью (по поводу различных типов импорта можно почитать
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!
).
После этого мы, в соответствии с
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!
, создали вспомогательную функцию, которая будет обрабатывать аргументы, переданные скрипту при запуске из командной строки. Как видите, в скрипте будет предусмотрена работа со списком доменов/IP-диапазонов, а также возможность фильтрации результатов по ключевым словам и по
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!
и еще пара мелочей, как, например, смена
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!
и опциональная проверка HTTPS-версии искомого ресурса. Последние две строки в основном используются для разделения кода, который будет выполнен при запуске самого скрипта и при импортировании в другой скрипт. В общем тут все сложно, все так пишут. Мы тоже так будем писать. Можно было бы немного модифицировать этот код, например, добавив возврат разных статусов системе в зависимости от того, как отработала функция main, добавить argv в качестве аргумента, и так далее, но мы изучаем Python только 10 минут и ленимся вчитываться в документацию.
Делаем перерыв и выпиваем глоток освежающей минеральной воды.
Поехали дальше.
Код:
def main():
    # Обрабатываем аргументы и инициализируем логирование
    # с блекджеком и цветными записями
    args = setup_args()
    coloredlogs.install()
 
    # Сообщаем бесполезную информацию, а также запускаем цикл проверки
    logging.info("Starting...")
    try:
        check_loop(args)
    except Exception as exception:
        logging.error(exception)
    logging.info("Finished")
 
 
def check_loop(args):
    # Создаем пул потоков, еще немного обрабатываем переданные аргументы
    # и формируем очередь заданий
    with concurrent.futures.ThreadPoolExecutor(max_workers = args.threads) as pool:
        domains = args.domains.split(args.separator)
        ips = args.ips.split(args.separator)
        codes = args.codes.split(args.separator)
 
        tasks = deque([])
        for entry in ips:
            ip_list = IPNetwork(entry)
            for ip in ip_list:
                for domain in domains:
                    tasks.append(
                        pool.submit(
                            check_ip, domain, ip, args, codes
                        )
                    )
        
        # Обрабатываем результаты и выводим найденные пары домен-IP
        for task in concurrent.futures.as_completed(tasks):
            try:
                result = task.result()
            except Exception as exception:
                logging.error(exception)
            else:
                if result != None:
                    data = str(result[0])
                    if(
                        ( args.exclude == None and args.include == None )
                        or
                        ( args.exclude and args.exclude not in data )
                        or
                        ( args.include and args.include in data )
                    ):
                        logging.critical("[+] " + args.separator.join(result[1:]))
В коде появился минимум комментариев. Это прогресс. Надо войти в кураж (не зря мы заготовили прамирацетам) и дописать одну единственную функцию, которая будет осуществлять, непосредственно, проверку. Ее имя уже упомянуто в коде выше: check_ip.
30 минут спустя
Хорошо-то как. Не зря я говорил, что понадобится час времени. Продолжим.
Код:
def check_ip(domain, ip, args, codes):
    # Преобразуем IP из числа в строку
    # Магическая code-flow переменная для совершения двух проверок
    # И бесполезное логирование
    ip = str(ip)
    check_https = False
 
    logging.info("Checking " + args.separator.join([ip, domain]))
 
    while True:
        # Задаем порт и схему для запроса в зависимости от магической переменной
        schema = 'https://' if check_https else 'http://';
        port = str(args.https_port) if check_https else str(args.http_port)
 
        request = urllib.request.Request(
            schema + ip + ':' + port + '/',
            data = None,
            headers = {
                'User-Agent': args.agent,
                'Host': domain
            }
        )
        # Совершаем запрос, и если получаем удовлетворительный код состояни HTTP,
        # то возвращаем содержимое ответа сервера, а также домен и IP
        try:
            response = urllib.request.urlopen(
                request,
                data = None,
                timeout = args.timeout,
                context = ssl._create_unverified_context()
            )
            data = response.read()
            return [data, ip, domain]
        except urllib.error.HTTPError as exception:
            if str(exception.code) in codes:
                data = exception.fp.read()
                return [data, ip, domain]
        except Exception:
            pass
 
        if args.https and not check_https:
            check_https = True
            continue
 
        return None
В общем-то весь наш скрипт готов. Приступаем к тестированию.
b6cd1b3ebc6be946d67972cddbb2e70b.jpeg
Неожиданно узнаем, что у блога есть альтернативный IP-адрес. И действительно:

Код:
curl -i 'http://188.226.181.47/' --header 'Host: kaimi.io'
Код:
HTTP/1.1 301 Moved Permanently
Server: nginx/1.4.6 (Ubuntu)
Date: Sun, 02 Oct 2016 13:52:43 GMT
Content-Type: text/html
Content-Length: 193
Connection: keep-alive
Location: https://kaimi.io/
 
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.4.6 (Ubuntu)</center>
</body>
</html>
Однако:
Код:
curl -i 'https://188.226.181.47/' --header 'Host: kaimi.io'
Код:
curl: (51) SSL: certificate subject name (*.polygraph.io) does not match target host name '188.226.181.47'
Какой-то левый хост обрабатывает запросы. Почему? Потому что это прокси, который реагирует на содержимое заголовка Host. В общем скрипт готов, по крайней мере альфа-версия скрипта. Если вам понравилось - подписывайтесь, ставьте лайки, шлите pull-реквесты на
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!
.
 

О нас

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

    Dark-Time 2015 - 2022

    При поддержке: XenForo.Info

Быстрая навигация

Меню пользователя