aegis-node 0.1.0__py3-none-any.whl
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.
- aegis_node/__init__.py +4 -0
- aegis_node/__main__.py +4 -0
- aegis_node/adapters.py +128 -0
- aegis_node/agent.py +3104 -0
- aegis_node-0.1.0.dist-info/METADATA +76 -0
- aegis_node-0.1.0.dist-info/RECORD +9 -0
- aegis_node-0.1.0.dist-info/WHEEL +5 -0
- aegis_node-0.1.0.dist-info/entry_points.txt +2 -0
- aegis_node-0.1.0.dist-info/top_level.txt +1 -0
aegis_node/__init__.py
ADDED
aegis_node/__main__.py
ADDED
aegis_node/adapters.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""USB WiFi adapter detection and capability probing."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
import re
|
|
6
|
+
import shutil
|
|
7
|
+
import subprocess
|
|
8
|
+
|
|
9
|
+
log = logging.getLogger('aegis.wifi_node.adapters')
|
|
10
|
+
|
|
11
|
+
# VID:PID → (chipset, driver, monitor_default, inject_default)
|
|
12
|
+
KNOWN_ADAPTERS: dict[str, tuple[str, str, bool, bool]] = {
|
|
13
|
+
# Proven pentest adapters
|
|
14
|
+
'0e8d:7612': ('MT7612U', 'mt76x2u', True, True),
|
|
15
|
+
'148f:761a': ('MT7612U', 'mt76x2u', True, True),
|
|
16
|
+
'0b05:17d1': ('MT7612U', 'mt76x2u', True, True), # ASUS USB-AC54
|
|
17
|
+
'0cf3:9271': ('AR9271', 'ath9k_htc', True, True), # Alfa AWUS036NHA
|
|
18
|
+
'0bda:8812': ('RTL8812AU', 'rtl8812au', True, True),
|
|
19
|
+
'0bda:881a': ('RTL8812AU', 'rtl8812au', True, True),
|
|
20
|
+
'0846:9052': ('RTL8812AU', 'rtl8812au', True, True), # Netgear A6100
|
|
21
|
+
'0bda:8187': ('RTL8187L', 'rtl8187', True, True), # WIFISKY WS-980WG
|
|
22
|
+
# Managed-mode only
|
|
23
|
+
'0bda:c832': ('RTL8832CU', 'rtl8832cu', False, False), # NEWFAST NF-U353
|
|
24
|
+
'0bda:b832': ('RTL8832CU', 'rtl8832cu', False, False),
|
|
25
|
+
'0bda:c82c': ('RTL8822CU', 'rtl8822cu', False, False),
|
|
26
|
+
'0bda:8179': ('RTL8188EUS', 'rtl8188eu', False, False),
|
|
27
|
+
'2357:011e': ('RTL8812AU', 'rtl8812au', True, True), # TP-Link T4U
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _run(cmd: list[str], timeout: int = 10) -> str:
|
|
32
|
+
try:
|
|
33
|
+
r = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
|
|
34
|
+
return r.stdout + r.stderr
|
|
35
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
36
|
+
return ''
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def detect_adapters() -> list[dict]:
|
|
40
|
+
"""Detect USB WiFi adapters via lsusb + iw dev."""
|
|
41
|
+
adapters = []
|
|
42
|
+
lsusb = _run(['lsusb'])
|
|
43
|
+
for line in lsusb.splitlines():
|
|
44
|
+
m = re.match(r'Bus \d+ Device \d+: ID (\w{4}:\w{4})\s+(.*)', line)
|
|
45
|
+
if not m:
|
|
46
|
+
continue
|
|
47
|
+
vid_pid = m.group(1).lower()
|
|
48
|
+
desc = m.group(2).strip()
|
|
49
|
+
if vid_pid not in KNOWN_ADAPTERS:
|
|
50
|
+
continue
|
|
51
|
+
chipset, driver, mon_default, inj_default = KNOWN_ADAPTERS[vid_pid]
|
|
52
|
+
adapters.append({
|
|
53
|
+
'vid_pid': vid_pid,
|
|
54
|
+
'chipset': chipset,
|
|
55
|
+
'driver': driver,
|
|
56
|
+
'description': desc,
|
|
57
|
+
'cap_monitor_mode': mon_default,
|
|
58
|
+
'cap_injection': inj_default,
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
# Enrich with iw interface info
|
|
62
|
+
iw_out = _run(['iw', 'dev'])
|
|
63
|
+
ifaces = _parse_iw_dev(iw_out)
|
|
64
|
+
for a in adapters:
|
|
65
|
+
for iface in ifaces:
|
|
66
|
+
if iface.get('type') == 'managed':
|
|
67
|
+
a.setdefault('interface', iface['name'])
|
|
68
|
+
a.setdefault('mac', iface.get('addr', ''))
|
|
69
|
+
break
|
|
70
|
+
|
|
71
|
+
return adapters
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _parse_iw_dev(output: str) -> list[dict]:
|
|
75
|
+
"""Parse `iw dev` output into a list of interface dicts."""
|
|
76
|
+
ifaces = []
|
|
77
|
+
current: dict | None = None
|
|
78
|
+
for line in output.splitlines():
|
|
79
|
+
line = line.strip()
|
|
80
|
+
if line.startswith('Interface'):
|
|
81
|
+
if current:
|
|
82
|
+
ifaces.append(current)
|
|
83
|
+
current = {'name': line.split()[-1]}
|
|
84
|
+
elif current:
|
|
85
|
+
if line.startswith('addr'):
|
|
86
|
+
current['addr'] = line.split()[-1]
|
|
87
|
+
elif line.startswith('type'):
|
|
88
|
+
current['type'] = line.split()[-1]
|
|
89
|
+
if current:
|
|
90
|
+
ifaces.append(current)
|
|
91
|
+
return ifaces
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def probe_monitor_mode(interface: str) -> bool:
|
|
95
|
+
"""Test if an interface supports monitor mode via iw."""
|
|
96
|
+
if not interface:
|
|
97
|
+
return False
|
|
98
|
+
out = _run(['iw', 'phy'])
|
|
99
|
+
return 'monitor' in out.lower()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def probe_injection(interface: str) -> bool:
|
|
103
|
+
"""Test packet injection via aireplay-ng (requires monitor mode active)."""
|
|
104
|
+
if not shutil.which('aireplay-ng'):
|
|
105
|
+
return False
|
|
106
|
+
out = _run(['aireplay-ng', '--test', interface], timeout=15)
|
|
107
|
+
return 'Injection is working!' in out
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def detect_host_tools() -> dict[str, bool]:
|
|
111
|
+
"""Check which security tools are available on the host."""
|
|
112
|
+
tools = {}
|
|
113
|
+
for tool in ('airmon-ng', 'airodump-ng', 'aireplay-ng', 'aircrack-ng',
|
|
114
|
+
'nmap', 'hashcat', 'hcxdumptool', 'hcxpcapngtool',
|
|
115
|
+
'hostapd', 'dnsmasq', 'tcpdump', 'tshark', 'iw', 'iwconfig',
|
|
116
|
+
'reaver', 'arpspoof', 'macchanger'):
|
|
117
|
+
tools[tool] = shutil.which(tool) is not None
|
|
118
|
+
return tools
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_host_info() -> dict:
|
|
122
|
+
"""Collect host OS and hostname."""
|
|
123
|
+
import platform
|
|
124
|
+
return {
|
|
125
|
+
'os': f'{platform.system()} {platform.release()}',
|
|
126
|
+
'hostname': platform.node(),
|
|
127
|
+
'tools': detect_host_tools(),
|
|
128
|
+
}
|