zombie-vdp 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ include zombie_vdp/config.yaml
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.4
2
+ Name: zombie-vdp
3
+ Version: 1.0.0
4
+ Summary: 🧟‍♂️ Zombie VDP – Ultimate Identity Edition
5
+ Home-page: https://github.com/pormes-90/ZOMBIE.git
6
+ Author: Dikha Pormes
7
+ Author-email: pormesdikha90@gmail.com
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Information Technology
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Topic :: Security
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: aiohttp>=3.8
17
+ Requires-Dist: pyyaml>=6.0
18
+ Requires-Dist: dnspython>=2.3
19
+ Requires-Dist: psutil>=5.9
20
+ Requires-Dist: colorama>=0.4
21
+ Requires-Dist: beautifulsoup4>=4.12
22
+ Requires-Dist: cryptography>=41.0
23
+ Provides-Extra: full
24
+ Requires-Dist: scikit-learn>=1.3; extra == "full"
25
+ Requires-Dist: matplotlib>=3.7; extra == "full"
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: provides-extra
33
+ Dynamic: requires-dist
34
+ Dynamic: requires-python
35
+ Dynamic: summary
36
+
37
+ # 🧟‍♂️ Zombie VDP – Ultimate Identity Edition
38
+
39
+ **NASA VDP Compliant · 100% Passive · Triple Filter · Evidence Locker · Time Slice · Auto-PoC · Memory**
40
+
41
+ Zombie VDP adalah kerangka kerja bug bounty pribadi yang menggabungkan seluruh pipeline pengujian keamanan dalam satu nafas. Semua fitur dirancang dari nol, bukan meniru alat lain, melainkan menciptakan identitas sendiri: **Ninja**, **Samurai**, dan **Ghost**.
42
+
43
+ ---
44
+
45
+ ## 🔥 Fitur Legendaris
46
+
47
+ ### ⚔️ Triple Filter (Ninja · Samurai · Ghost)
48
+ - **Ninja Filter** – Hanya menerima temuan dengan bukti nyata (evidence).
49
+ - **Samurai Filter** – Hanya HIGH/CRITICAL dengan respons signifikan.
50
+ - **Ghost Filter** – Hanya confidence ≥98% atau metode timing/OOB.
51
+
52
+ ### 🧪 Zombie Deep Scan
53
+ Validasi lanjutan setelah filter: serangan timing untuk konfirmasi SQLi, dsb.
54
+
55
+ ### 🔒 Zombie Evidence Locker
56
+ Setiap temuan yang lolos filter disimpan sebagai bukti terenkripsi (format `.zombie`). Tidak bisa dibuka tanpa kunci.
57
+
58
+ ### ⏳ Zombie Time Slice
59
+ Zombie hanya beroperasi pada jam yang diizinkan (misal 02:00–05:00 UTC). Di luar jam itu, ia berhenti dan menunggu.
60
+
61
+ ### ⚡ Zombie Auto-PoC
62
+ Setiap temuan langsung dilengkapi skrip `curl` dan Python untuk mereproduksi kerentanan. Tim triase tinggal menjalankan.
63
+
64
+ ### 🧠 Zombie Memory
65
+ Jika pemindaian terhenti, Zombie mengingat titik terakhir dan bisa melanjutkan tanpa mengulang.
66
+
67
+ ### 🕸️ Zombie Crawler & Dorking (Internal)
68
+ Crawler mandiri + penyaring URL berbasis pola (tanpa search engine). 100% pasif, tidak meninggalkan jejak bot.
69
+
70
+ ### 🛡️ Scanner Kerentanan Bawaan
71
+ - Reflected XSS
72
+ - SQL Injection (error‑based + timing)
73
+ - Local File Inclusion (LFI)
74
+ - Server‑Side Template Injection (SSTI)
75
+ - Open Redirect
76
+ - Adaptive Fuzzer
77
+ - Secrets Scanner (AWS, GitHub, Slack, JWT)
78
+
79
+ ### 📊 Laporan Profesional
80
+ HTML report siap kirim ke program VDP. Ringan, rapi, hanya berisi temuan high/critical.
81
+
82
+ ---
83
+
84
+ ## 🚀 Menjalankan
85
+
86
+ ```bash
87
+ python zombie_vdp.py
@@ -0,0 +1,51 @@
1
+ # 🧟‍♂️ Zombie VDP – Ultimate Identity Edition
2
+
3
+ **NASA VDP Compliant · 100% Passive · Triple Filter · Evidence Locker · Time Slice · Auto-PoC · Memory**
4
+
5
+ Zombie VDP adalah kerangka kerja bug bounty pribadi yang menggabungkan seluruh pipeline pengujian keamanan dalam satu nafas. Semua fitur dirancang dari nol, bukan meniru alat lain, melainkan menciptakan identitas sendiri: **Ninja**, **Samurai**, dan **Ghost**.
6
+
7
+ ---
8
+
9
+ ## 🔥 Fitur Legendaris
10
+
11
+ ### ⚔️ Triple Filter (Ninja · Samurai · Ghost)
12
+ - **Ninja Filter** – Hanya menerima temuan dengan bukti nyata (evidence).
13
+ - **Samurai Filter** – Hanya HIGH/CRITICAL dengan respons signifikan.
14
+ - **Ghost Filter** – Hanya confidence ≥98% atau metode timing/OOB.
15
+
16
+ ### 🧪 Zombie Deep Scan
17
+ Validasi lanjutan setelah filter: serangan timing untuk konfirmasi SQLi, dsb.
18
+
19
+ ### 🔒 Zombie Evidence Locker
20
+ Setiap temuan yang lolos filter disimpan sebagai bukti terenkripsi (format `.zombie`). Tidak bisa dibuka tanpa kunci.
21
+
22
+ ### ⏳ Zombie Time Slice
23
+ Zombie hanya beroperasi pada jam yang diizinkan (misal 02:00–05:00 UTC). Di luar jam itu, ia berhenti dan menunggu.
24
+
25
+ ### ⚡ Zombie Auto-PoC
26
+ Setiap temuan langsung dilengkapi skrip `curl` dan Python untuk mereproduksi kerentanan. Tim triase tinggal menjalankan.
27
+
28
+ ### 🧠 Zombie Memory
29
+ Jika pemindaian terhenti, Zombie mengingat titik terakhir dan bisa melanjutkan tanpa mengulang.
30
+
31
+ ### 🕸️ Zombie Crawler & Dorking (Internal)
32
+ Crawler mandiri + penyaring URL berbasis pola (tanpa search engine). 100% pasif, tidak meninggalkan jejak bot.
33
+
34
+ ### 🛡️ Scanner Kerentanan Bawaan
35
+ - Reflected XSS
36
+ - SQL Injection (error‑based + timing)
37
+ - Local File Inclusion (LFI)
38
+ - Server‑Side Template Injection (SSTI)
39
+ - Open Redirect
40
+ - Adaptive Fuzzer
41
+ - Secrets Scanner (AWS, GitHub, Slack, JWT)
42
+
43
+ ### 📊 Laporan Profesional
44
+ HTML report siap kirim ke program VDP. Ringan, rapi, hanya berisi temuan high/critical.
45
+
46
+ ---
47
+
48
+ ## 🚀 Menjalankan
49
+
50
+ ```bash
51
+ python zombie_vdp.py
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,46 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ with open("README.md", "r", encoding="utf-8") as fh:
4
+ long_description = fh.read()
5
+
6
+ setup(
7
+ name="zombie-vdp",
8
+ version="1.0.0",
9
+ author="Dikha Pormes",
10
+ author_email="pormesdikha90@gmail.com",
11
+ description="🧟‍♂️ Zombie VDP – Ultimate Identity Edition",
12
+ long_description=long_description,
13
+ long_description_content_type="text/markdown",
14
+ url="https://github.com/pormes-90/ZOMBIE.git",
15
+ packages=find_packages(),
16
+ include_package_data=True, # Wajib agar config.yaml ikut terdistribusi
17
+ install_requires=[
18
+ "aiohttp>=3.8",
19
+ "pyyaml>=6.0",
20
+ "dnspython>=2.3",
21
+ "psutil>=5.9",
22
+ "colorama>=0.4",
23
+ "beautifulsoup4>=4.12",
24
+ "cryptography>=41.0",
25
+ ],
26
+ extras_require={
27
+ "full": [
28
+ "scikit-learn>=1.3",
29
+ "matplotlib>=3.7",
30
+ ],
31
+ },
32
+ entry_points={
33
+ "console_scripts": [
34
+ "zombie = zombie_vdp:main",
35
+ ],
36
+ },
37
+ classifiers=[
38
+ "Development Status :: 4 - Beta",
39
+ "Intended Audience :: Information Technology",
40
+ "License :: OSI Approved :: MIT License",
41
+ "Programming Language :: Python :: 3",
42
+ "Operating System :: OS Independent",
43
+ "Topic :: Security",
44
+ ],
45
+ python_requires=">=3.9",
46
+ )
@@ -0,0 +1,10 @@
1
+ # zombie_vdp/__init__.py
2
+ from .zombie import main_async
3
+ import asyncio
4
+
5
+ def main():
6
+ """Entry point untuk console_scripts."""
7
+ asyncio.run(main_async())
8
+
9
+ __version__ = "1.0.0"
10
+ __author__ = "Dikha Pormes"
@@ -0,0 +1,100 @@
1
+ # ═══════════════════════════════════════════
2
+ # ZOMBIE VDP – TRIPLE FILTER CONFIG
3
+ # (Mode Lambat – Aman dari Block)
4
+ # ═══════════════════════════════════════════
5
+
6
+ # ── TARGET ──────────────────────────────
7
+ target_domains:
8
+ - "nasa.gov"
9
+ - "www.nasa.gov"
10
+ - "mail.nasa.gov"
11
+ - "api.nasa.gov"
12
+ - "dev.nasa.gov"
13
+ - "admin.nasa.gov"
14
+ - "portal.nasa.gov"
15
+ - "cdn.nasa.gov"
16
+ - "static.nasa.gov"
17
+ - "assets.nasa.gov"
18
+ - "staging.nasa.gov"
19
+ - "test.nasa.gov"
20
+ - "*.nasa.gov"
21
+
22
+ # ── KEAMANAN ────────────────────────────
23
+ password: "zombie"
24
+
25
+ # ── OUTPUT & DATABASE ───────────────────
26
+ output_dir: "./output"
27
+ db_name: "zombie.db"
28
+
29
+ # ── WORKFLOW ────────────────────────────
30
+ workflow_steps:
31
+ - "zombie_recon"
32
+ - "zombie_crawl"
33
+ - "zombie_dork"
34
+ - "zombie_scan"
35
+ - "zombie_filter"
36
+ - "zombie_deep_scan"
37
+ - "zombie_evidence"
38
+ - "zombie_poc"
39
+ - "zombie_report"
40
+
41
+ # ── PERFORMANCE (LAMBAT & AMAN) ─────────
42
+ max_workers: 3
43
+ rate_limit: 1.0
44
+ timeout: 30
45
+ enable_ssl_verification: false
46
+
47
+ # ── CRAWLING (LAMBAT) ───────────────────
48
+ crawl_delay: [5.0, 10.0]
49
+ crawl_depth: 2
50
+ max_pages_crawl: 100
51
+
52
+ # ── DORKING (INTERNAL) ──────────────────
53
+ # (tidak pakai search engine, hanya filter URL)
54
+ dork_patterns:
55
+ - "\\.env$"
56
+ - "\\.sql$"
57
+ - "\\.log$"
58
+ - "\\.bak$"
59
+ - "\\.conf$"
60
+ - "password"
61
+ - "secret"
62
+ - "api_key"
63
+ - "token"
64
+ - "/admin"
65
+ - "/\\.git"
66
+ - "/config"
67
+ - "/backup"
68
+
69
+ # ── RECON (SUMBER PASIF) ────────────────
70
+ enable_wayback: true
71
+ enable_commoncrawl: true
72
+ enable_crtsh: true
73
+ enable_otx: true
74
+ enable_urlscan: true
75
+
76
+ # ── API KEYS ────────────────────────────
77
+ otx_api_key: "QM3FO7d0VCZGmsb5yavpubBm-dDQtpnPNPLKj4vpXLzU8fN_dhGv5Ec8cdaG5KBuIiEWrQqLc6T3BlbkFJX-RtvtGQCfzwIaj9SXGPE0nvADgcLvZMQQ3ZD0kpwWKfRIwfd2eDB8fVgpJWxeXUL_55UoOPYA"
78
+ urlscan_api_key: "019e4543-d4dc-70f9-9421-11a1c4030626"
79
+
80
+ # ── FILTER TRIPLE ───────────────────────
81
+ confidence_threshold: 90
82
+ active_filters:
83
+ - "ninja"
84
+ - "samurai"
85
+ - "ghost"
86
+
87
+ # ── FUZZER ──────────────────────────────
88
+ enable_fuzzer: true
89
+
90
+ # ── SECRETS SCANNER ─────────────────────
91
+ enable_secrets_scan: true
92
+
93
+ # ── LEGENDARY FEATURES ──────────────────
94
+ enable_evidence_locker: true
95
+ enable_time_slice: false
96
+ time_slice_start: 2
97
+ time_slice_end: 5
98
+ enable_auto_poc: true
99
+ enable_memory: true
100
+ memory_file: "zombie_memory.json"
@@ -0,0 +1,649 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ ZOMBIE VDP – TRIPLE FILTER EDITION (Final)
5
+ NASA VDP Compliant | 100% Passive
6
+ Fitur lengkap: Recon, Crawl, Dork, Scan, Fuzz, Secrets, Triple Filter,
7
+ Deep Scan, Evidence Locker, Auto-PoC, Memory, Report.
8
+ """
9
+
10
+ import asyncio, aiohttp, getpass, hashlib, json, logging, os, random, re, socket, ssl, sqlite3, sys, time, yaml
11
+ import dns.resolver, dns.query, dns.zone
12
+ from pathlib import Path
13
+ from typing import List, Set, Dict, Optional, Tuple, Any
14
+ from dataclasses import dataclass, field
15
+ from urllib.parse import urlparse, parse_qs, urlencode, urlunparse, urljoin
16
+ from collections import deque, defaultdict
17
+ from difflib import SequenceMatcher
18
+ from datetime import datetime
19
+ import resource, uuid, secrets, tempfile
20
+
21
+ # ─── Warna & Animasi ────────────────────────────────────────
22
+ try:
23
+ from colorama import Fore, Style, init; init(autoreset=True)
24
+ CYAN=Fore.CYAN; BLUE=Fore.BLUE; YELLOW=Fore.YELLOW; RED=Fore.RED
25
+ GREEN=Fore.GREEN; MAGENTA=Fore.MAGENTA; WHITE=Fore.WHITE; NC=Style.RESET_ALL
26
+ BOLD=Style.BRIGHT; PINK=Fore.MAGENTA
27
+ except:
28
+ CYAN=BLUE=YELLOW=RED=GREEN=MAGENTA=WHITE=NC=BOLD=PINK=""
29
+
30
+ def zombie_loading_bar(duration=2):
31
+ steps=100; bar_len=20; sleep_time=duration/steps
32
+ for i in range(steps+1):
33
+ filled=int(bar_len*i/steps)
34
+ bar='■'*filled+'□'*(bar_len-filled)
35
+ print(f'\r {PINK}[{NC}{bar}{PINK}]{NC} {CYAN}{i}%{NC}', end='', flush=True)
36
+ time.sleep(sleep_time)
37
+ print()
38
+
39
+ async def zombie_progress_bar(phase_name, duration=2):
40
+ steps=100; bar_len=20; sleep_time=duration/steps
41
+ for i in range(steps+1):
42
+ filled=int(bar_len*i/steps)
43
+ bar='■'*filled+'□'*(bar_len-filled)
44
+ print(f'\r {CYAN}{phase_name}{NC} {PINK}[{NC}{bar}{PINK}]{NC} {CYAN}{i}%{NC}', end='', flush=True)
45
+ await asyncio.sleep(sleep_time)
46
+ print()
47
+
48
+ def ninja_animation(): print(f"{PINK}🥷 Ninja Filter: hanya bukti nyata...{NC}"); zombie_loading_bar(1)
49
+ def samurai_animation(): print(f"{RED}⚔️ Samurai Filter: HIGH/CRITICAL + respons signifikan...{NC}"); zombie_loading_bar(1)
50
+ def ghost_animation(): print(f"{CYAN}👻 Ghost Filter: confidence ≥98% atau timing/OOB...{NC}"); zombie_loading_bar(1)
51
+
52
+ # ─── User-Agent Pool ────────────────────────────────────────
53
+ USER_AGENTS = [
54
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0",
55
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Version/17.0",
56
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/119.0.0.0",
57
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/120.0",
58
+ ]
59
+
60
+ def get_random_headers():
61
+ return {
62
+ "User-Agent": random.choice(USER_AGENTS),
63
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
64
+ "Accept-Language": "en-US,en;q=0.5",
65
+ }
66
+
67
+ # ─── Config ─────────────────────────────────────────────────
68
+ @dataclass
69
+ class Config:
70
+ target_domains: List[str] = field(default_factory=lambda: ["nasa.gov"])
71
+ password: str = ""
72
+ output_dir: str = "./output"
73
+ db_name: str = "zombie.db"
74
+ workflow_steps: List[str] = field(default_factory=lambda: [
75
+ "zombie_recon","zombie_crawl","zombie_dork",
76
+ "zombie_scan","zombie_filter","zombie_deep_scan",
77
+ "zombie_evidence","zombie_poc","zombie_report"
78
+ ])
79
+ max_workers: int = 3
80
+ rate_limit: float = 1.0
81
+ timeout: int = 30
82
+ enable_ssl_verification: bool = False
83
+ crawl_delay: Tuple[float, float] = (5.0, 10.0)
84
+ crawl_depth: int = 2
85
+ max_pages_crawl: int = 100
86
+ dork_patterns: List[str] = field(default_factory=lambda: [
87
+ r'\.env$', r'\.sql$', r'\.log$', r'\.bak$', r'\.conf$',
88
+ r'password', r'secret', r'api_key', r'token',
89
+ r'/admin', r'/\.git', r'/config', r'/backup'
90
+ ])
91
+ enable_wayback: bool = True
92
+ enable_commoncrawl: bool = True
93
+ enable_crtsh: bool = True
94
+ enable_otx: bool = True
95
+ enable_urlscan: bool = True
96
+ otx_api_key: str = ""
97
+ urlscan_api_key: str = ""
98
+ confidence_threshold: int = 90
99
+ active_filters: List[str] = field(default_factory=lambda: ["ninja","samurai","ghost"])
100
+ enable_fuzzer: bool = True
101
+ enable_secrets_scan: bool = True
102
+ enable_evidence_locker: bool = True
103
+ enable_time_slice: bool = False
104
+ time_slice_start: int = 2
105
+ time_slice_end: int = 5
106
+ enable_auto_poc: bool = True
107
+ enable_memory: bool = True
108
+ memory_file: str = "zombie_memory.json"
109
+
110
+ def __post_init__(self):
111
+ Path(self.output_dir).mkdir(parents=True, exist_ok=True)
112
+ (Path(self.output_dir) / "reports").mkdir(exist_ok=True)
113
+ (Path(self.output_dir) / "evidence").mkdir(exist_ok=True)
114
+ (Path(self.output_dir) / "poc").mkdir(exist_ok=True)
115
+
116
+ @classmethod
117
+ def from_yaml(cls, path: str = "config.yaml") -> 'Config':
118
+ # 1. Cek current working directory
119
+ cwd_path = Path.cwd() / path
120
+ if cwd_path.exists():
121
+ with open(cwd_path) as f:
122
+ data = yaml.safe_load(f) or {}
123
+ else:
124
+ # 2. Fallback ke package directory
125
+ package_path = Path(__file__).parent / path
126
+ if package_path.exists():
127
+ with open(package_path) as f:
128
+ data = yaml.safe_load(f) or {}
129
+ else:
130
+ logging.warning(f"Config file not found, using defaults")
131
+ return cls()
132
+
133
+ fields = {f.name for f in cls.__dataclass_fields__.values()}
134
+ filtered = {k: v for k, v in data.items() if k in fields}
135
+ return cls(**filtered)
136
+
137
+ # ─── Session Manager ────────────────────────────────────────
138
+ class SessionManager:
139
+ def __init__(self, config: Config):
140
+ self.config = config
141
+ self.session: Optional[aiohttp.ClientSession] = None
142
+ self.semaphore = asyncio.Semaphore(config.max_workers)
143
+ self.last_request = 0
144
+
145
+ async def __aenter__(self):
146
+ connector = aiohttp.TCPConnector(limit=0, ssl=not self.config.enable_ssl_verification)
147
+ self.session = aiohttp.ClientSession(connector=connector)
148
+ return self
149
+
150
+ async def __aexit__(self, *args):
151
+ if self.session: await self.session.close()
152
+
153
+ async def fetch(self, url: str, method='GET', data=None, headers=None, **kwargs) -> dict:
154
+ async with self.semaphore:
155
+ now = time.monotonic()
156
+ if now - self.last_request < 1/self.config.rate_limit:
157
+ await asyncio.sleep(1/self.config.rate_limit)
158
+ self.last_request = time.monotonic()
159
+ if headers is None: headers = get_random_headers()
160
+ try:
161
+ async with self.session.request(method, url, data=data, headers=headers,
162
+ timeout=self.config.timeout, **kwargs) as resp:
163
+ if resp.status in (429, 403, 503):
164
+ pause = random.uniform(30, 60)
165
+ print(f"\n {YELLOW}⚠ Block terdeteksi ({resp.status}). Auto‑pause {pause:.0f}s...{NC}")
166
+ await asyncio.sleep(pause)
167
+ text = await resp.text()
168
+ return {"status":resp.status,"headers":dict(resp.headers),"text":text,"url":str(resp.url)}
169
+ except Exception as e:
170
+ return {"status":0,"headers":{},"text":"","url":url}
171
+
172
+ # ─── Database ───────────────────────────────────────────────
173
+ class Database:
174
+ def __init__(self, db_path:str):
175
+ self.conn = sqlite3.connect(db_path, check_same_thread=False)
176
+ self.conn.execute("""CREATE TABLE IF NOT EXISTS findings (
177
+ id TEXT PRIMARY KEY, url TEXT, vuln_type TEXT, severity TEXT, param TEXT, confidence INTEGER,
178
+ evidence TEXT, response_length INTEGER, method TEXT, timestamp TEXT
179
+ )""")
180
+ self.conn.commit()
181
+
182
+ def save(self, finding: Dict):
183
+ fid = finding.get("id", str(uuid.uuid4())[:8])
184
+ self.conn.execute("INSERT OR REPLACE INTO findings VALUES (?,?,?,?,?,?,?,?,?,?)",
185
+ (fid, finding["url"], finding["vuln_type"], finding["severity"],
186
+ finding.get("param",""), finding["confidence"],
187
+ finding.get("evidence",""), finding.get("response_length",0),
188
+ finding.get("method",""), datetime.now().isoformat()))
189
+ self.conn.commit()
190
+ return fid
191
+
192
+ def all(self):
193
+ return self.conn.execute("SELECT * FROM findings ORDER BY severity DESC").fetchall()
194
+
195
+ # ─── Recon Functions ────────────────────────────────────────
196
+ async def zombie_wayback(sm, domain):
197
+ urls=set()
198
+ try:
199
+ resp=await sm.fetch(f"http://web.archive.org/cdx/search/cdx?url=*.{domain}/*&output=json&collapse=urlkey&fl=original")
200
+ if resp["status"]==200:
201
+ data=json.loads(resp["text"])
202
+ for row in data[1:500]:
203
+ if domain in row[0]: urls.add(row[0])
204
+ except: pass
205
+ return urls
206
+
207
+ async def zombie_commoncrawl(sm, domain):
208
+ urls=set()
209
+ try:
210
+ idx="CC-MAIN-2024-10"
211
+ resp=await sm.fetch(f"http://index.commoncrawl.org/{idx}-index?url=*.{domain}/*&output=json&matchType=domain&fl=url")
212
+ if resp["status"]==200:
213
+ for line in resp["text"].splitlines():
214
+ if domain in line: urls.add(json.loads(line)["url"])
215
+ except: pass
216
+ return urls
217
+
218
+ async def zombie_crtsh(sm, domain):
219
+ urls=set()
220
+ try:
221
+ resp=await sm.fetch(f"https://crt.sh/?q=%.{domain}&output=json")
222
+ if resp["status"]==200:
223
+ data=json.loads(resp["text"])
224
+ for entry in data[:200]:
225
+ for sub in entry.get("name_value","").split():
226
+ if domain in sub: urls.add(f"https://{sub.strip('*.')}")
227
+ except: pass
228
+ return urls
229
+
230
+ async def zombie_otx(sm, domain, api_key):
231
+ urls=set()
232
+ if not api_key: return urls
233
+ headers={"X-OTX-API-KEY":api_key}
234
+ try:
235
+ async with aiohttp.ClientSession(headers=headers) as sess:
236
+ async with sess.get(f"https://otx.alienvault.com/api/v1/indicators/domain/{domain}/url_list") as resp:
237
+ if resp.status==200:
238
+ data=await resp.json()
239
+ for item in data.get("url_list",[])[:200]:
240
+ if domain in item.get("url",""): urls.add(item["url"])
241
+ except: pass
242
+ return urls
243
+
244
+ async def zombie_urlscan(sm, domain, api_key):
245
+ urls=set()
246
+ if not api_key: return urls
247
+ headers={"API-Key":api_key}
248
+ try:
249
+ async with aiohttp.ClientSession(headers=headers) as sess:
250
+ async with sess.get(f"https://urlscan.io/api/v1/search/?q=domain:{domain}") as resp:
251
+ if resp.status==200:
252
+ data=await resp.json()
253
+ for result in data.get("results",[])[:100]:
254
+ u=result.get("page",{}).get("url")
255
+ if u and domain in u: urls.add(u)
256
+ except: pass
257
+ return urls
258
+
259
+ async def zombie_dns_enum(domain):
260
+ subs=set()
261
+ resolver=dns.resolver.Resolver(); resolver.timeout=2
262
+ for sub in ["www","mail","api","dev","admin","portal","cdn","static","assets"]:
263
+ try:
264
+ resolver.resolve(f"{sub}.{domain}", 'A')
265
+ subs.add(f"{sub}.{domain}")
266
+ except: continue
267
+ return subs
268
+
269
+ # ─── Crawler ────────────────────────────────────────────────
270
+ class ZombieCrawler:
271
+ def __init__(self, config: Config): self.config=config
272
+ async def crawl(self, sm, base_domains, seed_urls=set()):
273
+ visited=set()
274
+ queue=deque([(u,0) for u in seed_urls if any(d in u for d in base_domains)])
275
+ for d in base_domains: queue.append((f"https://{d}",0))
276
+ while queue and len(visited)<self.config.max_pages_crawl:
277
+ url,depth=queue.popleft()
278
+ if url in visited: continue
279
+ visited.add(url)
280
+ if depth>=self.config.crawl_depth: continue
281
+ resp=await sm.fetch(url)
282
+ if resp["status"]!=200: continue
283
+ try:
284
+ from bs4 import BeautifulSoup
285
+ soup=BeautifulSoup(resp["text"],'html.parser')
286
+ for link in soup.find_all('a',href=True):
287
+ full=urljoin(url,link['href'])
288
+ if any(d in full for d in base_domains) and full not in visited:
289
+ queue.append((full,depth+1))
290
+ except: pass
291
+ await asyncio.sleep(random.uniform(*self.config.crawl_delay))
292
+ return visited
293
+
294
+ # ─── Dorker (Internal) ──────────────────────────────────────
295
+ class ZombieDorker:
296
+ def __init__(self, config: Config): self.config=config
297
+ def execute(self, urls: Set[str]) -> Set[str]:
298
+ filtered=set()
299
+ for url in urls:
300
+ for pattern in self.config.dork_patterns:
301
+ if re.search(pattern, url, re.IGNORECASE):
302
+ filtered.add(url); break
303
+ return filtered
304
+
305
+ # ─── Vulnerability Checks ──────────────────────────────────
306
+ def inject_payload(url, param, payload):
307
+ parsed=urlparse(url)
308
+ q=parse_qs(parsed.query); q[param]=[payload]
309
+ return urlunparse(parsed._replace(query=urlencode(q, doseq=True)))
310
+
311
+ async def zombie_xss(sm, url, param, config):
312
+ for p in ['"><script>alert(1)</script>','<img src=x onerror=alert(1)>']:
313
+ test_url=inject_payload(url,param,p)
314
+ resp=await sm.fetch(test_url)
315
+ if p in resp["text"]:
316
+ return {"vuln_type":"XSS","severity":"HIGH","confidence":95,"param":param,
317
+ "evidence":resp["text"][:200],"response_length":len(resp["text"]),
318
+ "method":"reflected","url":url,"payload":p}
319
+ return None
320
+
321
+ async def zombie_sqli(sm, url, param, config):
322
+ errors=["sql syntax","mysql_fetch","unclosed quotation","SQLSTATE"]
323
+ for p in ["' OR '1'='1","1 AND 1=1"]:
324
+ resp=await sm.fetch(inject_payload(url,param,p))
325
+ if any(e in resp["text"].lower() for e in errors):
326
+ return {"vuln_type":"SQLi","severity":"CRITICAL","confidence":92,"param":param,
327
+ "evidence":resp["text"][:200],"response_length":len(resp["text"]),
328
+ "method":"error","url":url,"payload":p}
329
+ return None
330
+
331
+ async def zombie_lfi(sm, url, param):
332
+ resp=await sm.fetch(inject_payload(url,param,"../../../../etc/passwd"))
333
+ if "root:x:" in resp["text"]:
334
+ return {"vuln_type":"LFI","severity":"HIGH","confidence":100,"param":param,
335
+ "evidence":resp["text"][:200],"response_length":len(resp["text"]),
336
+ "method":"reflected","url":url,"payload":"../../../../etc/passwd"}
337
+ return None
338
+
339
+ # ─── Fuzzer ─────────────────────────────────────────────────
340
+ class ZombieFuzzer:
341
+ def __init__(self): self.baselines={}
342
+ async def baseline(self, sm, url):
343
+ resp=await sm.fetch(url)
344
+ bl={"length":len(resp["text"]),"hash":hashlib.md5(resp["text"].encode()).hexdigest(),
345
+ "text":resp["text"][:5000],"status":resp["status"],"headers":resp["headers"]}
346
+ self.baselines[url]=bl; return bl
347
+ async def fuzz(self, sm, url, param, payloads):
348
+ baseline=await self.baseline(sm, url); anomalies=[]
349
+ for p in payloads:
350
+ test_url=inject_payload(url,param,p)
351
+ start=time.monotonic(); resp=await sm.fetch(test_url); elapsed=time.monotonic()-start
352
+ len_diff=abs(len(resp["text"])-baseline["length"])/max(baseline["length"],1)
353
+ hash_diff=hashlib.md5(resp["text"].encode()).hexdigest()!=baseline["hash"]
354
+ status_diff=resp["status"]!=baseline["status"]
355
+ similarity=SequenceMatcher(None,resp["text"][:2000],baseline["text"][:2000]).ratio()
356
+ time_anomaly=elapsed>2.0
357
+ error_count=sum(resp["text"].lower().count(kw) for kw in ["sql","syntax","mysql","error","exception","warning"])
358
+ score=0.0
359
+ if len_diff>0.3: score+=0.3
360
+ if hash_diff: score+=0.2
361
+ if status_diff: score+=0.2
362
+ if similarity<0.7: score+=0.3
363
+ if time_anomaly: score+=0.2
364
+ score+=min(error_count*0.05,0.3)
365
+ if score>=0.9:
366
+ anomalies.append({"vuln_type":"XSS (fuzzer)","severity":"HIGH",
367
+ "confidence":int(score*100),"param":param,
368
+ "evidence":resp["text"][:200],"response_length":len(resp["text"]),
369
+ "method":"fuzzer","url":url,"payload":p})
370
+ return anomalies
371
+
372
+ # ─── Secrets Scanner ────────────────────────────────────────
373
+ SECRET_PATTERNS = [
374
+ ('AWS Access Key', r'AKIA[0-9A-Z]{16}'),
375
+ ('GitHub Token', r'ghp_[0-9a-zA-Z]{36}'),
376
+ ('Slack Webhook', r'https://hooks.slack.com/services/[A-Za-z0-9/]+'),
377
+ ('Generic JWT', r'eyJ[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+'),
378
+ ]
379
+ async def zombie_find_secrets(url, text):
380
+ found=[]
381
+ for name,pat in SECRET_PATTERNS:
382
+ for match in re.finditer(pat, text):
383
+ found.append({"vuln_type":f"Secret: {name}","severity":"HIGH","confidence":95,
384
+ "param":match.group(),"evidence":text[match.start()-20:match.end()+20],
385
+ "response_length":0,"method":"pattern","url":url,"payload":match.group()})
386
+ return found
387
+
388
+ # ─── Triple Filter ──────────────────────────────────────────
389
+ class NinjaFilter:
390
+ def apply(self, findings):
391
+ return [f for f in findings if f.get("evidence") and f.get("confidence",0)>=90]
392
+ class SamuraiFilter:
393
+ def apply(self, findings):
394
+ return [f for f in findings if f.get("severity") in ("HIGH","CRITICAL") and f.get("response_length",0)>0 and f.get("confidence",0)>=90]
395
+ class GhostFilter:
396
+ def apply(self, findings):
397
+ return [f for f in findings if (f.get("method") in ("timing","oob") or f.get("confidence",0)>=98) and f.get("confidence",0)>=90]
398
+ class FilterPipeline:
399
+ def __init__(self, config: Config):
400
+ self.filters=[]
401
+ for name in config.active_filters:
402
+ if name=="ninja": self.filters.append(NinjaFilter())
403
+ elif name=="samurai": self.filters.append(SamuraiFilter())
404
+ elif name=="ghost": self.filters.append(GhostFilter())
405
+ def apply(self, findings):
406
+ for f in self.filters: findings=f.apply(findings)
407
+ return findings
408
+
409
+ # ─── Deep Scan ──────────────────────────────────────────────
410
+ async def zombie_deep_scan(sm, filtered_findings):
411
+ for finding in filtered_findings:
412
+ if finding["vuln_type"]=="SQLi" and finding.get("method")!="timing":
413
+ start=time.monotonic()
414
+ await sm.fetch(inject_payload(finding["url"], finding["param"], "' AND SLEEP(3)--"))
415
+ if time.monotonic()-start>2.5:
416
+ finding["confidence"]=99; finding["method"]="timing"
417
+ return filtered_findings
418
+
419
+ # ─── Evidence Locker ────────────────────────────────────────
420
+ try:
421
+ from cryptography.fernet import Fernet
422
+ CRYPTO_OK = True
423
+ except: CRYPTO_OK = False
424
+
425
+ class ZombieEvidenceLocker:
426
+ def __init__(self, config: Config):
427
+ self.config = config
428
+ self.key_file = Path(config.output_dir) / "evidence" / ".key"
429
+ if not self.key_file.exists() and CRYPTO_OK:
430
+ key = Fernet.generate_key()
431
+ self.key_file.write_bytes(key)
432
+ self.cipher = Fernet(self.key_file.read_bytes()) if CRYPTO_OK and self.key_file.exists() else None
433
+
434
+ def lock(self, finding: Dict):
435
+ fid = finding.get("id", str(uuid.uuid4())[:8])
436
+ evidence_path = Path(self.config.output_dir) / "evidence" / f"{fid}.zombie"
437
+ data = json.dumps({
438
+ "url": finding["url"],
439
+ "vuln_type": finding["vuln_type"],
440
+ "payload": finding.get("payload",""),
441
+ "evidence": finding.get("evidence",""),
442
+ }).encode()
443
+ if self.cipher: data = self.cipher.encrypt(data)
444
+ evidence_path.write_bytes(data)
445
+ return str(evidence_path)
446
+
447
+ # ─── Time Slice ─────────────────────────────────────────────
448
+ class ZombieTimeSlice:
449
+ def __init__(self, config: Config): self.config=config
450
+ async def wait_if_needed(self):
451
+ while self.config.enable_time_slice:
452
+ now=datetime.utcnow().hour
453
+ if self.config.time_slice_start <= now < self.config.time_slice_end:
454
+ break
455
+ print(f"{YELLOW}⏳ Zombie Time Slice: di luar jam operasi. Menunggu...{NC}")
456
+ await asyncio.sleep(300)
457
+
458
+ # ─── Auto-PoC ───────────────────────────────────────────────
459
+ class ZombieAutoPoC:
460
+ def __init__(self, config: Config): self.config=config
461
+ def generate(self, finding: Dict):
462
+ fid = finding.get("id", str(uuid.uuid4())[:8])
463
+ poc_dir = Path(self.config.output_dir) / "poc" / fid
464
+ poc_dir.mkdir(exist_ok=True)
465
+ curl_cmd = f"curl -X GET '{finding['url']}' -H 'User-Agent: ZombieVDP/1.0'"
466
+ if finding.get("param"):
467
+ curl_cmd = f"curl -X GET '{inject_payload(finding['url'], finding['param'], finding['payload'])}' -H 'User-Agent: ZombieVDP/1.0'"
468
+ (poc_dir / "reproduce.sh").write_text(f"#!/bin/bash\n{curl_cmd}\n")
469
+ py_script = f"""import requests
470
+ r = requests.get("{inject_payload(finding['url'], finding['param'], finding['payload'])}", headers={{"User-Agent":"ZombieVDP/1.0"}})
471
+ print(r.status_code, len(r.text))
472
+ """
473
+ (poc_dir / "reproduce.py").write_text(py_script)
474
+ return str(poc_dir)
475
+
476
+ # ─── Memory ─────────────────────────────────────────────────
477
+ class ZombieMemory:
478
+ def __init__(self, config: Config):
479
+ self.config = config
480
+ self.file = Path(config.output_dir) / config.memory_file
481
+ def load(self):
482
+ if self.file.exists(): return json.loads(self.file.read_text())
483
+ return {"scanned_urls":[], "findings_ids":[], "last_step":None}
484
+ def save(self, state: Dict):
485
+ self.file.write_text(json.dumps(state))
486
+
487
+ # ─── Report ─────────────────────────────────────────────────
488
+ def zombie_report(db, output_dir):
489
+ findings=db.all()
490
+ if not findings:
491
+ print(f"{YELLOW}⚠ No high/critical findings to report.{NC}")
492
+ return None
493
+ ts=datetime.now().strftime("%Y%m%d_%H%M%S")
494
+ report_path=output_dir/"reports"/f"zombie_{ts}.html"
495
+ with open(report_path,'w',encoding='utf-8') as f:
496
+ f.write("<html><head><title>Zombie VDP Report</title><style>body{font-family:monospace;background:#0a0e27;color:#ccc;padding:20px}h1{color:#00d4ff}.finding{margin:8px 0;padding:5px;border-left:3px solid #ff8800}</style></head><body>")
497
+ f.write(f"<h1>🧟 Zombie VDP Report</h1><p>Generated: {datetime.now()}</p><h2>Findings ({len(findings)})</h2>")
498
+ for row in findings:
499
+ url,vuln,sev,param,conf=row[1],row[2],row[3],row[4],row[5]
500
+ f.write(f"<div class='finding'><strong>{vuln}</strong> [{sev}] @ <a href='{url}'>{url}</a> | Param: {param} | Confidence: {conf}%</div>")
501
+ f.write("</body></html>")
502
+ logging.info(f"Report saved to {report_path}")
503
+ return report_path
504
+
505
+ # ─── Main ───────────────────────────────────────────────────
506
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
507
+ logger = logging.getLogger("ZombieVDP")
508
+
509
+ async def main_async():
510
+ config = Config.from_yaml()
511
+ db = Database(config.db_name)
512
+ pipeline = FilterPipeline(config)
513
+ evidence_locker = ZombieEvidenceLocker(config)
514
+ time_slice = ZombieTimeSlice(config)
515
+ auto_poc = ZombieAutoPoC(config)
516
+ memory = ZombieMemory(config)
517
+
518
+ if config.password:
519
+ pwd = getpass.getpass(f"{YELLOW}🔐 Password: {NC}")
520
+ if pwd != config.password:
521
+ print(f"{RED}✗ Wrong password.{NC}"); return
522
+ zombie_art = f"""
523
+ {CYAN}███████╗ ██████╗ ███╗ ███╗██████╗ ██╗███████╗
524
+ ╚══███╔╝██╔═══██╗████╗ ████║██╔══██╗██║██╔════╝
525
+ ███╔╝ ██║ ██║██╔████╔██║██████╔╝██║█████╗
526
+ ███╔╝ ██║ ██║██║╚██╔╝██║██╔══██╗██║██╔══╝
527
+ ███████╗╚██████╔╝██║ ╚═╝ ██║██████╔╝██║███████╗
528
+ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═╝╚══════╝{NC}
529
+ {PINK} ☣ Z O M B I E S Y S T E M ☣{NC}
530
+ """
531
+ print(zombie_art)
532
+ zombie_loading_bar(2)
533
+ else:
534
+ print(f"{YELLOW}⚠ No password set – langsung menjalankan.{NC}")
535
+ zombie_loading_bar(2)
536
+
537
+ await time_slice.wait_if_needed()
538
+
539
+ async with SessionManager(config) as sm:
540
+ ctx = {"all_urls": set(), "subdomains": set(), "raw_findings": [], "final_findings": []}
541
+ state = memory.load()
542
+ if state.get("last_step"):
543
+ print(f"{YELLOW}🧠 Zombie Memory: Melanjutkan dari '{state['last_step']}'...{NC}")
544
+ ctx["all_urls"] = set(state.get("all_urls", []))
545
+ ctx["subdomains"] = set(state.get("subdomains", []))
546
+
547
+ async def zombie_recon_phase():
548
+ urls = set()
549
+ for domain in config.target_domains:
550
+ if config.enable_wayback: urls |= await zombie_wayback(sm, domain)
551
+ if config.enable_commoncrawl: urls |= await zombie_commoncrawl(sm, domain)
552
+ if config.enable_crtsh: urls |= await zombie_crtsh(sm, domain)
553
+ if config.enable_otx and config.otx_api_key: urls |= await zombie_otx(sm, domain, config.otx_api_key)
554
+ if config.enable_urlscan and config.urlscan_api_key: urls |= await zombie_urlscan(sm, domain, config.urlscan_api_key)
555
+ subs = await zombie_dns_enum(domain)
556
+ ctx["subdomains"] |= subs
557
+ urls |= {f"https://{s}" for s in subs}
558
+ ctx["all_urls"] = urls
559
+ memory.save({"last_step":"zombie_recon","all_urls":list(urls),"subdomains":list(ctx["subdomains"])})
560
+
561
+ async def zombie_crawl_phase():
562
+ crawler = ZombieCrawler(config)
563
+ crawled = await crawler.crawl(sm, config.target_domains, ctx["all_urls"])
564
+ ctx["all_urls"] |= crawled
565
+ memory.save({"last_step":"zombie_crawl","all_urls":list(ctx["all_urls"])})
566
+
567
+ async def zombie_dork_phase():
568
+ dorker = ZombieDorker(config)
569
+ dorked = dorker.execute(ctx["all_urls"])
570
+ ctx["all_urls"] = dorked
571
+ memory.save({"last_step":"zombie_dork","all_urls":list(ctx["all_urls"])})
572
+
573
+ async def zombie_scan_phase():
574
+ raw = []
575
+ urls = list(ctx["all_urls"])[:100]
576
+ for url in urls:
577
+ params = set(parse_qs(urlparse(url).query).keys())
578
+ for param in params:
579
+ r = await zombie_xss(sm, url, param, config)
580
+ if r: raw.append(r)
581
+ r = await zombie_sqli(sm, url, param, config)
582
+ if r: raw.append(r)
583
+ r = await zombie_lfi(sm, url, param)
584
+ if r: raw.append(r)
585
+ if config.enable_fuzzer and params:
586
+ fuzzer = ZombieFuzzer()
587
+ for param in params:
588
+ anoms = await fuzzer.fuzz(sm, url, param, ['"><script>alert(1)</script>','<img src=x onerror=alert(1)>'])
589
+ raw.extend(anoms)
590
+ if config.enable_secrets_scan:
591
+ for url in urls[:50]:
592
+ resp = await sm.fetch(url)
593
+ if resp["text"]: raw.extend(await zombie_find_secrets(url, resp["text"]))
594
+ ctx["raw_findings"] = raw
595
+ memory.save({"last_step":"zombie_scan"})
596
+
597
+ async def zombie_filter_phase():
598
+ print(f"\n{PINK}{BOLD}FILTERING WITH TRIPLE WARRIORS...{NC}")
599
+ ninja_animation(); samurai_animation(); ghost_animation()
600
+ filtered = pipeline.apply(ctx["raw_findings"])
601
+ ctx["final_findings"] = filtered
602
+ memory.save({"last_step":"zombie_filter"})
603
+
604
+ async def zombie_deep_scan_phase():
605
+ findings = await zombie_deep_scan(sm, ctx["final_findings"])
606
+ for f in findings:
607
+ fid = db.save(f)
608
+ f["id"] = fid
609
+ ctx["final_findings"] = findings
610
+ memory.save({"last_step":"zombie_deep_scan"})
611
+
612
+ async def zombie_evidence_phase():
613
+ if not config.enable_evidence_locker: return
614
+ for f in ctx["final_findings"]:
615
+ evidence_locker.lock(f)
616
+ print(f"{GREEN}🔒 Evidence locked.{NC}")
617
+
618
+ async def zombie_poc_phase():
619
+ if not config.enable_auto_poc: return
620
+ for f in ctx["final_findings"]:
621
+ auto_poc.generate(f)
622
+ print(f"{GREEN}⚡ Auto-PoC generated.{NC}")
623
+
624
+ async def zombie_report_phase():
625
+ path = zombie_report(db, Path(config.output_dir))
626
+ if path: print(f"{GREEN}✔ Report generated: {path}{NC}")
627
+
628
+ phases = {
629
+ "zombie_recon": zombie_recon_phase,
630
+ "zombie_crawl": zombie_crawl_phase,
631
+ "zombie_dork": zombie_dork_phase,
632
+ "zombie_scan": zombie_scan_phase,
633
+ "zombie_filter": zombie_filter_phase,
634
+ "zombie_deep_scan": zombie_deep_scan_phase,
635
+ "zombie_evidence": zombie_evidence_phase,
636
+ "zombie_poc": zombie_poc_phase,
637
+ "zombie_report": zombie_report_phase,
638
+ }
639
+
640
+ for step in config.workflow_steps:
641
+ if step in phases:
642
+ print(f"\n{CYAN}{'='*60}{NC}")
643
+ print(f"{CYAN}{BOLD}[{step.upper()}]{NC}")
644
+ await zombie_progress_bar(step, 1.5)
645
+ await phases[step]()
646
+
647
+ if __name__ == "__main__":
648
+ import asyncio
649
+ asyncio.run(main_async())
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.4
2
+ Name: zombie-vdp
3
+ Version: 1.0.0
4
+ Summary: 🧟‍♂️ Zombie VDP – Ultimate Identity Edition
5
+ Home-page: https://github.com/pormes-90/ZOMBIE.git
6
+ Author: Dikha Pormes
7
+ Author-email: pormesdikha90@gmail.com
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Information Technology
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Topic :: Security
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: aiohttp>=3.8
17
+ Requires-Dist: pyyaml>=6.0
18
+ Requires-Dist: dnspython>=2.3
19
+ Requires-Dist: psutil>=5.9
20
+ Requires-Dist: colorama>=0.4
21
+ Requires-Dist: beautifulsoup4>=4.12
22
+ Requires-Dist: cryptography>=41.0
23
+ Provides-Extra: full
24
+ Requires-Dist: scikit-learn>=1.3; extra == "full"
25
+ Requires-Dist: matplotlib>=3.7; extra == "full"
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: provides-extra
33
+ Dynamic: requires-dist
34
+ Dynamic: requires-python
35
+ Dynamic: summary
36
+
37
+ # 🧟‍♂️ Zombie VDP – Ultimate Identity Edition
38
+
39
+ **NASA VDP Compliant · 100% Passive · Triple Filter · Evidence Locker · Time Slice · Auto-PoC · Memory**
40
+
41
+ Zombie VDP adalah kerangka kerja bug bounty pribadi yang menggabungkan seluruh pipeline pengujian keamanan dalam satu nafas. Semua fitur dirancang dari nol, bukan meniru alat lain, melainkan menciptakan identitas sendiri: **Ninja**, **Samurai**, dan **Ghost**.
42
+
43
+ ---
44
+
45
+ ## 🔥 Fitur Legendaris
46
+
47
+ ### ⚔️ Triple Filter (Ninja · Samurai · Ghost)
48
+ - **Ninja Filter** – Hanya menerima temuan dengan bukti nyata (evidence).
49
+ - **Samurai Filter** – Hanya HIGH/CRITICAL dengan respons signifikan.
50
+ - **Ghost Filter** – Hanya confidence ≥98% atau metode timing/OOB.
51
+
52
+ ### 🧪 Zombie Deep Scan
53
+ Validasi lanjutan setelah filter: serangan timing untuk konfirmasi SQLi, dsb.
54
+
55
+ ### 🔒 Zombie Evidence Locker
56
+ Setiap temuan yang lolos filter disimpan sebagai bukti terenkripsi (format `.zombie`). Tidak bisa dibuka tanpa kunci.
57
+
58
+ ### ⏳ Zombie Time Slice
59
+ Zombie hanya beroperasi pada jam yang diizinkan (misal 02:00–05:00 UTC). Di luar jam itu, ia berhenti dan menunggu.
60
+
61
+ ### ⚡ Zombie Auto-PoC
62
+ Setiap temuan langsung dilengkapi skrip `curl` dan Python untuk mereproduksi kerentanan. Tim triase tinggal menjalankan.
63
+
64
+ ### 🧠 Zombie Memory
65
+ Jika pemindaian terhenti, Zombie mengingat titik terakhir dan bisa melanjutkan tanpa mengulang.
66
+
67
+ ### 🕸️ Zombie Crawler & Dorking (Internal)
68
+ Crawler mandiri + penyaring URL berbasis pola (tanpa search engine). 100% pasif, tidak meninggalkan jejak bot.
69
+
70
+ ### 🛡️ Scanner Kerentanan Bawaan
71
+ - Reflected XSS
72
+ - SQL Injection (error‑based + timing)
73
+ - Local File Inclusion (LFI)
74
+ - Server‑Side Template Injection (SSTI)
75
+ - Open Redirect
76
+ - Adaptive Fuzzer
77
+ - Secrets Scanner (AWS, GitHub, Slack, JWT)
78
+
79
+ ### 📊 Laporan Profesional
80
+ HTML report siap kirim ke program VDP. Ringan, rapi, hanya berisi temuan high/critical.
81
+
82
+ ---
83
+
84
+ ## 🚀 Menjalankan
85
+
86
+ ```bash
87
+ python zombie_vdp.py
@@ -0,0 +1,12 @@
1
+ MANIFEST.in
2
+ README.md
3
+ setup.py
4
+ zombie_vdp/__init__.py
5
+ zombie_vdp/config.yaml
6
+ zombie_vdp/zombie.py
7
+ zombie_vdp.egg-info/PKG-INFO
8
+ zombie_vdp.egg-info/SOURCES.txt
9
+ zombie_vdp.egg-info/dependency_links.txt
10
+ zombie_vdp.egg-info/entry_points.txt
11
+ zombie_vdp.egg-info/requires.txt
12
+ zombie_vdp.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ zombie = zombie_vdp:main
@@ -0,0 +1,11 @@
1
+ aiohttp>=3.8
2
+ pyyaml>=6.0
3
+ dnspython>=2.3
4
+ psutil>=5.9
5
+ colorama>=0.4
6
+ beautifulsoup4>=4.12
7
+ cryptography>=41.0
8
+
9
+ [full]
10
+ scikit-learn>=1.3
11
+ matplotlib>=3.7
@@ -0,0 +1 @@
1
+ zombie_vdp