
42
Бро, тема горячая – квишинг (QR-code phishing) в 2026-м выстрелил так, что традиционные email-гейтвеи просто не видят угрозу: она спрятана в картинке. А сверху AI подкинул генерацию персонализированных пейлоадов и текстов, из-за чего атака стала масштабируемой как конвейер. Разберём механику, покажу код для детекта и дам чек-лист защиты – материал для образовательного контента, без готового боевого инструмента для атак на реальных людей.
Почему квишинг взлетел именно сейчас
Цифры говорят сами за себя – рост идёт лавинообразно, и это не хайп, а статистика от крупных вендоров.
| Метрика | Значение | Источник |
|---|---|---|
| Доля QR-кодов в фишинговых письмах (2025) | ~12% | Keepnet Labs / APWG |
| Рост квишинга в 2023 | +587% г/г | Keepnet Labs |
| Рост QR-фишинга Q1→Q1 2026 (Microsoft) | +146% (7.6М → 18.7М писем) | Microsoft Threat Intelligence |
| Уникальных вредоносных QR (Mimecast, Q3 2025) | 716 306 | APWG/Mimecast |
| Обнаружений вредоносных QR в день (Unit 42) | 11 000+ | Palo Alto Unit 42 |
| Скликивают QR без проверки (США) | 73% пользователей | NordVPN/CNBC |
| Целей — кража credential’ов | ~90% атак | Keepnet Labs |
Ключевая причина живучести атаки простая: email security gateway читает текст, а не пиксели. Ссылка спрятана внутри картинки QR-кода – SEG и антифишинг-фильтры на базе NLP её попросту не видят. Дальше жертва сканирует код телефоном – и уже вышла за периметр корпоративной защиты: нет EDR, нет secure web gateway, есть только личный смартфон и голый браузер.
Как AI меняет механику атаки
Раньше квишинг был “спрей”: одна и та же ссылка, один шаблон письма. Сейчас AI встроен на трёх уровнях конвейера атаки.
Генерация пейлоада и текста. LLM пишет уникальный текст для каждой жертвы – под её роль, компанию, стиль переписки. По данным decodeit, свыше 92% полиморфных фишинговых кампаний используют AI для генерации сотен контекстно-уникальных вариантов сообщения под одну кампанию. Это разбивает сигнатурный детект: каждое письмо технически “новое”.
Уклонение через вариативность изображения. Генеративные модели создают QR-коды с разным дизайном, вставляют логотип “легитимного” сервиса (банк, DocuSign, MFA-провайдер), меняют цвет, рамку, фон – так антиспам-модели, обученные на паттернах известных вредоносных QR, теряют якорь для классификации. Cyble обнаружил, что ~80% PDF с вредоносными QR-кодами при первом сканировании давали 0 детектов на VirusTotal.
Динамическая инфраструктура. AI-инструменты автоматизируют ротацию доменов и генерацию клон-страниц логина (AiTM-прокси), которые перехватывают не только пароль, но и сессионный токен/2FA-код в реальном времени.
Сценарий атаки, который сейчас реально встречается “в поле”: фишинговый PDF от “IT-отдела” с QR “для обновления MFA”, письмо написано LLM под стиль внутренней переписки компании, QR ведёт на AiTM-прокси Microsoft 365 логина – и всё это генерируется автоматически под каждую цель пачками через фишинг-кит as-a-service.
Детект своими руками: разбор QR перед сканом
Вот рабочий скрипт для образовательных целей – показывает, как декодировать QR-код и прогнать URL через базовые проверки (домен, редиректы, эвристики), прежде чем открывать в браузере. Логика ровно та, что используют defensive-инструменты типа QGuard.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
import re from urllib.parse import urlparse from pyzbar.pyzbar import decode from PIL import Image SUSPICIOUS_TLDS = {'.xyz', '.top', '.click', '.tk', '.zip'} URL_SHORTENERS = {'bit.ly', 'tinyurl.com', 'goo.gl', 't.co', 'is.gd'} def analyze_qr(image_path: str) -> dict: img = Image.open(image_path) decoded = decode(img) if not decoded: return {"status": "no_qr_found"} url = decoded[0].data.decode('utf-8') parsed = urlparse(url) domain = parsed.netloc.lower() flags = [] if any(domain.endswith(tld) for tld in SUSPICIOUS_TLDS): flags.append("suspicious_tld") if domain in URL_SHORTENERS: flags.append("shortened_url_hides_destination") if re.search(r'(login|verify|secure|account).*\.(?!com$)', domain): flags.append("brand_impersonation_pattern") if parsed.scheme != 'https': flags.append("no_tls") if len(domain.split('.')) > 3: flags.append("excessive_subdomains") return { "url": url, "domain": domain, "risk_score": len(flags), "flags": flags, "verdict": "BLOCK" if flags else "REVIEW" } |
Для боевого продукта сюда добавляется: проверка через VirusTotal/urlscan.io API, WHOIS-возраст домена (свежие домены – красный флаг), скрин целевой страницы headless-браузером для визуального сравнения с легитимным логином через perceptual hashing.
Чек-лист защиты, который реально закрывает дыру