Обфускация писем для обхода спам-фильтров

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
С добрым утром xss.is!
Сегодня я расскажу вам, как замутить софт, который поможет обфусцировать HTML-код электронных марекетинговых писем и обойти спам-фильтры и попасть с инбокс!
Так что запасайтесь кофе или чем покрепче, потому что мы погрузимся в детали: от идеи до архитектуры проекта, с пошаговым разбором кода и кучей примеров.

Что такое обфускация и зачем она нужна?​

Давайте начнем с основ. Обфускация - это когда мы берём понятный код и превращаем его в какую-то кашу, которую всё ещё можно исполнить, но разобрать её без боли в голове уже сложно. В нашем случае мы будем обфусцировать HTML-код писем. Зачем? Чтобы спам-фильтры не могли понять, что это за письмо, и пропускали его в "Входящие", а не в "Спам".
Спам-фильтры работают хитро: они ищут повторяющиеся паттерны - одинаковые куски текста, стили, ссылки или подозрительные элементы, а у гугла вообще спам фильтры обрабатывает их Gemini (я так предполагаю). Если вы отправляете тысячу одинаковых писем, фильтр быстро вычисляет шаблон и блокирует их. А вот если каждое письмо будет уникальным, то шансов проскочить у него намного больше.
Мой инструмент, который я назвал StealthHTML, как раз и делает это - генерирует уникальные версии HTML, сохраняя внешний вид и функциональность письма.
Представьте, что вы прячете своё письмо среди других писем, которые напоминают спам? Фильтру сложно вычислить, какое из них является спамом, и он решает: "Ладно, пропускай". Вот так мы и будем работать.

Основные техники обфускации​

Чтобы сделать каждое письмо уникальным, мы используем несколько приёмов. Вот список того, что умеет StealthHTML:
  1. Генерация случайного текста - добавляем рандомный текст из безопасных словарей (общий, технический, маркетинговый), чтобы письмо выглядело живым.
  2. Вставка невидимых символов - засовываем нулевые пробелы и другие невидимки, которые меняют код, но не видны глазу.
  3. Перемешивание стилей CSS - меняем местами свойства в стилях, чтобы запутать анализаторы.
  4. Случайные атрибуты и элементы - добавляем рандомные классы, ID, data-атрибуты и скрытые элементы.
  5. Рандомизация ссылок и изображений - кидаем случайные параметры в ссылки и вставляем невидимые картинки.
  6. Поддержка разных словарей - выбирайте, какие слова ближе к вашему контенту, либо дополняйте их самостоятельно.
  7. Настраиваемый уровень обфускации - регулируйте, насколько сильно запутать код.
Каждая из этих штук важна, и я разберу их все по полочкам с примерами.

Как это работает: техники в деталях​

1. Генерация случайного текста​

Первая фича - добавление случайного текста. Мы не будем просто пихать абракадабру вроде "dfgdfg", потому что это сразу вызовет подозрения. Вместо этого у нас есть словари с нормальными словами: общий (типа "news", "info"), технический ("server", "proxy") или маркетинговый ("sale", "offer"). Функция берёт случайные слова из словаря и лепит из них текст.
Пример: если выбрать маркетинговый словарь, получится что-то вроде "best deal today". Этот текст можно засунуть в скрытый <span> или комментарий, и он будет выглядеть как часть письма.

2. Вставка невидимых символов​

Тут настоящая магия. Есть такие Unicode-символы, как нулевой пробел (\u200B), которые не отображаются, но присутствуют в коде. Мы вставляем их в текст с какой-то вероятностью (например, 20%). Человек ничего не заметит, а для фильтра текст "hello" и "h\u200Be\u200Bl\u200Blo" - это две разные строки.
Пример:
  • До: <p>Hello world</p>
  • После: <p>Hell\u200Bo wo\u200Brld</p>

3. Перемешивание стилей CSS​

Спам-фильтры могут искать определённый порядок свойств в стилях, например, "color: red; font-size: 12px". Мы берём строку стилей и тасуем свойства местами. Рандомизация стилей - крайне важный шаг для попадания в инбокс.
Пример:
  • До: style="color: blue; margin: 10px; font-size: 14px"
  • После: style="font-size: 14px; color: blue; margin: 10px"

4. Случайные атрибуты и элементы​

Мы добавляем рандомные классы, ID или data-атрибуты к тегам. Ещё можем вставить скрытые <span> или <div> с display: none. Это запутывает структуру HTML.
Пример:
  • До: <p>Hello</p>
  • После: <p class="rnd123" data-info="xyz789">Hello<span style="display: none;">random text</span></p>

5. Рандомизация ссылок и изображений​

Ссылки вроде "
Example Domain

" могут быть одинаковыми во всех письмах, что выдаёт шаблон. Мы добавляем случайные параметры: "
Example Domain

". Плюс вставляем невидимые картинки с рандомными URL.
Пример:

6. Поддержка разных словарей​

Выбирайте словарь под задачу.
Маркетинговый - для рассылок, технический - для писем про софт. Это делает текст осмысленным и менее подозрительным, так как в почтовиках я всё чаще и чаще стал встречать проверку писем при помощи ИИ, так как подозрительно часто мои письма стали улетать в спам.

7. Настраиваемый уровень обфускации​

Хотите лёгкую обфускацию или полный разнос письма? Регулируйте параметры: сколько комментариев, элементов или символов добавлять, это крайне удобно.

Архитектура проекта​

Теперь к коду. StealthHTML написан на Python с использованием библиотеки BeautifulSoup для работы с HTML. Структура простая, но гибкая:
  • Словари - слова захардкоденные внутри файла. Можете добавить свои, либо использовать из списка (дополнить код не составит труда для вас).
  • Модуль обфускации - куча функций, каждая отвечает за свою технику.
  • Главная функция - собирает всё вместе и обрабатывает HTML.
  • CLI - интерфейс командной строки через argparse для удобства.
Входной файл (HTML) читается, проходит через все функции обфускации, и результат либо сохраняется, либо выводится в консоль (stdout).

Разбор кода пошагово​

Давайте заглянем внутрь, как оно выглядит на самом деле. Вот основные функции и как они работают.

Функция generate_random_text

Генерирует случайный текст из словаря.
Python: Скопировать в буфер обмена
Код:
import random

DICTIONARIES = {
    'general': [
        'news', 'update', 'info', 'alert', 'notice', 'message', 'reminder', 'notification',
        'report', 'summary', 'announcement', 'bulletin', 'memo', 'brief', 'digest', 'release',
        'statement', 'communication', 'dispatch', 'correspondence', 'letter', 'note', 'post',
        'article', 'piece', 'item', 'story', 'feature', 'column', 'editorial'
    ],
    'technical': [
        'code', 'system', 'data', 'network', 'server', 'software', 'hardware', 'update',
        'patch', 'bug', 'feature', 'release', 'version', 'protocol', 'interface', 'module',
        'function', 'algorithm', 'process', 'thread', 'query', 'database', 'backup', 'log',
        'monitor', 'config', 'deploy', 'test', 'build', 'compile'
    ],
    'marketing': [
        'offer', 'deal', 'sale', 'discount', 'promo', 'gift', 'bonus', 'special', 'event',
        'campaign', 'launch', 'product', 'service', 'brand', 'exclusive', 'limited', 'free',
        'trial', 'benefit', 'value', 'opportunity', 'package', 'subscription', 'plan',
        'feature', 'highlight', 'trend', 'news', 'update', 'announce'
    ]
}

def generate_random_text(min_words=2, max_words=5, dictionary='general'):
    count = random.randint(min_words, max_words)
    return ' '.join(random.choice(DICTIONARIES[dictionary]) for _ in range(count))

# Пример вызова
text = generate_random_text("marketing")  # "promo gift subscription"
Тут всё просто: открываем файл словаря, берём случайное число слов и склеиваем их в строку.

Функция insert_invisible_chars

Добавляет невидимые символы
Python: Скопировать в буфер обмена
Код:
def insert_invisible_chars(text, invisible_char_prob=0.15):
    invisible_chars = ['\u200B', '\u200C', '\u200D', '\uFEFF', '\u2060']
    result = ''
    for char in text:
        result += char
        if random.random() < invisible_char_prob:
            result += random.choice(invisible_chars)
    return result

print(insert_invisible_chars("hello", 0.2))  # "h\u200Bello"
Вероятность prob задаёт, как часто вставлять символы

Функция shuffle_styles

Перемешивает CSS-свойства.
Python: Скопировать в буфер обмена
Код:
def shuffle_styles(style_string):
    styles = [s.strip() for s in style_string.split(';') if s.strip()]
    random.shuffle(styles)
    return '; '.join(styles) + ';'

# Пример
style = "color: red; font-size: 12px; margin: 5px"
print(shuffle_styles(style))  # "margin: 5px; color: red; font-size: 12px"
Разделяем строку по точке с запятой, тасуем и собираем обратно.

Функция insert_random_hidden_element

Добавляет скрытый элемент.
Python: Скопировать в буфер обмена
Код:
def insert_random_hidden_element(soup, dictionary='general'):
    hidden_span = soup.new_tag('span', style='font-size:0px; display:inline;')
    hidden_span.string = generate_random_text(1, 3, dictionary)
    hidden_span['class'] = generate_random_class()
    hidden_span['id'] = generate_random_class()
    hidden_span[f'data-{generate_random_class()}'] = str(random.randint(0, 1000))
    return hidden_span

# Пример
soup = BeautifulSoup("<body><p>Hi</p></body>", "html.parser")
soup = insert_random_hidden_element(soup, "general")
print(soup)  # <body><p>Hi</p><span style="font-size:0px; display:inline;">news info</span></body>

Создаём <span> с display: none и random текстом.

Главная функция generate_emails

Собирает всё вместе.
Её код вставлять не буду, можете посмотреть в полных исходниках.

Так же происходит работа с хедерами, редкими тегами и прочим добром по анологии с кусками кода выше

Как использовать​

Запускаем из командной строки:
Bash: Скопировать в буфер обмена
./generate_emails.py 1.html
и получаем вывод в stdout, либо если надо в файл, то:
Bash: Скопировать в буфер обмена
./generate_emails.py 1.html -o 1_obfuscated.html
и получаем 1_obfuscated.html письмо.
Вот все доступные на момент написания статьи аргументы:
Код: Скопировать в буфер обмена
Код:
./generate_emails.py -h
usage: generate_emails.py [-h] [-o OUTPUT] [--min_words MIN_WORDS] [--max_words MAX_WORDS] [--invisible_char_prob INVISIBLE_CHAR_PROB] [--span_prob SPAN_PROB]
                          [--comment_count COMMENT_COUNT] [--meta_count META_COUNT] [--table_count TABLE_COUNT] [--style_count STYLE_COUNT]
                          [--image_count IMAGE_COUNT] [--script_count SCRIPT_COUNT] [--rare_tag_count RARE_TAG_COUNT] [--header_count HEADER_COUNT]
                          [--dictionary {general,technical,marketing}]
                          input_file

Generator of randomized HTML emails to bypass spam filters

positional arguments:
  input_file            Path to the input HTML file

options:
  -h, --help            show this help message and exit
  -o, --output OUTPUT   Output file path (default: - for stdout)
  --min_words MIN_WORDS
                        Minimum number of words in generated text (default: 2)
  --max_words MAX_WORDS
                        Maximum number of words in generated text (default: 5)
  --invisible_char_prob INVISIBLE_CHAR_PROB
                        Probability of inserting an invisible character (default: 0.15)
  --span_prob SPAN_PROB
                        Probability of inserting a span tag (default: 0.4)
  --comment_count COMMENT_COUNT
                        Number of random comments (default: 1)
  --meta_count META_COUNT
                        Number of random meta tags (default: 1)
  --table_count TABLE_COUNT
                        Number of random tables (default: 1)
  --style_count STYLE_COUNT
                        Number of random styles (default: 1)
  --image_count IMAGE_COUNT
                        Number of random images (default: 1)
  --script_count SCRIPT_COUNT
                        Number of random scripts (default: 1)
  --rare_tag_count RARE_TAG_COUNT
                        Number of random rare tags (default: 1)
  --header_count HEADER_COUNT
                        Number of random headers (default: 1)
  --dictionary {general,technical,marketing}
                        Dictionary for text generation (default: general)

Спам-фильтры на ИИ и пара слов напоследок​

Основные фишки​

Спам-фильтры - это дотошные методы, которые лазают по всему коду писем (HTML, заголовки - всё подряд), выискивая подозрительные моменты. Если в письме куча одинакового текста, стилей или ссылок, которые выглядят как "привет от спамеров", - оно тут же улетает в папку "Спам". И это не просто "ой, тут ссылка", а глубокий разбор, как будто письмо под микроскоп кладут.
Я сам проверял, как это работает, и могу сказать: современные фильтры, особенно у Gmail, прям на стероидах от искусственного интеллекта (ИИ). Они используют машинное обучение, чтобы следить не только за кодом, но и за тем, как люди реагируют на письма - открывают их, игнорят или сразу в мусорку кидают. ИИ прям вынюхивает контекст: откуда письмо, кому, как часто ты такие шлёшь. Короче, прогресс дошёл до того, что эти штуки стали умнее, чем многие спамеры.
Но тут прикол: ИИ в спам-фильтрах (в том же Gmail) ещё и подстраивается под всякие хитрые трюки, типа обфускации кода. Обход становится сложнее, но всё ещё реально.
Но скоро думаю будет так: ты замаскировал письмо, поменял HTML, чтобы фильтр не спалил. Раньше это прокатывало, но теперь ИИ такой: "Хм, а почему юзеры это не открывают? Давай-ка в спам!" Так что, чтобы пробиться в "инбокс", мало код запутать - надо ещё, чтобы люди твои письма любили и открывали. Но пока обфускация HTML и парочка хитростей спасают.
Так что, пока работает, пользуемся на полную.
Небольшой пруф про ИИ:
1740909834820.png


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


КатегорияФакторОписаниеЧто менять
Анализ кодаСтруктура HTMLФильтры ищут подозрительные элементы (скрытый текст, избыток тегов)Упростить HTML, убрать скрытые элементы, использовать стандартные структуры
Анализ кодаИспользование CSSЧрезмерное использование inline-стилей или странные паттерны CSSСократить inline-CSS
Анализ кодаПрисутствие JavaScriptJavaScript в письмах часто воспринимается как спам или угрозаНе вставлять JavaScript в письма
Анализ кодаСоотношение текста и изображенийВысокое соотношение изображений к тексту - сигнал спамаДобавить больше текста, сбалансировать с картинками
Анализ кодаСокращенные ссылкиВсякие сократители ссылок могут выглядеть как попытка скрыть вредоносные ссылкиИспользовать полные ссылки или брендированные короткие URL
Анализ кодаВстроенные формыФормы в письмах ассоциируются с фишингом и блокируютсяНе встраивать формы, перенаправлять на внешние страницы
Анализ кодаИспользование IframeIframe может загружать внешний контент, что вызывает подозренияИзбегать iframe в письмах
Анализ кодаТрюки с шрифтами и цветамиСкрытый текст (например, белый на белом) - частый прием спамеровУбедиться, что текст читаем и соответствует фону
Анализ кодаКомментарии в HTMLМного подозрительных комментариев могут быть флагомУбрать лишние комментарии или сделать их естественными
Анализ через ИИСходство контентаИИ сравнивает контент с известными спам-кампаниямиСоздавать уникальный контент для каждой рассылки
Анализ через ИИЯзыковые шаблоныСлова вроде "срочно", "бесплатно" или избыточные предложения флагятсяИспользовать естественный язык, избегать триггер-слов
Анализ через ИИПерсонализацияОтсутствие персонализации выдает массовую рассылкуДобавлять имена получателей или другие персональные данные
Анализ через ИИАнализ тональностиСлишком позитивный или негативный тон может быть подозрительнымДержать нейтральный или умеренно позитивный тон
Анализ через ИИТематическая классификацияТемы вроде денег или здоровья часто флагятся как спамМаскировать тему или избегать типичных спам-тем
Анализ через ИИОбнаружение аномалийИИ ищет отклонения от "нормальных" писемКопировать структуру легитимных писем

Анализ через ИИ
Анализ изображенийИИ проверяет картинки на спам-контент или скрытый текстИспользовать релевантные изображения без скрытых элементов
Анализ через ИИАнализ вложенийВложения проверяются на вирусы или подозрительные типы файловИзбегать вложений или использовать безопасные форматы
Поведение отправителяЧастота отправкиСлишком частые письма от одного отправителя флагятсяОграничить частоту или варьировать временные промежутки
Поведение отправителяРепутация IPПлохая репутация IP-адреса увеличивает шанс попадания в спамИспользовать чистые IP и менять их
Поведение отправителяВозраст доменаНовые домены вызывают больше подозренийИспользовать старые домены или наращивать репутацию новых
Поведение отправителяАутентификация (SPF, DKIM, DMARC)Отсутствие настройки ведет к классификации как спамНастроить SPF, DKIM, DMARC корректно
Поведение отправителяПроцент отказовВысокий bounce rate говорит о плохом качестве спискаОчищать список, использовать только валидные адреса
Поведение отправителяИсточник спискаКупленные или украденные списки чаще попадают в спамИспользовать только opt-in списки с согласием получателей
Поведение отправителяВремя отправкиОтправка в странное время (ночью) может быть подозрительнойОтправлять в рабочее время
Поведение получателяПроцент открытийНизкий процент открытий говорит о неинтересном или спам-контентеУлучшить заголовки и контент для роста открытий
Поведение получателяКлики по ссылкамНизкий CTR показывает, что контент не цепляетДобавить сильные призывы к действию и интересный контент
Поведение получателяПроцент отписокВысокий уровень отписок сигнализирует о нежелательности писемДать ценный контент и простой способ отписки
Поведение получателяЖалобы на спамЖалобы напрямую портят репутацию отправителяУбедиться, что письма релевантны и получатели согласны их получать
Поведение получателяВремя взаимодействияКороткое время чтения указывает на низкий интересСоздавать контент, который удерживает внимание
Поведение получателяПересылка писемРедкая пересылка может говорить о недоверии к письмуДобавить контент, которым хочется делиться
Поведение получателяОтветы на письмаНизкий уровень ответов указывает на отсутствие доверия (за исключением no-reply)Включать вопросы или призывы к ответам

Идеи для улучшений кода​

  1. Словари:
    1. Добавить поддержку словарей из файлов
    2. Добавить поддержку словарей из других языков
    3. Добавить поддержку словарей фраз по цепям маркова, чтобы генерировать осмысленные тексты
  2. Более хитрые техники, вроде изменения структуры DOM:
    1. Оборачивание элеметов в дополнительные теги со стилями, которые не меняют внешний вид
    2. Добавление более сложных конструкций в тело письма, безопасных невидимых ссылок из серии ссылок на гугл поиск, либо на ответы гугл
  3. Ну и любые другие изменения
Принимаю все изменения в код на гитхабе)
Публикую полный код тут https://github.com/keklick1337/StealthHTML , так что берите и используйте. Отпишите по инбоксу, интересно как работает с вашими задчами.
Так же код может ломать в некоторых случаях визуальный вид письма, об этих багах тоже сообщайте с примерами минимальными писем, буду исправлять по возможности.

Автор: keklick1337
Специально для xss.is
 
Сверху Снизу