Skip to content

Magwerste/ip-scanner

Repository files navigation

IP Scanner

Scans one or more IP addresses against local threat intelligence lists and VirusTotal. Originally designed for Azure AD / Entra ID sign-in log analysis but works with any list of IPs.

Every public IP is checked against local blocklists first, then passed to VirusTotal. If a local list catches an IP, both detections are combined in the output — so you always get the full picture. Private and reserved IPs are silently skipped and never sent anywhere.

Automatically enforces the VirusTotal Public API limits:

  • 500 requests per day (tracked across restarts via quota_state.json)
  • 4 requests per minute (15-second enforced delay between calls)

Download

Go to the Releases page and download ip-scanner.exe — no Python installation required.


How to get a VirusTotal API key

  1. Go to https://www.virustotal.com and click Join us to register a free account.
  2. After signing in, click your profile icon in the top-right and select API key.
  3. Copy the key — you'll need it in the next step.

The free Public API allows 500 lookups per day and 4 per minute. No payment required.


Setup

  1. Place ip-scanner.exe in a folder on your machine.
  2. In the same folder, create a file named .env containing your VirusTotal API key:
    VT_API_KEY=your_api_key_here
    
  3. Run the scanner — no terminal required:
    • Double-click ip-scanner.exe to open the interactive prompt and paste IPs directly.
    • Drag a CSV or TXT file onto ip-scanner.exe in File Explorer to scan it automatically.

How it works

Input IPs
    │
    ▼
Strip private / RFC 1918 addresses (never sent anywhere)
    │
    ▼
Check local threat intel lists (no external API calls)
    ├── IPsum          — downloaded fresh each run
    ├── CINS Army      — bundled with the exe
    ├── Tor Exit Nodes — downloaded fresh each run
    └── DShield        — downloaded fresh each run (subnet blocklist)
         │
         ├── MATCH → flagged (local), then ALSO queried against VirusTotal
         │              └── sources combined: e.g. "IPsum, VirusTotal"
         │
         └── NO MATCH → queried against VirusTotal
                             │
                             ├── Malicious / Suspicious → flagged
                             └── Clean → not included in output
    │
    ▼
malicious_ips.csv — flagged IPs only, with Severity and Source columns

Each run downloads fresh copies of IPsum, Tor exits, and DShield. The CINS Army list is bundled with the exe.


Usage

Drag and drop (no terminal needed)

Drag a CSV or TXT file onto ip-scanner.exe in File Explorer. The scanner opens automatically and starts scanning.

Scan from an Entra ID / Azure AD CSV export

ip-scanner.exe --file SignInLogs_export.csv

The scanner automatically detects the Entra ID format and reads only the IP address column(s) — all other columns (user, device, location, etc.) are discarded without being stored.

Scan from a plain-text file (one IP per line)

ip-scanner.exe --file suspicious_ips.txt

Scan specific IPs directly

ip-scanner.exe --ips 8.8.8.8 1.1.1.1 185.220.101.5

Interactive mode (double-click or no arguments)

ip-scanner.exe

Paste one or more IPs, or type them one per line. Press Enter on a blank line to start scanning.


Options

Flag Short Description
--file PATH -f Input file (plain text or CSV)
--ips IP [IP ...] -i One or more IPs as arguments
--output PATH -o Custom path for the malicious IPs CSV (default: output/malicious_ips.csv)
--no-report Skip saving a CSV report
--quiet -q Suppress per-IP output, show summary only
--no-enrich Skip VirusTotal for local list hits (saves quota, loses combined source data)

Output

Terminal: Color-coded result for each IP:

  • Red — flagged as malicious
  • Yellow — flagged as suspicious
  • Green — clean

IPs caught by local lists are printed inline as MALICIOUS (local) with the matching source name(s).

CSV report: Saved to output/malicious_ips.csv after each scan (unless --no-report is used). The output/ folder is created automatically if it doesn't exist. Only flagged IPs are written — clean IPs are not included. Columns:

ip, severity, source, malicious_engines, suspicious_engines, reputation, country, asn, as_owner, network, last_analysis_date, scan_timestamp

Column Description
severity HIGH, MEDIUM, or LOW — plain-English risk rating
source What caught it — e.g. IPsum, VirusTotal, or IPsum, VirusTotal if caught by both
malicious_engines Engines that flagged it as malicious out of total queried — e.g. 3|94
suspicious_engines Engines that flagged it as suspicious out of total queried — e.g. 1|94

The engine counts adapt to however many engines VirusTotal ran on that IP for that specific scan. N/A is shown for local-only hits when --no-enrich is used.

Severity ratings

Level Condition
HIGH 4 or more malicious engine detections
MEDIUM 1–3 malicious engine detections
LOW Suspicious engines only (no malicious), or Tor exit / local list with no VT malicious hits

Local list hits and VirusTotal detections are counted independently. If VT finds malicious engines, that count is used (both sources detected the same threat). If VT finds nothing, each local list that flagged the IP counts as one detection — so an IP in both IPsum and DShield with no VT malicious data scores 2 → MEDIUM.


Local threat intelligence sources

Source Type Update
IPsum Known bad IPs (aggregated from multiple blocklists) Downloaded each run
Tor Exit Nodes Active Tor exit node IPs Downloaded each run
DShield Top attack source subnets Downloaded each run
CINS Army Known bad IPs (Collective Intelligence Network Security) Bundled — no download needed

If a download fails the run continues without that list — a warning is printed but no IPs are skipped.

Note on IPv6: Both IPv4 and IPv6 addresses are accepted as input and queried against VirusTotal. However, all four local blocklists are IPv4-only — IPv6 addresses will never match locally and are always sent to VirusTotal. This is a limitation of the upstream lists, not the scanner.


API quota

The VirusTotal Public API allows 500 requests per day. The scanner tracks usage in quota_state.json and resets automatically at midnight UTC. A warning is shown when fewer than 50 requests remain.

By default, every public IP is queried against VirusTotal — including those already caught by local lists, so sources can be combined. If you are scanning a very large file and need to conserve quota, pass --no-enrich to skip VT for local list hits.

If the number of IPs to scan exceeds your remaining daily quota, a warning is printed before the scan starts so you can decide whether to proceed or use --no-enrich.


For developers

Run from source

See setup.md for a full walkthrough (developer/source install). For a non-technical end-user guide, see walkthrough.md. Quick start:

git clone https://github.com/Magwerste/ip-scanner
cd vt-py-ip-scanner
python -m venv .venv
.venv\Scripts\activate
pip install -e ".[dev]"

Create a .env file with your API key, then run:

ip-scanner --file SignInLogs_export.csv

Project structure

vt-py-ip-scanner/
├── src/
│   └── ip_scanner/
│       ├── __init__.py         # Package marker
│       ├── __main__.py         # Entry point — CLI, input handling, scan loop
│       ├── client.py           # VirusTotal API calls and response parsing
│       ├── config.py           # Config loading from .env and constants
│       ├── output.py           # Terminal display (Rich) and CSV writing
│       ├── rate_limiter.py     # Per-minute and daily quota enforcement
│       └── threat_intel.py     # Local list download, loading, and lookup
├── tests/                      # Test suite (see tests/README.md)
├── vt-scan.spec                # PyInstaller build spec
├── .env                        # Your API key (never share or commit this)
├── .env.example                # Safe template — copy this to .env
├── pyproject.toml              # Package metadata and entry point definition
├── quota_state.json            # Auto-created — tracks daily API usage across restarts
├── threat_intel/               # Auto-created — downloaded list files cached here
├── threat_intel_static/        # Bundled static lists (CINS Army)
│   └── cinsarmy_badguys.txt    # CINS Army blocklist (included in repo, bundled in exe)
├── output/
│   └── malicious_ips.csv       # Auto-created — flagged IPs from each run
└── .venv/                      # Virtual environment (created during setup)

Acknowledgements

This tool wouldn't be possible without the following free and open resources:

  • VirusTotal — for providing a free Public API that makes large-scale IP reputation lookups accessible to everyone. The generous 500 requests/day allowance makes this tool practical for real-world use.

  • IPsum by @stamparm — a community-maintained aggregated blocklist that brings together threat intelligence from dozens of sources into a single, reliable feed.

  • Tor Project / dan.me.uk — for maintaining a publicly accessible list of active Tor exit nodes, enabling detection of anonymised traffic in sign-in logs.

  • DShield / SANS Internet Storm Center — for their block list of the most active attack-source subnets, updated daily from real firewall data contributed by the security community.

  • CINS Army / Collective Intelligence Network Security — for their freely distributed blocklist of known bad actors, included directly in this tool so it works out of the box with no extra setup.

Thank you to everyone who maintains these feeds and makes them freely available to the community.

About

IP scanner that checks IP addresses against local threat intelligence lists and VirusTotal. Designed for Azure AD / Entra ID sign-in log analysis.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages