Fix WEBRUNNER: attack_box format, self-contained CIDR, tools submenu, Tor, teardown
- deploy_webrunner.py: full rewrite following attack_box pattern exactly — auto-generate engagement name when blank, select_provider+gather_provider_config per provider (handles region selection), separate teardown_after_scan (default=yes) from enhanced_opsec, use_tor prompt, bundled YAML defaults, setup_logging+confirm_action+show_naming_relationship - utils/cidr_resolver.py: self-contained RIR delegation file downloader/parser — downloads APNIC/ARIN/RIPE/LACNIC/AFRINIC, caches 24h in ~/.cache/c2itall/cidr/, no geo-scout dep - utils/chunk_utils.py: remove geo-scout _try_load_geo_scout() dependency, use cidr_resolver - modules/webrunner/inputs/countries.yaml: bundled default country list (no external dep) - modules/webrunner/inputs/targets.yaml: bundled default scan targets and ports - deploy.py: move WEBRUNNER from main menu (item 14) to tools submenu (item 10) - configure_node.yml: install tor+proxychains4, start tor service, configure proxychains, wait for circuit establishment when use_tor=true - run_scan.yml: prefix command with proxychains4 when use_tor=true - providers/webrunner.yml: add Play 4 teardown — Linode DELETE + AWS terminate-instances using hostvars instance IDs stored during provisioning, conditional on teardown_after_scan
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
import ipaddress
|
||||
import math
|
||||
import time
|
||||
from pathlib import Path
|
||||
from urllib.request import urlretrieve
|
||||
from urllib.error import URLError
|
||||
|
||||
CACHE_DIR = Path.home() / '.cache' / 'c2itall' / 'cidr'
|
||||
CACHE_TTL = 86400 # 24 hours
|
||||
|
||||
RIR_URLS = {
|
||||
'arin': 'https://ftp.arin.net/pub/stats/arin/delegated-arin-extended-latest',
|
||||
'ripe': 'https://ftp.ripe.net/ripe/stats/delegated-ripencc-extended-latest',
|
||||
'apnic': 'https://ftp.apnic.net/stats/apnic/delegated-apnic-extended-latest',
|
||||
'lacnic': 'https://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-extended-latest',
|
||||
'afrinic': 'https://ftp.afrinic.net/stats/delegated-afrinic-extended-latest',
|
||||
}
|
||||
|
||||
|
||||
def _cache_path(rir: str) -> Path:
|
||||
return CACHE_DIR / f'{rir}.txt'
|
||||
|
||||
|
||||
def _is_stale(path: Path) -> bool:
|
||||
if not path.exists():
|
||||
return True
|
||||
return (time.time() - path.stat().st_mtime) > CACHE_TTL
|
||||
|
||||
|
||||
def _fetch_rir(rir: str, url: str) -> Path:
|
||||
path = _cache_path(rir)
|
||||
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
if _is_stale(path):
|
||||
try:
|
||||
urlretrieve(url, path)
|
||||
except (URLError, OSError):
|
||||
pass # use stale cache if download fails
|
||||
return path
|
||||
|
||||
|
||||
def _count_to_cidrs(start: str, count: int) -> list[str]:
|
||||
try:
|
||||
start_addr = ipaddress.IPv4Address(start)
|
||||
end_addr = ipaddress.IPv4Address(int(start_addr) + count - 1)
|
||||
return [str(n) for n in ipaddress.summarize_address_range(start_addr, end_addr)]
|
||||
except (ipaddress.AddressValueError, ValueError):
|
||||
return []
|
||||
|
||||
|
||||
def _parse_rir_file(path: Path, target_ccs: set[str]) -> dict[str, list[str]]:
|
||||
result: dict[str, list[str]] = {cc: [] for cc in target_ccs}
|
||||
try:
|
||||
with open(path, encoding='latin-1') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
parts = line.split('|')
|
||||
if len(parts) < 7:
|
||||
continue
|
||||
_, cc, type_, start, count_str, _, status = parts[:7]
|
||||
if type_ != 'ipv4':
|
||||
continue
|
||||
if status not in ('allocated', 'assigned'):
|
||||
continue
|
||||
cc = cc.upper()
|
||||
if cc not in target_ccs:
|
||||
continue
|
||||
try:
|
||||
count = int(count_str)
|
||||
except ValueError:
|
||||
continue
|
||||
result[cc].extend(_count_to_cidrs(start, count))
|
||||
except OSError:
|
||||
pass
|
||||
return result
|
||||
|
||||
|
||||
def get_country_cidrs(country_codes: list[str], exclude_map: dict[str, list] | None = None) -> dict[str, list[str]]:
|
||||
if exclude_map is None:
|
||||
exclude_map = {}
|
||||
target_ccs = {cc.upper() for cc in country_codes}
|
||||
combined: dict[str, list[str]] = {cc: [] for cc in target_ccs}
|
||||
|
||||
for rir, url in RIR_URLS.items():
|
||||
path = _fetch_rir(rir, url)
|
||||
partial = _parse_rir_file(path, target_ccs)
|
||||
for cc, cidrs in partial.items():
|
||||
combined[cc].extend(cidrs)
|
||||
|
||||
for cc, excludes in exclude_map.items():
|
||||
cc = cc.upper()
|
||||
if cc not in combined or not excludes:
|
||||
continue
|
||||
exclude_nets = []
|
||||
for ex in excludes:
|
||||
try:
|
||||
exclude_nets.append(ipaddress.ip_network(ex, strict=False))
|
||||
except ValueError:
|
||||
pass
|
||||
if not exclude_nets:
|
||||
continue
|
||||
filtered = []
|
||||
for cidr in combined[cc]:
|
||||
try:
|
||||
net = ipaddress.ip_network(cidr, strict=False)
|
||||
if not any(net.overlaps(ex) for ex in exclude_nets):
|
||||
filtered.append(cidr)
|
||||
except ValueError:
|
||||
filtered.append(cidr)
|
||||
combined[cc] = filtered
|
||||
|
||||
return combined
|
||||
Reference in New Issue
Block a user