nexus-scan 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.
- nexus_scan-1.0.0/PKG-INFO +11 -0
- nexus_scan-1.0.0/README.md +1 -0
- nexus_scan-1.0.0/nexus/__init__.py +0 -0
- nexus_scan-1.0.0/nexus/cli.py +499 -0
- nexus_scan-1.0.0/nexus_scan.egg-info/PKG-INFO +11 -0
- nexus_scan-1.0.0/nexus_scan.egg-info/SOURCES.txt +11 -0
- nexus_scan-1.0.0/nexus_scan.egg-info/dependency_links.txt +1 -0
- nexus_scan-1.0.0/nexus_scan.egg-info/entry_points.txt +2 -0
- nexus_scan-1.0.0/nexus_scan.egg-info/requires.txt +2 -0
- nexus_scan-1.0.0/nexus_scan.egg-info/top_level.txt +1 -0
- nexus_scan-1.0.0/pyproject.toml +18 -0
- nexus_scan-1.0.0/setup.cfg +4 -0
- nexus_scan-1.0.0/setup.py +17 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nexus-scan
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Advanced Recon & Network Audit Suite
|
|
5
|
+
Author: NEXUS GOAT
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: requests
|
|
9
|
+
Requires-Dist: urllib3
|
|
10
|
+
|
|
11
|
+
# Nexus Scanner Tool
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Nexus Scanner Tool
|
|
File without changes
|
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import socket
|
|
4
|
+
import ssl
|
|
5
|
+
import time
|
|
6
|
+
import http.client
|
|
7
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
8
|
+
import requests
|
|
9
|
+
import ipaddress
|
|
10
|
+
import urllib3
|
|
11
|
+
|
|
12
|
+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
13
|
+
|
|
14
|
+
# High Quality 24-bit TrueColor RGB Palette
|
|
15
|
+
def rgb(r, g, b):
|
|
16
|
+
return f"\033[38;2;{r};{g};{b}m"
|
|
17
|
+
|
|
18
|
+
RESET = "\033[0m"
|
|
19
|
+
BOLD = "\033[1m"
|
|
20
|
+
UNDERLINE = "\033[4m"
|
|
21
|
+
|
|
22
|
+
# Premium Neon Visuals
|
|
23
|
+
COLOR_BANNER = rgb(255, 35, 80) # Neon Deep Red
|
|
24
|
+
COLOR_CYAN = rgb(0, 255, 255) # Electric Cyan
|
|
25
|
+
COLOR_GREEN = rgb(50, 255, 70) # Lime Green
|
|
26
|
+
COLOR_YELLOW = rgb(255, 230, 0) # Bright Yellow
|
|
27
|
+
COLOR_PURPLE = rgb(190, 80, 255) # Neon Purple
|
|
28
|
+
COLOR_BLUE = rgb(60, 160, 255) # Sky Blue
|
|
29
|
+
COLOR_ORANGE = rgb(255, 140, 20) # Neon Orange
|
|
30
|
+
COLOR_PINK = rgb(255, 105, 180) # Hot Pink
|
|
31
|
+
COLOR_WHITE = rgb(245, 245, 255) # Ultra Ice White
|
|
32
|
+
COLOR_LINE = rgb(90, 90, 110) # Matrix Gray Border
|
|
33
|
+
|
|
34
|
+
HEADERS = {
|
|
35
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
def clean_host(target):
|
|
39
|
+
target = target.strip()
|
|
40
|
+
return target.replace("http://", "").replace("https://", "").split("/")[0]
|
|
41
|
+
|
|
42
|
+
def clear():
|
|
43
|
+
os.system('clear' if os.name != 'nt' else 'cls')
|
|
44
|
+
|
|
45
|
+
def banner():
|
|
46
|
+
clear()
|
|
47
|
+
print(f"""{COLOR_BANNER}{BOLD}
|
|
48
|
+
███╗ ██╗███████╗██╗ ██╗██╗ ██╗███████╗
|
|
49
|
+
████╗ ██║██╔════╝╚██╗██╔╝██║ ██║██╔════╝
|
|
50
|
+
██╔██╗ ██║█████╗ ╚███╔╝ ██║ ██║███████╗
|
|
51
|
+
██║╚██╗██║██╔══╝ ██╔██╗ ██║ ██║╚════██║
|
|
52
|
+
██║ ╚████║███████╗██╔╝ ██╗╚██████╔╝███████║
|
|
53
|
+
╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝{RESET}""")
|
|
54
|
+
print(f"{COLOR_LINE}──────────────────────────────────────────────────────────{RESET}")
|
|
55
|
+
print(f" {COLOR_PURPLE}{BOLD}CHANNEL{RESET} : {COLOR_CYAN}{UNDERLINE}https://t.me/DARKGLOBALNET{RESET}")
|
|
56
|
+
print(f" {COLOR_PURPLE}{BOLD}DEVELOPER{RESET} : {COLOR_WHITE}{BOLD}NEXUS GOAT{RESET}")
|
|
57
|
+
print(f" {COLOR_PURPLE}{BOLD}USERNAME{RESET} : {COLOR_GREEN}{BOLD}@V2NEXUSPRIME{RESET}")
|
|
58
|
+
print(f"{COLOR_LINE}──────────────────────────────────────────────────────────{RESET}\n")
|
|
59
|
+
|
|
60
|
+
# ==================== ADVANCED HOST PROFILER ENGINE ====================
|
|
61
|
+
class AdvancedHostEngine:
|
|
62
|
+
CDN_PROVIDERS = {
|
|
63
|
+
"Cloudflare": {
|
|
64
|
+
"headers": ["cf-ray", "cf-cache-status", "cf-request-id", "cf-visitor", "cf-connecting-ip", "cf-ipcountry", "cf-railgun", "cf-polished", "cf-apo-via"],
|
|
65
|
+
"cname": ["cloudflare.net", "cloudflare.com", "cloudflare-dns.com"]
|
|
66
|
+
},
|
|
67
|
+
"Amazon CloudFront": {
|
|
68
|
+
"headers": ["x-amz-cf-id", "x-amz-cf-pop", "x-amz-request-id"],
|
|
69
|
+
"cname": ["cloudfront.net", "amazonaws.com"]
|
|
70
|
+
},
|
|
71
|
+
"Google Cloud CDN": {
|
|
72
|
+
"headers": ["x-goog-cache-status", "x-goog-generation", "x-goog-metageneration", "x-guploader-uploadid"],
|
|
73
|
+
"cname": ["googleusercontent.com", "googlevideo.com", "google.com", "gstatic.com", "googleapis.com"]
|
|
74
|
+
},
|
|
75
|
+
"Akamai": {
|
|
76
|
+
"headers": ["x-akamai-transformed", "akamai-cache-status", "akamai-origin-hop", "x-akamai-request-id", "x-akamai-ssl-client-sid", "akamai-grn", "x-akamai-config-log-detail"],
|
|
77
|
+
"cname": ["akamai.net", "edgekey.net", "edgesuite.net", "akamaized.net", "akamaiedge.net", "akamaitechnologies.com", "akamaihd.net"]
|
|
78
|
+
},
|
|
79
|
+
"Fastly": {
|
|
80
|
+
"headers": ["fastly-debug", "x-served-by", "x-cache-hits", "x-timer", "fastly-ff", "x-fastly-request-id"],
|
|
81
|
+
"cname": ["fastly.net", "fastlylb.net"]
|
|
82
|
+
},
|
|
83
|
+
"Microsoft Azure": {
|
|
84
|
+
"headers": ["x-azure-ref", "x-azure-requestid", "x-msedge-ref", "x-ec-custom-error", "x-azure-fdid"],
|
|
85
|
+
"cname": ["azureedge.net", "msedge.net", "azure-edge.net", "trafficmanager.net", "azurefd.net"]
|
|
86
|
+
},
|
|
87
|
+
"BunnyCDN": {
|
|
88
|
+
"headers": ["cdn-pullzone", "cdn-uid", "cdn-requestid", "cdn-cache", "cdn-zone", "bunnycdn-cache-tag"],
|
|
89
|
+
"cname": ["b-cdn.net"]
|
|
90
|
+
},
|
|
91
|
+
"Sucuri": {
|
|
92
|
+
"headers": ["x-sucuri-id", "x-sucuri-cache", "x-sucuri-block", "server-sucuri"],
|
|
93
|
+
"cname": ["sucuri.net"]
|
|
94
|
+
},
|
|
95
|
+
"Imperva": {
|
|
96
|
+
"headers": ["x-iinfo", "incap-ses", "visid-incap"],
|
|
97
|
+
"cname": ["incapdns.net", "imperva.com", "impervadns.net"]
|
|
98
|
+
},
|
|
99
|
+
"Cachefly": {
|
|
100
|
+
"headers": ["x-cf-", "server-cachefly"],
|
|
101
|
+
"cname": ["cachefly.net"]
|
|
102
|
+
},
|
|
103
|
+
"Alibaba": {
|
|
104
|
+
"headers": ["ali-cdn-", "x-oss-", "server-tengine"],
|
|
105
|
+
"cname": ["alikunlun.com", "alicdn.com"]
|
|
106
|
+
},
|
|
107
|
+
"Tencent": {
|
|
108
|
+
"headers": ["x-nws-", "x-daa-tunnel"],
|
|
109
|
+
"cname": ["qcloudcdn.com", "myqcloud.com"]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
def __init__(self, host, protocol="https", method_list=None):
|
|
114
|
+
self.host = clean_host(host)
|
|
115
|
+
self.protocol = protocol.lower()
|
|
116
|
+
self.url = f"{self.protocol}://{self.host}"
|
|
117
|
+
self.method_list = method_list or ["GET", "HEAD"]
|
|
118
|
+
self.http_headers = {}
|
|
119
|
+
|
|
120
|
+
def get_ips(self):
|
|
121
|
+
try:
|
|
122
|
+
ips = socket.getaddrinfo(self.host, None)
|
|
123
|
+
unique_ips = list(set(ip[4][0] for ip in ips))
|
|
124
|
+
print(f"\n{COLOR_CYAN}{BOLD}Resolved Network IPs:{RESET}")
|
|
125
|
+
for ip in unique_ips:
|
|
126
|
+
print(f" {COLOR_GREEN}• {COLOR_WHITE}{ip}")
|
|
127
|
+
return True
|
|
128
|
+
except socket.gaierror as e:
|
|
129
|
+
print(f"{COLOR_BANNER}[!] Error resolving hostname: {e}{RESET}")
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
def get_cname_records(self):
|
|
133
|
+
result = []
|
|
134
|
+
try:
|
|
135
|
+
answers = socket.getaddrinfo(self.host, None)
|
|
136
|
+
for answer in answers:
|
|
137
|
+
try:
|
|
138
|
+
cname = socket.gethostbyaddr(answer[4][0])[0]
|
|
139
|
+
result.append(cname.lower())
|
|
140
|
+
except (socket.herror, socket.gaierror):
|
|
141
|
+
continue
|
|
142
|
+
except (socket.herror, socket.gaierror):
|
|
143
|
+
pass
|
|
144
|
+
return result
|
|
145
|
+
|
|
146
|
+
def get_cdn(self):
|
|
147
|
+
try:
|
|
148
|
+
detected_cdns = set()
|
|
149
|
+
headers = {}
|
|
150
|
+
if self.http_headers:
|
|
151
|
+
headers = {k.lower(): str(v).lower() for k, v in self.http_headers.items()}
|
|
152
|
+
else:
|
|
153
|
+
try:
|
|
154
|
+
response = requests.get(self.url, headers=HEADERS, timeout=5, verify=False)
|
|
155
|
+
headers = {k.lower(): str(v).lower() for k, v in response.headers.items()}
|
|
156
|
+
except Exception:
|
|
157
|
+
pass
|
|
158
|
+
|
|
159
|
+
cnames = self.get_cname_records()
|
|
160
|
+
|
|
161
|
+
for provider, indicators in self.CDN_PROVIDERS.items():
|
|
162
|
+
if any(h.lower() in headers.keys() for h in indicators['headers']):
|
|
163
|
+
detected_cdns.add(provider)
|
|
164
|
+
continue
|
|
165
|
+
|
|
166
|
+
if any(cname_pattern in cname for cname in cnames for cname_pattern in indicators['cname']):
|
|
167
|
+
detected_cdns.add(provider)
|
|
168
|
+
|
|
169
|
+
print(f"\n{COLOR_CYAN}{BOLD}CDN & Shield Detection:{RESET}")
|
|
170
|
+
if detected_cdns:
|
|
171
|
+
for cdn in detected_cdns:
|
|
172
|
+
print(f" {COLOR_PINK}• {BOLD}{cdn}{RESET}")
|
|
173
|
+
else:
|
|
174
|
+
print(f" {COLOR_YELLOW}• No known CDN detected{RESET}")
|
|
175
|
+
except Exception as e:
|
|
176
|
+
print(f"{COLOR_BANNER}[!] Error checking CDN: {e}{RESET}")
|
|
177
|
+
|
|
178
|
+
def get_http_info(self):
|
|
179
|
+
def check_method(method):
|
|
180
|
+
try:
|
|
181
|
+
response = requests.request(method, self.url, headers=HEADERS, timeout=5, verify=False, allow_redirects=False)
|
|
182
|
+
return method, response.status_code, dict(response.headers)
|
|
183
|
+
except requests.exceptions.RequestException as e:
|
|
184
|
+
return method, 0, {'error': str(e)}
|
|
185
|
+
|
|
186
|
+
print(f"\n{COLOR_CYAN}{BOLD}HTTP Methods & Header Probe:{RESET}")
|
|
187
|
+
with ThreadPoolExecutor(max_workers=min(len(self.method_list), 10)) as executor:
|
|
188
|
+
futures = {executor.submit(check_method, m): m for m in self.method_list}
|
|
189
|
+
for future in as_completed(futures):
|
|
190
|
+
method, status_code, headers = future.result()
|
|
191
|
+
|
|
192
|
+
if method == "GET" and status_code > 0 and 'error' not in headers:
|
|
193
|
+
self.http_headers = headers
|
|
194
|
+
|
|
195
|
+
status_desc = http.client.responses.get(status_code, 'Unknown Code')
|
|
196
|
+
color_stat = COLOR_GREEN if status_code == 200 else (COLOR_YELLOW if status_code < 400 else COLOR_BANNER)
|
|
197
|
+
print(f"\n {COLOR_YELLOW}{BOLD}Method: {method:<7}{RESET} | {color_stat}{BOLD}Status: {status_code} {status_desc}{RESET}")
|
|
198
|
+
|
|
199
|
+
if 'error' in headers:
|
|
200
|
+
print(f" {COLOR_BANNER}Error: {headers['error']}{RESET}")
|
|
201
|
+
else:
|
|
202
|
+
for h_name in ["server", "content-type", "x-powered-by", "location"]:
|
|
203
|
+
for real_name, val in headers.items():
|
|
204
|
+
if real_name.lower() == h_name:
|
|
205
|
+
print(f" {COLOR_BLUE}{real_name}: {COLOR_WHITE}{val}{RESET}")
|
|
206
|
+
|
|
207
|
+
def get_sni_info(self):
|
|
208
|
+
if self.protocol != "https":
|
|
209
|
+
return
|
|
210
|
+
|
|
211
|
+
print(f"\n{COLOR_CYAN}{BOLD}SSL / SNI Handshake Details:{RESET}")
|
|
212
|
+
try:
|
|
213
|
+
context = ssl.create_default_context()
|
|
214
|
+
context.check_hostname = False
|
|
215
|
+
context.verify_mode = ssl.CERT_NONE
|
|
216
|
+
|
|
217
|
+
with socket.create_connection((self.host, 443), timeout=5) as sock:
|
|
218
|
+
with context.wrap_socket(sock, server_hostname=self.host) as ssock:
|
|
219
|
+
cipher = ssock.cipher()
|
|
220
|
+
print(f" {COLOR_PURPLE}• SSL Protocol :{RESET} {COLOR_WHITE}{ssock.version()}")
|
|
221
|
+
if cipher:
|
|
222
|
+
print(f" {COLOR_PURPLE}• Cipher Suite :{RESET} {COLOR_WHITE}{cipher[0]} ({cipher[1]} bits)")
|
|
223
|
+
print(f" {COLOR_PURPLE}• SNI Match :{RESET} {COLOR_GREEN}Valid ({self.host})")
|
|
224
|
+
except Exception as e:
|
|
225
|
+
print(f" {COLOR_BANNER}[!] SSL Probe Error: {e}{RESET}")
|
|
226
|
+
|
|
227
|
+
def scan(self):
|
|
228
|
+
if not self.get_ips():
|
|
229
|
+
return
|
|
230
|
+
self.get_http_info()
|
|
231
|
+
self.get_cdn()
|
|
232
|
+
self.get_sni_info()
|
|
233
|
+
|
|
234
|
+
# ==================== MAIN FUNCTIONS ====================
|
|
235
|
+
|
|
236
|
+
# [1] HOST SCANNER -> ADVANCED HOST PROBE
|
|
237
|
+
def host_scanner():
|
|
238
|
+
banner()
|
|
239
|
+
print(f"{COLOR_YELLOW}{BOLD}[*] EXECUTING: ADVANCED HOST PROBE{RESET}\n")
|
|
240
|
+
print(f" {COLOR_CYAN}[1]{RESET} {COLOR_WHITE}Single Host/Domain{RESET}")
|
|
241
|
+
print(f" {COLOR_CYAN}[2]{RESET} {COLOR_WHITE}Host List File (.txt){RESET}")
|
|
242
|
+
print(f" {COLOR_CYAN}[3]{RESET} {COLOR_WHITE}CIDR Subnet Block{RESET}\n")
|
|
243
|
+
|
|
244
|
+
choice = input(f"{COLOR_YELLOW}[?] Select Target Type (1/2/3): {COLOR_WHITE}").strip()
|
|
245
|
+
targets = []
|
|
246
|
+
|
|
247
|
+
if choice == "1":
|
|
248
|
+
h = input(f"{COLOR_CYAN}[?] Enter Host/IP: {COLOR_WHITE}").strip()
|
|
249
|
+
if h:
|
|
250
|
+
targets = [h]
|
|
251
|
+
elif choice == "2":
|
|
252
|
+
path = input(f"{COLOR_CYAN}[?] Enter Host File Path: {COLOR_WHITE}").strip()
|
|
253
|
+
if path.startswith("~/"):
|
|
254
|
+
path = os.path.expanduser(path)
|
|
255
|
+
try:
|
|
256
|
+
with open(path, "r", encoding="utf-8", errors="ignore") as f:
|
|
257
|
+
targets = [l.strip() for l in f if l.strip()]
|
|
258
|
+
except Exception as e:
|
|
259
|
+
print(f"\n{COLOR_BANNER}[!] File Error: {e}{RESET}")
|
|
260
|
+
input(f"\n{COLOR_YELLOW}Press Enter to return...{RESET}")
|
|
261
|
+
return
|
|
262
|
+
elif choice == "3":
|
|
263
|
+
cidr = input(f"{COLOR_CYAN}[?] Enter CIDR (e.g. 192.168.1.0/28): {COLOR_WHITE}").strip()
|
|
264
|
+
try:
|
|
265
|
+
net = ipaddress.ip_network(cidr, strict=False)
|
|
266
|
+
targets = [str(ip) for ip in net.hosts()]
|
|
267
|
+
except Exception:
|
|
268
|
+
print(f"\n{COLOR_BANNER}[!] Invalid CIDR format.{RESET}")
|
|
269
|
+
input(f"\n{COLOR_YELLOW}Press Enter to return...{RESET}")
|
|
270
|
+
return
|
|
271
|
+
else:
|
|
272
|
+
print(f"\n{COLOR_BANNER}[!] Invalid Option!{RESET}")
|
|
273
|
+
input(f"\n{COLOR_YELLOW}Press Enter to return...{RESET}")
|
|
274
|
+
return
|
|
275
|
+
|
|
276
|
+
ports_in = input(f"{COLOR_CYAN}[?] Enter Port(s) [Default: 80,443]: {COLOR_WHITE}").strip()
|
|
277
|
+
ports = [p.strip() for p in ports_in.split(",")] if ports_in else ["80", "443"]
|
|
278
|
+
|
|
279
|
+
method = input(f"{COLOR_CYAN}[?] HTTP Method [GET/HEAD - Default: GET]: {COLOR_WHITE}").strip().upper()
|
|
280
|
+
if method not in ["GET", "HEAD"]:
|
|
281
|
+
method = "GET"
|
|
282
|
+
|
|
283
|
+
th_in = input(f"{COLOR_CYAN}[?] Threads [Default: 30]: {COLOR_WHITE}").strip()
|
|
284
|
+
threads = int(th_in) if th_in.isdigit() else 30
|
|
285
|
+
|
|
286
|
+
out_file = input(f"{COLOR_CYAN}[?] Output File [Default: results.txt]: {COLOR_WHITE}").strip()
|
|
287
|
+
if not out_file:
|
|
288
|
+
out_file = "results.txt"
|
|
289
|
+
|
|
290
|
+
def probe_single(h, p):
|
|
291
|
+
h = clean_host(h)
|
|
292
|
+
proto = "https" if str(p) in ["443", "8443"] else "http"
|
|
293
|
+
try:
|
|
294
|
+
res = requests.request(method, f"{proto}://{h}:{p}", headers=HEADERS, timeout=4, verify=False, allow_redirects=False)
|
|
295
|
+
return {"host": h, "port": p, "status": res.status_code, "server": res.headers.get("Server", "Hidden"), "alive": True}
|
|
296
|
+
except:
|
|
297
|
+
return None
|
|
298
|
+
|
|
299
|
+
print(f"\n{COLOR_BLUE}[*] Scanning {len(targets)} host(s)...{RESET}\n")
|
|
300
|
+
valid_results = []
|
|
301
|
+
with ThreadPoolExecutor(max_workers=threads) as executor:
|
|
302
|
+
futures = [executor.submit(probe_single, h, p) for h in targets for p in ports]
|
|
303
|
+
for f in as_completed(futures):
|
|
304
|
+
res = f.result()
|
|
305
|
+
if res and res["alive"]:
|
|
306
|
+
print(f" {COLOR_GREEN}[✔] {COLOR_WHITE}{res['host']}:{res['port']:<5} {COLOR_LINE}| {COLOR_CYAN}Status: {res['status']:<8} {COLOR_LINE}| {COLOR_YELLOW}Server: {res['server']}{RESET}")
|
|
307
|
+
valid_results.append(f"{res['host']}:{res['port']} | Status: {res['status']} | Server: {res['server']}")
|
|
308
|
+
|
|
309
|
+
if valid_results:
|
|
310
|
+
with open(out_file, "w", encoding="utf-8") as out:
|
|
311
|
+
out.write("\n".join(valid_results) + "\n")
|
|
312
|
+
print(f"\n{COLOR_GREEN}[✔] Saved {len(valid_results)} active host(s) in '{out_file}'.{RESET}")
|
|
313
|
+
else:
|
|
314
|
+
print(f"\n{COLOR_BANNER}[-] No active responses.{RESET}")
|
|
315
|
+
|
|
316
|
+
input(f"\n{COLOR_YELLOW}Press Enter to return...{RESET}")
|
|
317
|
+
|
|
318
|
+
# [2] SUB HUNTER -> SUB-ASSET RADAR
|
|
319
|
+
def sub_hunter():
|
|
320
|
+
banner()
|
|
321
|
+
print(f"{COLOR_YELLOW}{BOLD}[*] EXECUTING: SUB-ASSET RADAR{RESET}\n")
|
|
322
|
+
domain = clean_host(input(f"{COLOR_CYAN}[?] Enter Target Domain: {COLOR_WHITE}"))
|
|
323
|
+
print(f"\n{COLOR_BLUE}[*] Querying Certificate Logs & Multi-APIs...{RESET}")
|
|
324
|
+
subs = set()
|
|
325
|
+
|
|
326
|
+
try:
|
|
327
|
+
r = requests.get(f"https://api.hackertarget.com/hostsearch/?q={domain}", headers=HEADERS, timeout=8).text
|
|
328
|
+
for line in r.splitlines():
|
|
329
|
+
if "," in line:
|
|
330
|
+
s = line.split(",")[0].strip()
|
|
331
|
+
if domain in s:
|
|
332
|
+
subs.add(s)
|
|
333
|
+
except:
|
|
334
|
+
pass
|
|
335
|
+
|
|
336
|
+
if len(subs) < 5:
|
|
337
|
+
try:
|
|
338
|
+
r = requests.get(f"https://crt.sh/?q=%25.{domain}&output=json", headers=HEADERS, timeout=8).json()
|
|
339
|
+
for itm in r:
|
|
340
|
+
nv = itm.get("name_value")
|
|
341
|
+
if nv:
|
|
342
|
+
for s in nv.split("\n"):
|
|
343
|
+
s = s.strip().replace("*.", "")
|
|
344
|
+
if domain in s:
|
|
345
|
+
subs.add(s)
|
|
346
|
+
except:
|
|
347
|
+
pass
|
|
348
|
+
|
|
349
|
+
if subs:
|
|
350
|
+
print(f"\n{COLOR_GREEN}[+] Sub-Assets Discovered: {COLOR_WHITE}{len(subs)}\n")
|
|
351
|
+
for s in list(subs)[:30]:
|
|
352
|
+
print(f" {COLOR_PURPLE}❯ {COLOR_WHITE}{s}{RESET}")
|
|
353
|
+
if len(subs) > 30:
|
|
354
|
+
print(f"{COLOR_YELLOW}\n...and {len(subs) - 30} more found.{RESET}")
|
|
355
|
+
else:
|
|
356
|
+
print(f"\n{COLOR_BANNER}[✖] No subdomains discovered.{RESET}")
|
|
357
|
+
|
|
358
|
+
input(f"\n{COLOR_YELLOW}Press Enter to return...{RESET}")
|
|
359
|
+
|
|
360
|
+
# [3] DNS RECORD -> CLOUD DNS RESOLVER
|
|
361
|
+
def dns_record():
|
|
362
|
+
banner()
|
|
363
|
+
print(f"{COLOR_YELLOW}{BOLD}[*] EXECUTING: CLOUD DNS RESOLVER{RESET}\n")
|
|
364
|
+
domain = clean_host(input(f"{COLOR_CYAN}[?] Enter Target Domain: {COLOR_WHITE}"))
|
|
365
|
+
types = ["A", "AAAA", "MX", "NS", "TXT"]
|
|
366
|
+
print(f"\n{COLOR_BLUE}[*] Resolving DNS mapping via Cloudflare & Google...{RESET}\n")
|
|
367
|
+
|
|
368
|
+
found = False
|
|
369
|
+
for t in types:
|
|
370
|
+
try:
|
|
371
|
+
res = requests.get(
|
|
372
|
+
f"https://cloudflare-dns.com/dns-query?name={domain}&type={t}",
|
|
373
|
+
headers={"Accept": "application/dns-json"},
|
|
374
|
+
timeout=4
|
|
375
|
+
).json()
|
|
376
|
+
for r in res.get("Answer", []):
|
|
377
|
+
print(f" {COLOR_ORANGE}[{t:<4}] {COLOR_WHITE}{r.get('data')}{RESET}")
|
|
378
|
+
found = True
|
|
379
|
+
except:
|
|
380
|
+
pass
|
|
381
|
+
|
|
382
|
+
if not found:
|
|
383
|
+
print(f"{COLOR_BANNER}[✖] DNS records not found.{RESET}")
|
|
384
|
+
|
|
385
|
+
input(f"\n{COLOR_YELLOW}Press Enter to return...{RESET}")
|
|
386
|
+
|
|
387
|
+
# [4] HOST INFO -> DEEP HOST INTEL
|
|
388
|
+
def host_info():
|
|
389
|
+
banner()
|
|
390
|
+
print(f"{COLOR_YELLOW}{BOLD}[*] EXECUTING: DEEP HOST INTEL & PROFILER{RESET}\n")
|
|
391
|
+
raw_host = input(f"{COLOR_CYAN}[?] Enter Target Host (e.g. example.com): {COLOR_WHITE}").strip()
|
|
392
|
+
target = clean_host(raw_host)
|
|
393
|
+
|
|
394
|
+
if not target:
|
|
395
|
+
print(f"{COLOR_BANNER}[!] Input empty!{RESET}")
|
|
396
|
+
input(f"\n{COLOR_YELLOW}Press Enter to return...{RESET}")
|
|
397
|
+
return
|
|
398
|
+
|
|
399
|
+
proto = input(f"{COLOR_CYAN}[?] Protocol (http/https) [Default: https]: {COLOR_WHITE}").strip().lower()
|
|
400
|
+
if proto not in ["http", "https"]:
|
|
401
|
+
proto = "https"
|
|
402
|
+
|
|
403
|
+
methods_in = input(f"{COLOR_CYAN}[?] HTTP Methods [Default: GET,HEAD,OPTIONS]: {COLOR_WHITE}").strip()
|
|
404
|
+
methods = [m.strip().upper() for m in methods_in.split(",")] if methods_in else ["GET", "HEAD", "OPTIONS"]
|
|
405
|
+
|
|
406
|
+
scanner = AdvancedHostEngine(target, protocol=proto, method_list=methods)
|
|
407
|
+
scanner.scan()
|
|
408
|
+
|
|
409
|
+
input(f"\n{COLOR_YELLOW}Press Enter to return...{RESET}")
|
|
410
|
+
|
|
411
|
+
# [5] IP LOOKUP -> IP & GEO TRACER
|
|
412
|
+
def ip_lookup():
|
|
413
|
+
banner()
|
|
414
|
+
print(f"{COLOR_YELLOW}{BOLD}[*] EXECUTING: IP & GEO TRACER{RESET}\n")
|
|
415
|
+
target = clean_host(input(f"{COLOR_CYAN}[?] Enter Host/IP: {COLOR_WHITE}"))
|
|
416
|
+
|
|
417
|
+
try:
|
|
418
|
+
ip = socket.gethostbyname(target)
|
|
419
|
+
res = requests.get(f"http://ip-api.com/json/{ip}", headers=HEADERS, timeout=6).json()
|
|
420
|
+
print(f"\n{COLOR_GREEN}[✔] Resolved IP : {COLOR_WHITE}{ip}")
|
|
421
|
+
print(f"{COLOR_GREEN}[✔] Location : {COLOR_WHITE}{res.get('country', 'N/A')}, {res.get('city', 'N/A')}")
|
|
422
|
+
print(f"{COLOR_GREEN}[✔] ISP Provider : {COLOR_WHITE}{res.get('isp', 'N/A')}")
|
|
423
|
+
print(f"{COLOR_GREEN}[✔] ASN Route : {COLOR_WHITE}{res.get('as', 'N/A')}")
|
|
424
|
+
print(f"{COLOR_GREEN}[✔] Timezone : {COLOR_WHITE}{res.get('timezone', 'N/A')}")
|
|
425
|
+
except Exception:
|
|
426
|
+
print(f"{COLOR_BANNER}[!] IP lookup failed.{RESET}")
|
|
427
|
+
|
|
428
|
+
input(f"\n{COLOR_YELLOW}Press Enter to return...{RESET}")
|
|
429
|
+
|
|
430
|
+
# [11] CIDR TO IP -> SUBNET TO IP EXTRACTOR
|
|
431
|
+
def cidr_to_ip():
|
|
432
|
+
banner()
|
|
433
|
+
print(f"{COLOR_YELLOW}{BOLD}[*] EXECUTING: SUBNET TO IP EXTRACTOR{RESET}\n")
|
|
434
|
+
cidr = input(f"{COLOR_CYAN}[?] Enter Subnet Block (e.g. 192.168.1.0/28): {COLOR_WHITE}").strip()
|
|
435
|
+
try:
|
|
436
|
+
net = ipaddress.ip_network(cidr, strict=False)
|
|
437
|
+
with open("cidr_ips.txt", "w") as f:
|
|
438
|
+
for ip in net.hosts():
|
|
439
|
+
f.write(str(ip) + "\n")
|
|
440
|
+
print(f"\n{COLOR_GREEN}[✔] Extracted host IPs saved to: {COLOR_WHITE}cidr_ips.txt{RESET}")
|
|
441
|
+
except:
|
|
442
|
+
print(f"{COLOR_BANNER}[!] Invalid Subnet mask.{RESET}")
|
|
443
|
+
input(f"\n{COLOR_YELLOW}Press Enter to return...{RESET}")
|
|
444
|
+
|
|
445
|
+
# [12] DOMAIN TO IP -> BULK DOMAIN RESOLVER
|
|
446
|
+
def domain_to_ip():
|
|
447
|
+
banner()
|
|
448
|
+
print(f"{COLOR_YELLOW}{BOLD}[*] EXECUTING: BULK DOMAIN RESOLVER{RESET}\n")
|
|
449
|
+
fname = input(f"{COLOR_CYAN}[?] Domain List File: {COLOR_WHITE}").strip()
|
|
450
|
+
if fname.startswith("~/"):
|
|
451
|
+
fname = os.path.expanduser(fname)
|
|
452
|
+
if os.path.exists(fname):
|
|
453
|
+
print(f"\n{COLOR_BLUE}[*] Resolving names to IPs...{RESET}\n")
|
|
454
|
+
out_name = f"resolved_{os.path.basename(fname)}"
|
|
455
|
+
with open(fname, 'r', encoding='utf-8', errors='ignore') as f, open(out_name, 'w') as out:
|
|
456
|
+
for line in f:
|
|
457
|
+
d = clean_host(line)
|
|
458
|
+
if d:
|
|
459
|
+
try:
|
|
460
|
+
ip = socket.gethostbyname(d)
|
|
461
|
+
out.write(f"{d} -> {ip}\n")
|
|
462
|
+
print(f" {COLOR_GREEN}[✔] {COLOR_WHITE}{d:<25} {COLOR_CYAN}-> {COLOR_GREEN}{ip}{RESET}")
|
|
463
|
+
except:
|
|
464
|
+
print(f" {COLOR_BANNER}[✖] {COLOR_WHITE}{d:<25} {COLOR_BANNER}-> Failed{RESET}")
|
|
465
|
+
print(f"\n{COLOR_GREEN}[✔] Batch complete! Output: {COLOR_WHITE}{out_name}{RESET}")
|
|
466
|
+
else:
|
|
467
|
+
print(f"{COLOR_BANNER}[!] File not found.{RESET}")
|
|
468
|
+
input(f"\n{COLOR_YELLOW}Press Enter to return...{RESET}")
|
|
469
|
+
|
|
470
|
+
# MAIN MENU CONTROLLER (CUSTOMIZED TITLES WITH HD COLOR)
|
|
471
|
+
def main():
|
|
472
|
+
while True:
|
|
473
|
+
banner()
|
|
474
|
+
print(f" {COLOR_CYAN}[1]{RESET} {COLOR_WHITE}{BOLD}ADVANCED HOST PROBE{RESET}")
|
|
475
|
+
print(f" {COLOR_PURPLE}[2]{RESET} {COLOR_WHITE}{BOLD}SUB-ASSET RADAR{RESET}")
|
|
476
|
+
print(f" {COLOR_CYAN}[3]{RESET} {COLOR_WHITE}{BOLD}CLOUD DNS RESOLVER{RESET}")
|
|
477
|
+
print(f" {COLOR_GREEN}[4]{RESET} {COLOR_WHITE}{BOLD}DEEP HOST INTEL{RESET}")
|
|
478
|
+
print(f" {COLOR_YELLOW}[5]{RESET} {COLOR_WHITE}{BOLD}IP & GEO TRACER{RESET}")
|
|
479
|
+
print(f" {COLOR_BLUE}[6]{RESET} {COLOR_WHITE}{BOLD}SUBNET TO IP EXTRACTOR{RESET}")
|
|
480
|
+
print(f" {COLOR_ORANGE}[7]{RESET} {COLOR_WHITE}{BOLD}BULK DOMAIN RESOLVER{RESET}")
|
|
481
|
+
print(f" {COLOR_BANNER}[8]{RESET} {COLOR_BANNER}{BOLD}TERMINATE / EXIT{RESET}\n")
|
|
482
|
+
|
|
483
|
+
ch = input(f"{COLOR_YELLOW}[-] Your Choice: {COLOR_WHITE}").strip()
|
|
484
|
+
|
|
485
|
+
if ch == '1': host_scanner()
|
|
486
|
+
elif ch == '2': sub_hunter()
|
|
487
|
+
elif ch == '3': dns_record()
|
|
488
|
+
elif ch == '4': host_info()
|
|
489
|
+
elif ch == '5': ip_lookup()
|
|
490
|
+
elif ch == '6': cidr_to_ip()
|
|
491
|
+
elif ch == '7': domain_to_ip()
|
|
492
|
+
elif ch == '8':
|
|
493
|
+
print(f"\n{COLOR_BANNER}[!] Session terminated. Bye!{RESET}\n")
|
|
494
|
+
sys.exit()
|
|
495
|
+
else:
|
|
496
|
+
time.sleep(0.4)
|
|
497
|
+
|
|
498
|
+
if __name__ == "__main__":
|
|
499
|
+
main()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nexus-scan
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Advanced Recon & Network Audit Suite
|
|
5
|
+
Author: NEXUS GOAT
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: requests
|
|
9
|
+
Requires-Dist: urllib3
|
|
10
|
+
|
|
11
|
+
# Nexus Scanner Tool
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
setup.py
|
|
4
|
+
nexus/__init__.py
|
|
5
|
+
nexus/cli.py
|
|
6
|
+
nexus_scan.egg-info/PKG-INFO
|
|
7
|
+
nexus_scan.egg-info/SOURCES.txt
|
|
8
|
+
nexus_scan.egg-info/dependency_links.txt
|
|
9
|
+
nexus_scan.egg-info/entry_points.txt
|
|
10
|
+
nexus_scan.egg-info/requires.txt
|
|
11
|
+
nexus_scan.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nexus
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "nexus-scan"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
authors = [{ name="NEXUS GOAT" }]
|
|
9
|
+
description = "Advanced Recon & Network Audit Suite"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"requests",
|
|
14
|
+
"urllib3"
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
nexus = "nexus.cli:main"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="nexus-scan",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
author="NEXUS GOAT",
|
|
7
|
+
description="Nexus Recon and Scanning Suite",
|
|
8
|
+
long_description="Advanced Network Scanning Suite",
|
|
9
|
+
long_description_content_type="text/markdown",
|
|
10
|
+
packages=find_packages(),
|
|
11
|
+
install_requires=["requests", "urllib3"],
|
|
12
|
+
entry_points={
|
|
13
|
+
"console_scripts": [
|
|
14
|
+
"nexus=nexus.cli:main",
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
)
|