eva-exploit 3.4.21__tar.gz → 3.5__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.
Files changed (27) hide show
  1. {eva_exploit-3.4.21 → eva_exploit-3.5}/PKG-INFO +5 -2
  2. {eva_exploit-3.4.21 → eva_exploit-3.5}/README.md +4 -1
  3. {eva_exploit-3.4.21 → eva_exploit-3.5}/config.py +1 -1
  4. {eva_exploit-3.4.21 → eva_exploit-3.5}/eva.py +3 -0
  5. {eva_exploit-3.4.21 → eva_exploit-3.5}/eva_exploit.egg-info/PKG-INFO +5 -2
  6. {eva_exploit-3.4.21 → eva_exploit-3.5}/eva_exploit.egg-info/SOURCES.txt +1 -0
  7. {eva_exploit-3.4.21 → eva_exploit-3.5}/modules/exploit_search.py +3 -0
  8. {eva_exploit-3.4.21 → eva_exploit-3.5}/modules/llm.py +3 -0
  9. {eva_exploit-3.4.21 → eva_exploit-3.5}/pyproject.toml +1 -1
  10. {eva_exploit-3.4.21 → eva_exploit-3.5}/sessions/eva_session.py +3 -0
  11. eva_exploit-3.5/utils/config_loader.py +132 -0
  12. {eva_exploit-3.4.21 → eva_exploit-3.5}/utils/system.py +117 -34
  13. {eva_exploit-3.4.21 → eva_exploit-3.5}/eva_exploit.egg-info/dependency_links.txt +0 -0
  14. {eva_exploit-3.4.21 → eva_exploit-3.5}/eva_exploit.egg-info/entry_points.txt +0 -0
  15. {eva_exploit-3.4.21 → eva_exploit-3.5}/eva_exploit.egg-info/requires.txt +0 -0
  16. {eva_exploit-3.4.21 → eva_exploit-3.5}/eva_exploit.egg-info/top_level.txt +0 -0
  17. {eva_exploit-3.4.21 → eva_exploit-3.5}/modules/__init__.py +0 -0
  18. {eva_exploit-3.4.21 → eva_exploit-3.5}/modules/attack_map.py +0 -0
  19. {eva_exploit-3.4.21 → eva_exploit-3.5}/modules/prompt_builder.py +0 -0
  20. {eva_exploit-3.4.21 → eva_exploit-3.5}/modules/reporting.py +0 -0
  21. {eva_exploit-3.4.21 → eva_exploit-3.5}/modules/tooling.py +0 -0
  22. {eva_exploit-3.4.21 → eva_exploit-3.5}/modules/vuln_intel.py +0 -0
  23. {eva_exploit-3.4.21 → eva_exploit-3.5}/modules/workflow.py +0 -0
  24. {eva_exploit-3.4.21 → eva_exploit-3.5}/sessions/__init__.py +0 -0
  25. {eva_exploit-3.4.21 → eva_exploit-3.5}/setup.cfg +0 -0
  26. {eva_exploit-3.4.21 → eva_exploit-3.5}/utils/__init__.py +0 -0
  27. {eva_exploit-3.4.21 → eva_exploit-3.5}/utils/ui.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eva-exploit
3
- Version: 3.4.21
3
+ Version: 3.5
4
4
  Summary: Exploit Vector Agent
5
5
  Author: ARCANGEL0
6
6
  License: MIT
@@ -249,6 +249,9 @@ eva --config
249
249
  # deletes all sessions and files
250
250
  eva --delete
251
251
 
252
+ # configure custom api and payload handler
253
+ eva --custom-api
254
+
252
255
  # vulnerability / exploit intel search
253
256
  eva --search i have a wingftp server running on version 4.7.3, find me exploits for it
254
257
 
@@ -342,7 +345,7 @@ Let me start with basic system reconnaissance to understand the target better...
342
345
  - ❌ Might be unstable or down sometimes, low stability.
343
346
 
344
347
  ### ⟅ Custom API
345
- - **Endpoint**: Configurable in `API_ENDPOINT` to use your own as you wish.
348
+ - **Endpoint**: Configurable API to use your own as you wish. Please run `eva --custom-api` to set API handler and payload
346
349
  - **About**:
347
350
  - ✅ Custom model integration
348
351
  - ✅ Modifiable as you wish
@@ -237,6 +237,9 @@ eva --config
237
237
  # deletes all sessions and files
238
238
  eva --delete
239
239
 
240
+ # configure custom api and payload handler
241
+ eva --custom-api
242
+
240
243
  # vulnerability / exploit intel search
241
244
  eva --search i have a wingftp server running on version 4.7.3, find me exploits for it
242
245
 
@@ -330,7 +333,7 @@ Let me start with basic system reconnaissance to understand the target better...
330
333
  - ❌ Might be unstable or down sometimes, low stability.
331
334
 
332
335
  ### ⟅ Custom API
333
- - **Endpoint**: Configurable in `API_ENDPOINT` to use your own as you wish.
336
+ - **Endpoint**: Configurable API to use your own as you wish. Please run `eva --custom-api` to set API handler and payload
334
337
  - **About**:
335
338
  - ✅ Custom model integration
336
339
  - ✅ Modifiable as you wish
@@ -10,7 +10,7 @@ from pathlib import Path
10
10
 
11
11
  # ================= CONFIG =================
12
12
  APP_NAME = "EVA"
13
- APP_VERSION = "3.4.21"
13
+ APP_VERSION = "3.5"
14
14
  GITHUB_REPO = "arcangel0/EVA"
15
15
  PYPI_PACKAGE = "eva-exploit"
16
16
  API_ENDPOINT = "NOT_SET"
@@ -11,6 +11,9 @@ import subprocess
11
11
  import sys
12
12
  import time
13
13
  import shutil
14
+ from utils.config_loader import ensure_config_module
15
+
16
+ ensure_config_module()
14
17
  import config as config_module
15
18
  # ============ Check modules, and autoinstall if not present ============
16
19
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eva-exploit
3
- Version: 3.4.21
3
+ Version: 3.5
4
4
  Summary: Exploit Vector Agent
5
5
  Author: ARCANGEL0
6
6
  License: MIT
@@ -249,6 +249,9 @@ eva --config
249
249
  # deletes all sessions and files
250
250
  eva --delete
251
251
 
252
+ # configure custom api and payload handler
253
+ eva --custom-api
254
+
252
255
  # vulnerability / exploit intel search
253
256
  eva --search i have a wingftp server running on version 4.7.3, find me exploits for it
254
257
 
@@ -342,7 +345,7 @@ Let me start with basic system reconnaissance to understand the target better...
342
345
  - ❌ Might be unstable or down sometimes, low stability.
343
346
 
344
347
  ### ⟅ Custom API
345
- - **Endpoint**: Configurable in `API_ENDPOINT` to use your own as you wish.
348
+ - **Endpoint**: Configurable API to use your own as you wish. Please run `eva --custom-api` to set API handler and payload
346
349
  - **About**:
347
350
  - ✅ Custom model integration
348
351
  - ✅ Modifiable as you wish
@@ -20,5 +20,6 @@ modules/workflow.py
20
20
  sessions/__init__.py
21
21
  sessions/eva_session.py
22
22
  utils/__init__.py
23
+ utils/config_loader.py
23
24
  utils/system.py
24
25
  utils/ui.py
@@ -19,6 +19,9 @@ from urllib.parse import quote_plus
19
19
  import requests
20
20
  from colorama import Fore, Style
21
21
 
22
+ from utils.config_loader import ensure_config_module
23
+
24
+ ensure_config_module()
22
25
  import config as config_module
23
26
  from config import (
24
27
  OLLAMA_API_KEY,
@@ -16,6 +16,9 @@ from pathlib import Path
16
16
  import openai
17
17
  import requests
18
18
  from colorama import Fore, Style
19
+ from utils.config_loader import ensure_config_module
20
+
21
+ ensure_config_module()
19
22
  import config as config_module
20
23
 
21
24
  from config import (
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "eva-exploit"
7
- version = "3.4.21"
7
+ version = "3.5"
8
8
  description = "Exploit Vector Agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -17,6 +17,9 @@ from datetime import datetime, timezone
17
17
 
18
18
  from colorama import Fore,Back,Style
19
19
 
20
+ from utils.config_loader import ensure_config_module
21
+
22
+ ensure_config_module()
20
23
  from config import API_ENDPOINT, MAPS_DIR, REPORTS_DIR, SESSIONS_DIR, username
21
24
  from modules.attack_map import generate_attack_map_files, open_attack_map
22
25
  from modules.exploit_search import run_exploit_search
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import importlib
4
+ import importlib.util
5
+ import sys
6
+ from importlib import metadata
7
+ from pathlib import Path
8
+
9
+
10
+ def _resolve_app_version():
11
+ try:
12
+ return metadata.version("eva-exploit")
13
+ except metadata.PackageNotFoundError:
14
+ return "3.4.3"
15
+
16
+
17
+ def _default_config_source():
18
+ app_version = _resolve_app_version()
19
+ return f"""#!/usr/bin/env python3
20
+ import getpass
21
+ from pathlib import Path
22
+
23
+ APP_NAME = "EVA"
24
+ APP_VERSION = "{app_version}"
25
+ GITHUB_REPO = "arcangel0/EVA"
26
+ PYPI_PACKAGE = "eva-exploit"
27
+ API_ENDPOINT = "NOT_SET"
28
+ CUSTOM_API_HANDLER = "custom.py"
29
+ G4F_MODEL = "gpt-oss-120b"
30
+ G4F_URL = "https://api.gpt4free.workers.dev/api/novaai/chat/completions"
31
+ OLLAMA_MODEL = "ALIENTELLIGENCE/whiterabbitv2"
32
+ SEARCHVULN_MODEL = "gpt-oss:120b-cloud"
33
+ SEARCVULN_URL = "https://ollama.com/api/chat"
34
+ OLLAMA_API_KEY = "NOT_SET"
35
+ OPENAI_API_KEY = "NOT_SET"
36
+ ANTHROPIC_API_KEY = "NOT_SET"
37
+ GEMINI_API_KEY = "NOT_SET"
38
+ ANTHROPIC_MODEL = "claude-3-5-sonnet-latest"
39
+ GEMINI_MODEL = "gemini-2.0-flash"
40
+ OLLAMA_CLOUD_TIMEOUT = 45
41
+ CONFIG_DIR = Path.home() / "EVA_data"
42
+ SESSIONS_DIR = CONFIG_DIR / "sessions"
43
+ REPORTS_DIR = CONFIG_DIR / "reports"
44
+ MAPS_DIR = CONFIG_DIR / "attack_maps"
45
+ TERMS_ACCEPTEDTHING = CONFIG_DIR / ".confirm"
46
+ try:
47
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
48
+ SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
49
+ REPORTS_DIR.mkdir(parents=True, exist_ok=True)
50
+ MAPS_DIR.mkdir(parents=True, exist_ok=True)
51
+ except OSError:
52
+ CONFIG_DIR = Path("/tmp") / "EVA_data"
53
+ SESSIONS_DIR = CONFIG_DIR / "sessions"
54
+ REPORTS_DIR = CONFIG_DIR / "reports"
55
+ MAPS_DIR = CONFIG_DIR / "attack_maps"
56
+ TERMS_ACCEPTEDTHING = CONFIG_DIR / ".confirm"
57
+ try:
58
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
59
+ SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
60
+ REPORTS_DIR.mkdir(parents=True, exist_ok=True)
61
+ MAPS_DIR.mkdir(parents=True, exist_ok=True)
62
+ except OSError:
63
+ pass
64
+ username = getpass.getuser()
65
+ MAX_RETRIES = 10
66
+ RETRY_DELAY = 10
67
+ """
68
+
69
+
70
+ def _load_module_from_path(path):
71
+ spec = importlib.util.spec_from_file_location("config", str(path))
72
+ if not spec or not spec.loader:
73
+ return None
74
+ module = importlib.util.module_from_spec(spec)
75
+ spec.loader.exec_module(module)
76
+ sys.modules["config"] = module
77
+ return module
78
+
79
+
80
+ def _load_module_from_source(source, source_name="<eva-generated-config>"):
81
+ spec = importlib.util.spec_from_loader("config", loader=None, origin=source_name)
82
+ module = importlib.util.module_from_spec(spec)
83
+ module.__file__ = source_name
84
+ exec(compile(source, source_name, "exec"), module.__dict__)
85
+ sys.modules["config"] = module
86
+ return module
87
+
88
+
89
+ def _candidate_fallback_paths():
90
+ return [
91
+ Path.home() / "EVA_data" / "config.py",
92
+ Path("/tmp") / "eva_config.py",
93
+ ]
94
+
95
+
96
+ def _load_or_create_fallback(path, source):
97
+ if path.exists():
98
+ return _load_module_from_path(path)
99
+ try:
100
+ path.parent.mkdir(parents=True, exist_ok=True)
101
+ path.write_text(source, encoding="utf-8")
102
+ except OSError:
103
+ return None
104
+ return _load_module_from_path(path)
105
+
106
+
107
+ def ensure_config_module():
108
+ existing = sys.modules.get("config")
109
+ if existing is not None:
110
+ return existing
111
+
112
+ try:
113
+ return importlib.import_module("config")
114
+ except ModuleNotFoundError:
115
+ pass
116
+
117
+ repo_config = Path(__file__).resolve().parents[1] / "config.py"
118
+ if repo_config.exists():
119
+ loaded = _load_module_from_path(repo_config)
120
+ if loaded is not None:
121
+ return loaded
122
+
123
+ source = _default_config_source()
124
+ for path in _candidate_fallback_paths():
125
+ loaded = _load_or_create_fallback(path, source)
126
+ if loaded is not None:
127
+ return loaded
128
+
129
+ return _load_module_from_source(source)
130
+
131
+
132
+ config_module = ensure_config_module()
@@ -18,6 +18,9 @@ from importlib import metadata
18
18
  from pathlib import Path
19
19
  from urllib import error, request
20
20
  import tomllib
21
+ from utils.config_loader import ensure_config_module
22
+
23
+ ensure_config_module()
21
24
  import config as config_module
22
25
 
23
26
  from colorama import Fore, Style
@@ -249,11 +252,74 @@ def _is_newer(latest, current):
249
252
  _UPDATE_STATUS_CACHE = None
250
253
 
251
254
 
255
+ def _module_git_root():
256
+ here = Path(__file__).resolve()
257
+ for base in (here.parent, *here.parents):
258
+ if (base / ".git").exists():
259
+ return base
260
+ return None
261
+
262
+
263
+ def _installed_package_version():
264
+ try:
265
+ return metadata.version(PYPI_PACKAGE)
266
+ except metadata.PackageNotFoundError:
267
+ return None
268
+
269
+
270
+ def _is_path_in_repo(raw_path, repo_root):
271
+ if not raw_path:
272
+ return False
273
+ try:
274
+ candidate = Path(raw_path).expanduser()
275
+ if not candidate.exists():
276
+ return False
277
+ candidate = candidate.resolve()
278
+ return candidate.is_relative_to(repo_root.resolve())
279
+ except OSError:
280
+ return False
281
+
282
+
283
+ def _running_from_repo_checkout(repo_root):
284
+ main_module = sys.modules.get("__main__")
285
+ main_file = getattr(main_module, "__file__", "")
286
+ if _is_path_in_repo(main_file, repo_root):
287
+ return True
288
+ argv0 = sys.argv[0] if sys.argv else ""
289
+ if argv0 and Path(argv0).expanduser().exists() and _is_path_in_repo(argv0, repo_root):
290
+ return True
291
+ return False
292
+
293
+
294
+ def _read_local_version(base_path):
295
+ pyproject = base_path / "pyproject.toml"
296
+ if pyproject.exists():
297
+ try:
298
+ data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
299
+ version = data.get("project", {}).get("version")
300
+ if version:
301
+ return str(version).strip()
302
+ except (tomllib.TOMLDecodeError, OSError):
303
+ pass
304
+
305
+ cfg_path = base_path / "config.py"
306
+ if cfg_path.exists():
307
+ try:
308
+ raw = cfg_path.read_text(encoding="utf-8")
309
+ except OSError:
310
+ return None
311
+ match = re.search(r'^APP_VERSION\s*=\s*["\']([^"\']+)["\']', raw, flags=re.MULTILINE)
312
+ if match:
313
+ return match.group(1).strip()
314
+ return None
315
+
316
+
252
317
  def _git_branch():
253
- if not Path(".git").exists():
318
+ repo_root = _module_git_root()
319
+ if repo_root is None:
254
320
  return "main"
255
321
  branch_detect = subprocess.run(
256
- ["git", "rev-parse", "--abbrev-ref", "HEAD"],
322
+ ["git", "-C", str(repo_root), "rev-parse", "--abbrev-ref", "HEAD"],
257
323
  capture_output=True,
258
324
  text=True
259
325
  )
@@ -263,13 +329,15 @@ def _git_branch():
263
329
 
264
330
 
265
331
  def _update_source():
266
- if Path(".git").exists():
332
+ repo_root = _module_git_root()
333
+ installed_version = _installed_package_version()
334
+ if repo_root is not None and command_exists("git") and _running_from_repo_checkout(repo_root):
267
335
  return "github"
268
- try:
269
- metadata.version(PYPI_PACKAGE)
336
+ if installed_version:
270
337
  return "pypi"
271
- except metadata.PackageNotFoundError:
338
+ if repo_root is not None and command_exists("git"):
272
339
  return "github"
340
+ return "pypi"
273
341
 
274
342
 
275
343
  def _can_reach_tls_host(host):
@@ -282,18 +350,25 @@ def _can_reach_tls_host(host):
282
350
 
283
351
 
284
352
  def get_current_version():
285
- try:
286
- return metadata.version(PYPI_PACKAGE)
287
- except metadata.PackageNotFoundError:
288
- pyproject = Path("pyproject.toml")
289
- if pyproject.exists():
290
- try:
291
- data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
292
- version = data.get("project", {}).get("version")
293
- if version:
294
- return version
295
- except (tomllib.TOMLDecodeError, OSError):
296
- pass
353
+ repo_root = _module_git_root()
354
+ installed_version = _installed_package_version()
355
+
356
+ if repo_root is not None and _running_from_repo_checkout(repo_root):
357
+ local_version = _read_local_version(repo_root)
358
+ if local_version:
359
+ return local_version
360
+
361
+ if installed_version:
362
+ return installed_version
363
+
364
+ if repo_root is not None:
365
+ local_version = _read_local_version(repo_root)
366
+ if local_version:
367
+ return local_version
368
+
369
+ local_version = _read_local_version(Path.cwd())
370
+ if local_version:
371
+ return local_version
297
372
  return APP_VERSION
298
373
 
299
374
 
@@ -339,7 +414,11 @@ def get_update_status(force=False):
339
414
  latest = None
340
415
  available = bool(latest) and _is_newer(latest, current)
341
416
 
342
- command = f"git pull --tags origin {branch}" if source == "github" else "eva -u"
417
+ repo_root = _module_git_root()
418
+ if source == "github" and repo_root is not None:
419
+ command = f"git -C {shlex.quote(str(repo_root))} pull --tags origin {branch}"
420
+ else:
421
+ command = "eva -u"
343
422
  prefix = "|> Update github checkout running " if source == "github" else "|> Update eva to latest version running "
344
423
 
345
424
  _UPDATE_STATUS_CACHE = {
@@ -377,21 +456,22 @@ def run_self_update():
377
456
  source = status.get("source")
378
457
  print(Style.BRIGHT + Fore.MAGENTA + f"Update {latest} found! Installing . . . . " + Style.RESET_ALL)
379
458
 
459
+ repo_root = _module_git_root()
380
460
  updated = False
381
- with open(os.devnull, "w") as devnull:
382
- if source == "github" and Path(".git").exists() and command_exists("git"):
383
- branch = _git_branch()
384
- pull_result = subprocess.run(
385
- ["git", "pull", "--tags", "origin", branch],
386
- text=True
387
- )
388
- updated = pull_result.returncode == 0
389
- else:
390
- pip_result = subprocess.run(
391
- [sys.executable, "-m", "pip", "install", "--upgrade", PYPI_PACKAGE,"--break-system-packages"],
392
- text=True
393
- )
394
- updated = pip_result.returncode == 0
461
+ if source == "github" and repo_root is not None and command_exists("git"):
462
+ branch = _git_branch()
463
+ pull_result = subprocess.run(
464
+ ["git", "-C", str(repo_root), "pull", "--tags", "origin", branch],
465
+ text=True
466
+ )
467
+ updated = pull_result.returncode == 0
468
+ else:
469
+ pip_cmd = [sys.executable, "-m", "pip", "install", "--upgrade", PYPI_PACKAGE, "--break-system-packages"]
470
+ pip_result = subprocess.run(pip_cmd, text=True, capture_output=True)
471
+ if pip_result.returncode != 0 and "no such option: --break-system-packages" in (pip_result.stderr or "").lower():
472
+ pip_cmd = [sys.executable, "-m", "pip", "install", "--upgrade", PYPI_PACKAGE]
473
+ pip_result = subprocess.run(pip_cmd, text=True)
474
+ updated = pip_result.returncode == 0
395
475
 
396
476
  print(Fore.CYAN + "Almost done . . . . ")
397
477
  if updated:
@@ -402,7 +482,10 @@ def run_self_update():
402
482
 
403
483
  print(Fore.RED + "\n[!] Could not auto-update EVA in this environment.")
404
484
  if source == "github":
405
- print(Fore.YELLOW + f"Try manually: git pull --tags origin {_git_branch()}")
485
+ if repo_root is not None:
486
+ print(Fore.YELLOW + f"Try manually: git -C {shlex.quote(str(repo_root))} pull --tags origin {_git_branch()}")
487
+ else:
488
+ print(Fore.YELLOW + f"Try manually: git pull --tags origin {_git_branch()}")
406
489
  else:
407
490
  print(Fore.YELLOW + f"Try manually: {sys.executable} -m pip install --upgrade {PYPI_PACKAGE}")
408
491
  return 1
File without changes
File without changes