#!/usr/bin/env python3
import argparse
import json
from pathlib import Path
PROFILE_IMPORT = "index.php?option=com_jce&task=profiles.import"
DOMAINS = ["profiles.import","index.php"]
# Collect unique indicators
indicators = set()
for group in [DOMAINS]:
for val in group:
if val:
indicators.add(val)
SUSPICIOUS_DIRS = {"images", "media", "tmp"}
FILE_PATTERNS = {"images/*.php", "media/*.php", "tmp/*.php"}
SUSPICIOUS_SUFFIXES = {".php", ".phtml", ".php5", ".php7", ".phar"}
FIXED_VERSIONS = {"2.9.99.5", "2.9.99.6"}
def scan(root: Path) -> dict[str, list[str]]:
log_hits: list[str] = []
file_hits: list[str] = []
version_hits: list[str] = []
source_hits: list[str] = []
for path in root.rglob("*"):
if path.is_dir() or any(part in {".git", "node_modules", "vendor", "dist"} for part in path.parts):
continue
try:
text = path.read_text(errors="ignore")
except Exception:
text = ""
if PROFILE_IMPORT in text:
log_hits.append(f"{path}: {PROFILE_IMPORT}")
for domain in DOMAINS:
if domain in text:
source_hits.append(f"{path}: {domain}")
for url in URLS:
if url in text:
source_hits.append(f"{path}: {url}")
for version in FIXED_VERSIONS:
if version in text:
version_hits.append(f"{path}: {version}")
rel = path.relative_to(root)
if any(rel.match(pattern) for pattern in FILE_PATTERNS):
file_hits.append(f"{path}: suspicious PHP-like upload path")
elif path.suffix.lower() in SUSPICIOUS_SUFFIXES and any(part in SUSPICIOUS_DIRS for part in path.parts):
file_hits.append(f"{path}: suspicious PHP-like upload path")
return {
"log_hits": sorted(set(log_hits)),
"file_hits": sorted(set(file_hits)),
"version_hits": sorted(set(version_hits)),
"source_hits": sorted(set(source_hits)),
}
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("root", nargs="?", default=".", help="filesystem or log root to scan")
parser.add_argument("--out", default="jce-scope", help="output directory")
args = parser.parse_args()
root = Path(args.root).expanduser().resolve()
out = Path(args.out).expanduser().resolve()
out.mkdir(parents=True, exist_ok=True)
result = scan(root)
(out / "scan-summary.json").write_text(json.dumps(result, indent=2) + "\n", encoding="utf-8")
print(json.dumps({"scanned_root": str(root), **result}, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())