Initial commit - 611 cybersecurity skills across all subdomains

This commit is contained in:
mukul975
2026-02-25 10:47:44 +01:00
commit 22a7ab1462
1765 changed files with 280648 additions and 0 deletions
@@ -0,0 +1,93 @@
---
name: detecting-qr-code-phishing-with-email-security
description: Detect and prevent QR code phishing (quishing) attacks that bypass traditional email security by embedding malicious URLs in QR code images within emails.
domain: cybersecurity
subdomain: phishing-defense
tags: [quishing, qr-code, phishing, email-security, image-analysis, ocr, mobile-security]
version: "1.0"
author: mahipal
license: MIT
---
# Detecting QR Code Phishing with Email Security
## Overview
QR code phishing (quishing) is a rapidly growing attack vector where malicious URLs are embedded in QR code images within phishing emails. Quishing incidents grew fivefold from 46,000 to 250,000 between August and November 2025, with credential phishing comprising 89.3% of detected incidents. Traditional email security filters struggle because QR codes cannot be read by humans or standard URL scanners, and when scanned, users typically use personal mobile devices that lack corporate security controls. Attackers have evolved to use split QR codes (two separate images), nested QR codes, and ASCII text-based QR codes to evade detection.
## Prerequisites
- Email security gateway with image analysis capabilities
- Understanding of QR code structure and encoding
- Mobile device management (MDM) or mobile threat defense solution
- Security awareness training program
- SIEM platform for correlation and alerting
## Key Concepts
### Why Quishing Works
1. **Bypasses URL Scanners**: Traditional gateways scan text-based URLs but cannot decode image-embedded URLs
2. **Shifts to Unprotected Devices**: Corporate email arrives on secured systems but QR scan occurs on personal mobile devices
3. **User Trust**: QR codes are normalized in daily life (payments, menus, parking)
4. **Low Detection Rate**: Only 36% of quishing incidents are accurately identified by recipients
### Evasion Techniques (2025)
- **Split QR Codes**: QR code divided into two separate images that look benign individually (Gabagool PhaaS kit)
- **Nested QR Codes**: QR code within a QR code, with first scan leading to intermediate page
- **ASCII QR Codes**: QR rendered as text characters instead of images, bypassing image analysis (12% of attacks in Jan 2026)
- **Styled/Artistic QR Codes**: Custom-designed QR codes with logos that evade pattern matching
- **PDF Attachment QR**: QR code embedded in PDF attachment rather than email body
### Detection Challenges
- Pattern-based detection faces trade-off: aggressive tuning causes false positives, cautious tuning causes misses
- Average similarity score of 0.209 between quishing and legitimate QR emails
- QR codes in image attachments require OCR and deep image processing
## Implementation Steps
### Step 1: Enable Image-Based Threat Detection
- Configure email gateway to scan embedded images for QR codes
- Enable OCR processing on image attachments (PNG, JPG, GIF, BMP)
- Deploy multimodal AI that combines image processing, OCR, and NLP analysis
- Configure PDF scanning to detect QR codes within attachments
- Set up detection for ASCII/text-based QR code rendering
### Step 2: Configure QR Code URL Analysis
- Extract URLs from detected QR codes and submit to URL reputation services
- Apply same URL scanning policies to QR-extracted URLs as text-based URLs
- Enable real-time sandbox analysis for QR-decoded destination pages
- Configure time-of-click protection for QR-extracted URLs where possible
- Block known phishing domains extracted from QR codes
### Step 3: Deploy Mobile-Side Protection
- Implement mobile threat defense (MTD) with QR code scanning capability
- Deploy Palo Alto ALFA or equivalent safe-by-design QR scanning
- Configure MDM policies to warn users before opening scanned URLs
- Enable corporate VPN/secure browser for QR-scanned destinations
- Block known credential harvesting domains at the mobile proxy level
### Step 4: Build Detection Rules
- Alert on emails containing only an image and minimal text (common quishing pattern)
- Flag emails with QR code images from external first-time senders
- Detect urgency language combined with QR code presence
- Alert on emails impersonating IT/security team requesting QR scan for MFA setup
- Monitor for common quishing themes: MFA reset, document signing, voicemail notification
### Step 5: Train Users on Quishing Recognition
- Update security awareness program to include QR code phishing scenarios
- Conduct quishing simulation campaigns using controlled QR codes
- Teach users to verify QR destination URLs before entering credentials
- Establish reporting process for suspicious QR code emails
- Distribute guidance on safe QR scanning practices
## Tools & Resources
- **Barracuda Multimodal AI**: OCR + deep image processing for QR detection
- **Palo Alto ALFA**: Safe-by-design QR code scanning assessment
- **Microsoft Defender for O365**: QR code detection in email images
- **Proofpoint TAP**: Image-based threat analysis with QR decoding
- **Lookout/Zimperium**: Mobile threat defense with QR scanning
## Validation
- QR code phishing emails detected in controlled testing
- Split QR code and ASCII QR code evasion techniques caught
- QR-extracted URLs submitted to sandbox analysis
- Mobile devices alert on malicious QR destinations
- User reporting rate for quishing simulations exceeds 50%
- False positive rate for QR detection below 1%
@@ -0,0 +1,35 @@
# QR Code Phishing Detection Template
## Quishing Detection Rules
| Rule | Condition | Action | Status |
|---|---|---|---|
| QR in image | QR code detected in embedded image | Extract URL + analyze | |
| QR in PDF | QR code detected in PDF attachment | Extract URL + analyze | |
| ASCII QR | Text-rendered QR code pattern | Decode + analyze | |
| Image-only email | Email with image but minimal text | Flag for review | |
| MFA QR theme | QR + MFA/authentication language | High priority alert | |
## Common Quishing Themes to Monitor
- [ ] MFA enrollment requiring QR code scan
- [ ] Document signing via QR code
- [ ] Voicemail access via QR code
- [ ] Package delivery confirmation QR
- [ ] IT security update with QR authentication
- [ ] Shared document access via QR
## Mobile Protection Controls
- [ ] Mobile threat defense deployed with QR scanning
- [ ] MDM policy warns before opening QR URLs
- [ ] Corporate VPN required for QR destinations
- [ ] User training on safe QR scanning completed
## Incident Response for Quishing
| Step | Action | Responsible |
|---|---|---|
| 1 | Decode QR and extract URL | SOC Analyst |
| 2 | Check if URL is active phishing page | SOC Analyst |
| 3 | Search for same email across all mailboxes | Email Admin |
| 4 | Retract email from all recipients | Email Admin |
| 5 | Block URL at web proxy/firewall | Network Security |
| 6 | Check if any user scanned and submitted credentials | SOC Lead |
| 7 | Force password reset for affected users | IAM Team |
@@ -0,0 +1,39 @@
# Standards & References: Detecting QR Code Phishing
## Industry Statistics (2025-2026)
- Quishing incidents grew from 46,000 to 250,000 between Aug-Nov 2025 (Kaspersky)
- 89.3% of QR code phishing targets credential theft
- 12% of January 2026 attacks used ASCII text-based QR codes
- Only 36% of quishing incidents accurately identified by recipients
- 25% year-over-year growth in quishing incidents
## MITRE ATT&CK References
- **T1566.001**: Phishing: Spearphishing Attachment (QR in PDF/image)
- **T1566.002**: Phishing: Spearphishing Link (QR-encoded URL)
- **T1204.001**: User Execution: Malicious Link (user scans QR)
- **T1598.003**: Phishing for Information: Spearphishing Link
## Quishing Attack Patterns
| Pattern | Description | Detection Difficulty |
|---|---|---|
| Inline QR image | QR code embedded directly in email body | Medium |
| PDF attachment QR | QR code inside attached PDF document | High |
| Split QR code | QR divided into two benign-looking images | Very High |
| ASCII QR code | QR rendered as text characters | Very High |
| Nested QR code | QR within QR with intermediate redirect | High |
| Styled QR code | Artistic QR with logos/colors | Medium |
## Common Quishing Themes
- MFA enrollment/reset requiring QR scan
- Document signing via QR code
- Voicemail notification with QR access
- Package delivery QR confirmation
- IT security update requiring QR authentication
- Shared document access via QR
## Detection Technologies
- Multimodal AI (OCR + deep image + NLP)
- Computer vision QR code detection
- URL reputation analysis for decoded URLs
- Mobile threat defense QR scanning
- Behavioral analysis of image-only emails
@@ -0,0 +1,95 @@
# Workflows: Detecting QR Code Phishing
## Workflow 1: QR Code Email Detection Pipeline
```
Inbound email arrives at gateway
|
v
[Standard text/URL scanning]
+-- Check text-based URLs (standard pipeline)
+-- No malicious URLs found in text
|
v
[Image analysis module]
+-- Scan all embedded images and attachments
+-- Apply QR code detection algorithm
+-- Check for ASCII/text-rendered QR codes
+-- Scan PDF attachments for embedded QR codes
|
v
[QR code detected?]
+-- NO --> Continue standard delivery
+-- YES --> Extract encoded URL
|
v
[URL reputation and analysis]
+-- Check URL against threat intelligence feeds
+-- Check domain age and registration data
+-- Submit to sandbox for real-time analysis
+-- Check for credential harvesting indicators
|
v
[Decision]
+-- MALICIOUS URL: Block email, alert SOC
+-- SUSPICIOUS URL: Quarantine, add warning banner
+-- UNKNOWN URL: Tag email with QR warning banner
+-- CLEAN URL: Deliver with informational banner
```
## Workflow 2: Quishing Incident Response
```
User reports QR code phishing email
|
v
[Triage (15 minutes)]
+-- Extract QR code and decode URL
+-- Check if URL is active credential harvester
+-- Search mailboxes for same email to other recipients
|
v
[Containment]
+-- Block sender domain across email gateway
+-- Retract email from all recipient inboxes
+-- Block decoded URL at web proxy/firewall
+-- If user scanned: check for credential compromise
|
v
[Investigation]
+-- Did any user submit credentials on phishing page?
+-- Check authentication logs for compromised accounts
+-- If credentials entered: force password reset + revoke sessions
+-- Review phishing page infrastructure
|
v
[Recovery and prevention]
+-- Add QR URL pattern to detection rules
+-- Update security awareness training
+-- Send targeted alert to affected users
+-- Document IOCs for threat intelligence sharing
```
## Workflow 3: Mobile QR Scanning Protection
```
User scans QR code with mobile device
|
v
[Mobile threat defense intercepts]
+-- Decode QR destination URL
+-- Check against mobile threat intelligence
|
v
[URL assessment]
+-- KNOWN MALICIOUS: Block and alert user
+-- SUSPICIOUS: Display warning, require confirmation
+-- CREDENTIAL PAGE: Extra warning about entering passwords
+-- CLEAN: Allow access
|
v
[If user proceeds to suspicious site]
+-- Route through secure browser/VPN
+-- Monitor for credential submission
+-- Log URL and user action for SOC review
```
@@ -0,0 +1,341 @@
#!/usr/bin/env python3
"""
QR Code Phishing (Quishing) Detection Engine
Detects QR codes in images and email content, extracts encoded URLs,
and checks them against known phishing indicators.
Usage:
python process.py scan-image --image qr_image.png
python process.py scan-email --eml-file message.eml
python process.py check-url --url "https://example.com/login"
"""
import argparse
import json
import re
import sys
import base64
from dataclasses import dataclass, field, asdict
from urllib.parse import urlparse
try:
from PIL import Image
HAS_PIL = True
except ImportError:
HAS_PIL = False
try:
from pyzbar.pyzbar import decode as qr_decode
HAS_PYZBAR = True
except ImportError:
HAS_PYZBAR = False
@dataclass
class QRCodeFinding:
"""A detected QR code and its analysis."""
source: str = ""
decoded_url: str = ""
domain: str = ""
is_suspicious: bool = False
risk_score: int = 0
indicators: list = field(default_factory=list)
@dataclass
class QuishingAnalysis:
"""Complete quishing analysis result."""
source_file: str = ""
qr_codes_found: int = 0
findings: list = field(default_factory=list)
email_indicators: list = field(default_factory=list)
overall_risk: str = "low"
recommended_action: str = ""
# Suspicious URL patterns for credential phishing
SUSPICIOUS_URL_PATTERNS = [
r'login|signin|sign-in|log-in',
r'verify|verification|validate',
r'account|password|credential',
r'microsoft|office365|outlook|sharepoint',
r'google|gmail|workspace',
r'secure|security|auth',
r'update|confirm|suspend',
r'\.tk$|\.ml$|\.ga$|\.cf$|\.gq$',
r'bit\.ly|tinyurl|t\.co|is\.gd|cutt\.ly',
]
# Known phishing infrastructure patterns
PHISHING_INFRA_PATTERNS = [
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', # IP address URLs
r'[a-z0-9]{20,}\.web\.app', # Firebase hosting abuse
r'[a-z0-9]{20,}\.netlify\.app', # Netlify abuse
r'[a-z0-9-]+\.glitch\.me', # Glitch abuse
r'[a-z0-9-]+\.workers\.dev', # Cloudflare workers abuse
]
# Common quishing email indicators
QUISHING_EMAIL_PATTERNS = [
r'scan\s+(this|the)\s+qr\s+code',
r'scan\s+to\s+(verify|authenticate|confirm|access)',
r'multi.?factor\s+authentication',
r'mfa\s+(setup|enrollment|reset|update)',
r'voicemail\s+(notification|message)',
r'document\s+(sign|signing|review)',
r'security\s+update\s+required',
r'action\s+required',
]
def analyze_url(url: str) -> QRCodeFinding:
"""Analyze a URL extracted from a QR code for phishing indicators."""
finding = QRCodeFinding(decoded_url=url)
try:
parsed = urlparse(url)
finding.domain = parsed.netloc
except Exception:
finding.indicators.append("Could not parse URL")
finding.is_suspicious = True
finding.risk_score = 50
return finding
score = 0
# Check suspicious URL patterns
url_lower = url.lower()
for pattern in SUSPICIOUS_URL_PATTERNS:
if re.search(pattern, url_lower):
finding.indicators.append(f"Suspicious URL pattern: {pattern}")
score += 15
# Check phishing infrastructure patterns
for pattern in PHISHING_INFRA_PATTERNS:
if re.search(pattern, url_lower):
finding.indicators.append(f"Known phishing infrastructure pattern: {pattern}")
score += 25
# Check for URL shorteners (hiding true destination)
shorteners = ['bit.ly', 'tinyurl.com', 't.co', 'is.gd', 'cutt.ly',
'rebrand.ly', 'ow.ly', 'buff.ly']
if finding.domain in shorteners:
finding.indicators.append(f"URL shortener detected: {finding.domain}")
score += 20
# Check for IP address URL
if re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', finding.domain):
finding.indicators.append("URL uses IP address instead of domain name")
score += 30
# Check for excessive subdomains (common in phishing)
subdomain_count = finding.domain.count('.')
if subdomain_count > 3:
finding.indicators.append(f"Excessive subdomains ({subdomain_count})")
score += 15
# Check for homoglyph characters in domain
non_ascii = [c for c in finding.domain if ord(c) > 127]
if non_ascii:
finding.indicators.append("Non-ASCII characters in domain (possible homoglyph)")
score += 25
# Check protocol
if not url.startswith('https://'):
finding.indicators.append("URL does not use HTTPS")
score += 10
finding.risk_score = min(score, 100)
finding.is_suspicious = score >= 30
return finding
def scan_image_for_qr(image_path: str) -> list:
"""Scan an image file for QR codes and extract URLs."""
findings = []
if not HAS_PIL:
print("Pillow not installed. Install with: pip install Pillow", file=sys.stderr)
return findings
if not HAS_PYZBAR:
print("pyzbar not installed. Install with: pip install pyzbar", file=sys.stderr)
return findings
try:
img = Image.open(image_path)
decoded_objects = qr_decode(img)
for obj in decoded_objects:
data = obj.data.decode('utf-8', errors='replace')
if data.startswith(('http://', 'https://', 'www.')):
url = data if data.startswith('http') else f'https://{data}'
finding = analyze_url(url)
finding.source = image_path
findings.append(finding)
else:
finding = QRCodeFinding(
source=image_path,
decoded_url=data,
indicators=["QR code contains non-URL data"],
risk_score=10
)
findings.append(finding)
except Exception as e:
print(f"Error scanning image: {e}", file=sys.stderr)
return findings
def scan_email_content(eml_content: str) -> QuishingAnalysis:
"""Analyze email content for quishing indicators."""
analysis = QuishingAnalysis()
body_lower = eml_content.lower()
# Check for quishing email patterns
for pattern in QUISHING_EMAIL_PATTERNS:
if re.search(pattern, body_lower):
analysis.email_indicators.append(f"Quishing language pattern: {pattern}")
# Check for image-heavy email with minimal text
text_content = re.sub(r'<[^>]+>', '', eml_content)
text_content = re.sub(r'\s+', ' ', text_content).strip()
has_images = bool(re.search(r'<img|Content-Type:\s*image/', eml_content, re.IGNORECASE))
text_words = len(text_content.split())
if has_images and text_words < 50:
analysis.email_indicators.append(
"Image-heavy email with minimal text (common quishing pattern)"
)
# Check for base64-encoded images
b64_images = re.findall(
r'Content-Type:\s*image/\w+.*?Content-Transfer-Encoding:\s*base64\s*\n\n([\w+/=\n]+)',
eml_content, re.DOTALL | re.IGNORECASE
)
if b64_images and HAS_PIL and HAS_PYZBAR:
for i, b64_data in enumerate(b64_images):
try:
clean_data = b64_data.replace('\n', '')
img_bytes = base64.b64decode(clean_data)
import io
img = Image.open(io.BytesIO(img_bytes))
decoded = qr_decode(img)
for obj in decoded:
data = obj.data.decode('utf-8', errors='replace')
if data.startswith(('http://', 'https://')):
finding = analyze_url(data)
finding.source = f"embedded_image_{i}"
analysis.findings.append(finding)
analysis.qr_codes_found += 1
except Exception:
continue
# Calculate overall risk
indicator_count = len(analysis.email_indicators)
has_suspicious_qr = any(f.is_suspicious for f in analysis.findings)
if has_suspicious_qr and indicator_count >= 2:
analysis.overall_risk = "critical"
analysis.recommended_action = "BLOCK and alert SOC"
elif has_suspicious_qr or indicator_count >= 3:
analysis.overall_risk = "high"
analysis.recommended_action = "QUARANTINE for manual review"
elif indicator_count >= 1:
analysis.overall_risk = "medium"
analysis.recommended_action = "TAG with QR phishing warning banner"
else:
analysis.overall_risk = "low"
analysis.recommended_action = "DELIVER normally"
return analysis
def format_report(analysis: QuishingAnalysis) -> str:
"""Format analysis as readable report."""
lines = []
lines.append("=" * 60)
lines.append(" QR CODE PHISHING (QUISHING) ANALYSIS REPORT")
lines.append("=" * 60)
lines.append(f" QR Codes Found: {analysis.qr_codes_found}")
lines.append(f" Overall Risk: {analysis.overall_risk.upper()}")
lines.append(f" Action: {analysis.recommended_action}")
if analysis.email_indicators:
lines.append(f"\n [EMAIL INDICATORS] ({len(analysis.email_indicators)})")
for i, ind in enumerate(analysis.email_indicators, 1):
lines.append(f" {i}. {ind}")
if analysis.findings:
lines.append(f"\n [QR CODE FINDINGS] ({len(analysis.findings)})")
for i, finding in enumerate(analysis.findings, 1):
lines.append(f" {i}. URL: {finding.decoded_url}")
lines.append(f" Domain: {finding.domain}")
lines.append(f" Risk Score: {finding.risk_score}/100")
lines.append(f" Suspicious: {'YES' if finding.is_suspicious else 'No'}")
for ind in finding.indicators:
lines.append(f" - {ind}")
lines.append("=" * 60)
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="QR Code Phishing Detection")
subparsers = parser.add_subparsers(dest="command")
img_parser = subparsers.add_parser("scan-image", help="Scan image for QR codes")
img_parser.add_argument("--image", required=True)
eml_parser = subparsers.add_parser("scan-email", help="Scan email for quishing")
eml_parser.add_argument("--eml-file", required=True)
url_parser = subparsers.add_parser("check-url", help="Check URL from QR code")
url_parser.add_argument("--url", required=True)
parser.add_argument("--json", action="store_true")
args = parser.parse_args()
if args.command == "scan-image":
findings = scan_image_for_qr(args.image)
analysis = QuishingAnalysis(
source_file=args.image,
qr_codes_found=len(findings),
findings=findings
)
if args.json:
print(json.dumps(asdict(analysis), indent=2))
else:
print(format_report(analysis))
elif args.command == "scan-email":
with open(args.eml_file, 'r', errors='replace') as f:
content = f.read()
analysis = scan_email_content(content)
analysis.source_file = args.eml_file
if args.json:
print(json.dumps(asdict(analysis), indent=2))
else:
print(format_report(analysis))
elif args.command == "check-url":
finding = analyze_url(args.url)
if args.json:
print(json.dumps(asdict(finding), indent=2))
else:
print(f"URL: {finding.decoded_url}")
print(f"Domain: {finding.domain}")
print(f"Risk Score: {finding.risk_score}/100")
print(f"Suspicious: {'YES' if finding.is_suspicious else 'No'}")
for ind in finding.indicators:
print(f" - {ind}")
else:
parser.print_help()
if __name__ == "__main__":
main()