Scanning malicious websites with 'infinite' number of VPN tunnels (Part 2)
(Part 1 here)
Vibe Coded Tunnel Tool
Claude Fable was released while I was experimenting with VPN tunnels. I decided to test its capability by having it plan and implement a tunnel management application…At least that was the plan, until Fable refused to help due to networking=cybersecurity. I tried to be diplomatic and tried the recommended method:
From then on, the rest of the tool was vibe coded by Opus 4.8 + Qwen 3.5.
The installation step is not complex, but I recommend letting your favorite LLM agent install the application on your test system. Note that my test system’s LAN ip is 192.168.1.106, and I might have missed removing the hard coded reference in a few locations. Just ask your LLM to clean that up.
Demo usage: Scanning phishing URLs
To quickly test the tunnels, I needed a way to batch-scan large amount of URLs. Since I don’t work for a security firm anymore, I don’t have access to live malicious URL feeds.
A quick search shows 2 open intelligence feeds for live phishing websites-
https://phishstats.info/
https://phishunt.io/
Both sites provide APIs to retrieve live phishing URLs. I asked my LLM agents to use these APIs and build an automated website scanners.
Note that this is only a demo application. I didn’t bother removing any of the hardcoded references from the application.
Architecture
┌───────────────────────────────────────────────┐
│ VPN Host (192.168.1.106) │
│ one network namespace per country: │
│ vpn-tw vpn-sg vpn-nl vpn-kr vpn-jp │
└───────────────────────────────────────────────┘
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
Taiwan Singapore Neth. S.Korea Japan
Each namespace has its own WireGuard tunnel exiting a different country. A headless Playwright/Chromium browser runs inside each namespace, so all traffic for a test exits from that country. South Korea (kr) is the baseline every other location is compared against.
I decided to use South Korea as the baseline, due to them being the recipient of many specialized attacks in my experience.
The application would retrieve the latest URLs. For each URL, the scanner would use each of the 5 tunnels to visit each URL using Playwright. The scanner would gather the information from Playwright and save the result. Finally after all 5 tunnels are tested, the scanner would compare the data saved and see if there is any difference between accessing from different tunnels. Differences are calculated by using exact and fuzzy hashes.
===============================================================================
Website Geo Comparison - Parallel Execution
===============================================================================
[INFO] 2026-07-03 17:46:45 Verifying VPN namespaces...
[✓] 2026-07-03 17:46:49 All 5 namespaces healthy
[INFO] 2026-07-03 17:46:49 Created test run directory: run_20260703_174649
[INFO] 2026-07-03 17:46:49 === Test Run Started ===
[INFO] 2026-07-03 17:46:49 Run ID: run_20260703_174649
[INFO] 2026-07-03 17:46:49 URLs to test: 48
[INFO] 2026-07-03 17:46:49 Namespaces: tw sg nl kr jp (baseline: kr)
[INFO] 2026-07-03 17:46:49 Browser runs as: timlau
[INFO] 2026-07-03 17:46:49 Max retries: 1
[INFO] 2026-07-03 17:46:49 Outer timeout: 45s (baseline 90s); nav 27000ms, ipinfo 8000ms
[INFO] 2026-07-03 17:46:49 Rate limiting: 1s every 10 URLs
[✓] 2026-07-03 17:47:15 URL 000 complete (retries: 0)
[✓] 2026-07-03 17:47:36 URL 001 complete (retries: 0)
[✓] 2026-07-03 17:47:56 URL 002 complete (retries: 0)
[✓] 2026-07-03 17:48:11 URL 003 complete (retries: 0)
[✓] 2026-07-03 17:48:31 URL 004 complete (retries: 0)
[✓] 2026-07-03 17:48:45 URL 005 complete (retries: 0)
[✓] 2026-07-03 17:49:05 URL 006 complete (retries: 0)
[✓] 2026-07-03 17:49:24 URL 007 complete (retries: 0)
[✓] 2026-07-03 17:49:44 URL 008 complete (retries: 0)
[✓] 2026-07-03 17:50:04 URL 009 complete (retries: 0)
[INFO] 2026-07-03 17:50:04 Completed 10/48 URLs, pausing 1s...
[✓] 2026-07-03 17:50:25 URL 010 complete (retries: 0)
[✓] 2026-07-03 17:50:39 URL 011 complete (retries: 0)
[⚠] 2026-07-03 17:51:00 URL 012 | Retry 1/1
[✗] 2026-07-03 17:51:24 URL 012 | Failed after 2 attempts
[✓] 2026-07-03 17:51:43 URL 013 complete (retries: 0)
….
As one can see, some URLs show different contents depending on where the client is connecting from.
# Website Geographic Comparison Report (Fuzzy Hash)
## Executive Summary
| Metric | Value |
|--------|-------|
| **Test Date** | 2026-07-03 |
| **Run ID** | run_20260703_174649 |
| **Method** | ssdeep Fuzzy Hashing (noise-adaptive) |
| **Base Similarity Threshold** | 85% |
| **URLs Analyzed** | 48 |
| **Conclusive** | 39 of 48 (81.3%) |
| **Inconclusive** | 9 (no usable baseline / no comparable peers) |
| **Locations** | Taiwan, Singapore, Netherlands, South Korea, Japan |
| **Baseline** | South Korea (KR) |
---
## Key Findings
| Severity | Count | Percentage | Criteria |
|----------|-------|------------|----------|
| **HIGH** | 0 | 0.0% | Divergence ≥3 OR avg similarity <70% |
| **MEDIUM** | 1 | 2.1% | Divergence 1-2 OR below adaptive threshold OR geo-blocked |
| **LOW** | 38 | 79.2% | Consistent across all comparable locations |
| **INCONCLUSIVE** | 9 | 18.8% | Baseline failed/wrong egress, or no comparable peers |
---
To compare the website contents, I used SSdeep fuzzy hashing. This is more or less the simplest method you can implement, other than just SHA1 both sides and compare them.
Complete report file here.
Sadly the test run didn’t find anything interesting, probably due to the fact that the URLs are old.
Conclusion
Hopefully this 2-parts blog posts is helpful enough for you to start your own multi-tunnel experiment. There are many other things you can do:
Bittorrent swam investigation
TOR exit nodes analysis
Anything that restricts connection to per IP (eg. official F*FA ticket seller )
Multi-wan experiments that test the behavior of a site when the requests for a site are from multiple source addresses. Some sites can behave unexpectedly when resources are requested from different source addresses.
Tunnel-in-tunnel (yes, that includes Tailscale tunnels). It’s tunnels all the way down.








