wuhp commited on
Commit
124fd05
·
verified ·
1 Parent(s): 6723a89

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -221
app.py CHANGED
@@ -15,88 +15,93 @@ from collections import defaultdict
15
  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
16
  warnings.filterwarnings('ignore')
17
 
 
 
 
18
  # --- Enhanced Port Parsing with Multi-Port Service Detection ---
19
 
20
- def load_custom_ports(folder_path="ports") -> Dict[int, str]:
21
  """
22
  Enhanced parser that:
23
  1. Handles continuous format: '135 - MS SQL1433 - MSSQL1521 - Oracle'
24
  2. Detects services on multiple ports
25
  3. Groups related services
 
26
  """
27
  port_map = {80: "HTTP", 443: "HTTPS"}
28
  service_ports = defaultdict(list) # Track which ports belong to same service
29
 
30
- if not os.path.exists(folder_path):
31
- os.makedirs(folder_path)
32
- return port_map
 
 
 
33
 
34
- for filename in os.listdir(folder_path):
35
- if filename.endswith(('.txt', '.csv', '.conf', '.list')):
36
- file_path = os.path.join(folder_path, filename)
 
 
37
  try:
38
- with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
39
- content = f.read()
40
-
41
- # Strategy 1: Continuous format parser
42
- continuous_pattern = r'(\d+)\s*-\s*([A-Za-z][\w\s\-\.\(\)]*?)(?=\d+\s*-|$)'
43
- matches = re.findall(continuous_pattern, content, re.MULTILINE)
44
-
45
- for port_str, desc in matches:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  try:
47
  port_num = int(port_str)
48
  if 1 <= port_num <= 65535:
49
- desc = desc.strip().strip('-').strip()
50
  desc = re.sub(r'\s+', ' ', desc)
51
  if desc:
52
- # Extract base service name
53
  base_service = desc.split('-')[0].strip()
54
  service_ports[base_service].append(port_num)
55
  port_map[port_num] = desc
 
56
  except ValueError:
57
  continue
58
-
59
- # Strategy 2: Line-by-line format
60
- for line in content.split('\n'):
61
- line = line.strip()
62
- if not line or line.startswith('#'):
63
- continue
64
-
65
- if re.match(r'^\d+\s*-\s*[A-Za-z]', line):
66
- continue
67
-
68
- patterns = [
69
- r'^(.+?)\s*[:=]\s*(\d+)',
70
- r'port\s*[:=]?\s*(\d+)\s+(.+)',
71
- r'(\d+)\s*/\s*\w+\s+(.+)',
72
- r'^(\d+)\s+(.+)$',
73
- ]
74
-
75
- for pattern in patterns:
76
- match = re.match(pattern, line, re.IGNORECASE)
77
- if match:
78
- groups = match.groups()
79
-
80
- if groups[0].isdigit():
81
- port_str, desc = groups[0], groups[1]
82
- else:
83
- desc, port_str = groups[0], groups[1]
84
 
85
- try:
86
- port_num = int(port_str)
87
- if 1 <= port_num <= 65535:
88
- desc = re.sub(r'[^\w\s\-\.]+', '', desc).strip()
89
- desc = re.sub(r'\s+', ' ', desc)
90
- if desc:
91
- base_service = desc.split('-')[0].strip()
92
- service_ports[base_service].append(port_num)
93
- port_map[port_num] = desc
94
- break
95
- except ValueError:
96
- continue
97
-
98
- except Exception as e:
99
- print(f"⚠️ Error reading {filename}: {e}")
100
 
101
  # Add multi-port info to descriptions
102
  for service, ports in service_ports.items():
@@ -114,147 +119,9 @@ def load_custom_ports(folder_path="ports") -> Dict[int, str]:
114
  print(f"✅ Loaded {len(port_map)} port definitions")
115
  return port_map
116
 
 
117
 
118
- # --- IP Extraction ---
119
-
120
- def extract_ips(file_path: str) -> List[str]:
121
- """Enhanced IP extractor with validation."""
122
- try:
123
- with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
124
- content = f.read()
125
-
126
- found_ips = set(re.findall(r'\b(?:\d{1,3}\.){3}\d{1,3}\b', content))
127
-
128
- valid_ips = []
129
- for ip in found_ips:
130
- octets = [int(x) for x in ip.split('.')]
131
-
132
- if any(o > 255 for o in octets):
133
- continue
134
-
135
- if (octets[0] in [0, 127, 255] or
136
- octets[0] == 10 or
137
- (octets[0] == 172 and 16 <= octets[1] <= 31) or
138
- (octets[0] == 192 and octets[1] == 168) or
139
- (octets[0] == 169 and octets[1] == 254)):
140
- continue
141
-
142
- valid_ips.append(ip)
143
-
144
- return sorted(valid_ips)
145
- except Exception as e:
146
- print(f"Error extracting IPs: {e}")
147
- return []
148
-
149
-
150
- # --- C2 Detection ---
151
-
152
- C2_SIGNATURES = {
153
- "Cobalt Strike": ["404 Not Found", "application/ocsp-response", "BeEF", "cobaltstrike"],
154
- "Metasploit": ["Metasploit", "Mettle", "meterpreter"],
155
- "Covenant": ["covenant", "GruntHTTP", "Auth/Login"],
156
- "Empire": ["Empire", "session_id", "admin/login.php"],
157
- "Sliver": ["sliver", "implant"],
158
- "Mythic": ["mythic", "agent_message"]
159
- }
160
-
161
-
162
- def probe_target(ip: str, port: int, port_desc: str) -> Optional[Dict]:
163
- """Enhanced probe with better banner detection and multiple protocol attempts."""
164
- sock = None
165
- try:
166
- # Port connectivity check
167
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
168
- sock.settimeout(1.2)
169
- result = sock.connect_ex((ip, port))
170
-
171
- if result != 0:
172
- return None
173
-
174
- # Try to get raw banner first (works for many services)
175
- banner = "N/A"
176
- try:
177
- sock.send(b'\r\n')
178
- raw_banner = sock.recv(1024).decode('utf-8', errors='ignore').strip()
179
- if raw_banner and len(raw_banner) > 3:
180
- banner = raw_banner[:200] # First 200 chars
181
- except:
182
- pass
183
- finally:
184
- if sock:
185
- sock.close()
186
- sock = None
187
-
188
- # Try HTTP/HTTPS
189
- for protocol in ["https", "http"]:
190
- # Smart protocol selection
191
- if protocol == "https" and port not in [443, 8443, 2083, 2087, 9443, 8000, 4443]:
192
- if port < 8000: # Skip HTTPS for low ports unless common HTTPS ports
193
- continue
194
-
195
- try:
196
- resp = requests.get(
197
- f"{protocol}://{ip}:{port}",
198
- timeout=1.8,
199
- verify=False,
200
- allow_redirects=False,
201
- headers={'User-Agent': 'Mozilla/5.0'}
202
- )
203
-
204
- # Get server banner
205
- server = resp.headers.get('Server', '')
206
- powered_by = resp.headers.get('X-Powered-By', '')
207
-
208
- if server or powered_by:
209
- banner = f"{server} {powered_by}".strip()
210
- elif banner == "N/A":
211
- banner = f"HTTP {resp.status_code}"
212
-
213
- content = resp.text[:5000]
214
-
215
- category = f"Web ({port_desc})"
216
-
217
- # C2 Detection
218
- for name, sigs in C2_SIGNATURES.items():
219
- if any(sig.lower() in content.lower() or
220
- sig.lower() in str(resp.headers).lower() for sig in sigs):
221
- category = f"🚨 POTENTIAL {name}"
222
- break
223
-
224
- return {
225
- "IP": ip,
226
- "Port": port,
227
- "Service": port_desc,
228
- "Type": category,
229
- "Banner": banner
230
- }
231
- except requests.exceptions.SSLError:
232
- # SSL error on HTTP, try HTTPS
233
- if protocol == "http":
234
- continue
235
- else:
236
- break
237
- except:
238
- continue
239
-
240
- # Port is open but not HTTP
241
- return {
242
- "IP": ip,
243
- "Port": port,
244
- "Service": port_desc,
245
- "Type": "Open (Non-HTTP)",
246
- "Banner": banner if banner != "N/A" else "Unknown"
247
- }
248
-
249
- except Exception as e:
250
- return None
251
- finally:
252
- if sock:
253
- try:
254
- sock.close()
255
- except:
256
- pass
257
-
258
 
259
  def start_analysis(file_obj, max_threads: int = 50, progress=gr.Progress()):
260
  """Main analysis with pure threading."""
@@ -263,7 +130,8 @@ def start_analysis(file_obj, max_threads: int = 50, progress=gr.Progress()):
263
 
264
  try:
265
  progress(0, desc="📋 Parsing port definitions...")
266
- port_map = load_custom_ports("ports")
 
267
 
268
  progress(0.1, desc="🔍 Extracting IP addresses...")
269
  ips = extract_ips(file_obj.name)
@@ -396,8 +264,8 @@ with demo:
396
  )
397
 
398
  with gr.Column(scale=1):
399
- gr.Markdown("""
400
- ### 🔧 Port Format Support
401
 
402
  **Continuous** (your format):
403
  ```
@@ -442,26 +310,26 @@ with demo:
442
 
443
 
444
  if __name__ == "__main__":
445
- os.makedirs("ports", exist_ok=True)
446
-
447
- sample_file = "ports/common_ports.txt"
448
- if not os.path.exists(sample_file):
449
- with open(sample_file, 'w') as f:
450
- f.write("""# Common Ports
451
- 21 - FTP
452
- 22 - SSH
453
- 23 - Telnet
454
- 25 - SMTP
455
- 80 - HTTP
456
- 443 - HTTPS
457
- 3306 - MySQL
458
- 3307 - MySQL Alternate
459
- 3389 - RDP
460
- 5432 - PostgreSQL
461
- 5433 - PostgreSQL Alternate
462
- 8080 - HTTP Alt
463
- 8443 - HTTPS Alt
464
- """)
465
 
466
  demo.queue(max_size=10)
467
  demo.launch(
 
15
  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
16
  warnings.filterwarnings('ignore')
17
 
18
+ # GitHub raw URL for the ports file
19
+ GITHUB_PORTS_RAW_URL = "https://raw.githubusercontent.com/Wuhpondiscord/ports/main/common_ports.txt"
20
+
21
  # --- Enhanced Port Parsing with Multi-Port Service Detection ---
22
 
23
+ def load_custom_ports() -> Dict[int, str]:
24
  """
25
  Enhanced parser that:
26
  1. Handles continuous format: '135 - MS SQL1433 - MSSQL1521 - Oracle'
27
  2. Detects services on multiple ports
28
  3. Groups related services
29
+ Loads port definitions from a specified GitHub raw URL.
30
  """
31
  port_map = {80: "HTTP", 443: "HTTPS"}
32
  service_ports = defaultdict(list) # Track which ports belong to same service
33
 
34
+ try:
35
+ print(f"🌐 Fetching port definitions from: {GITHUB_PORTS_RAW_URL}")
36
+ response = requests.get(GITHUB_PORTS_RAW_URL, timeout=10)
37
+ response.raise_for_status() # Raise an HTTPError for bad responses (4xx or 5xx)
38
+ content = response.text
39
+ print("✅ Successfully fetched port definitions.")
40
 
41
+ # Strategy 1: Continuous format parser
42
+ continuous_pattern = r'(\d+)\s*-\s*([A-Za-z][\w\s\-\.\(\)]*?)(?=\d+\s*-|$)'
43
+ matches = re.findall(continuous_pattern, content, re.MULTILINE)
44
+
45
+ for port_str, desc in matches:
46
  try:
47
+ port_num = int(port_str)
48
+ if 1 <= port_num <= 65535:
49
+ desc = desc.strip().strip('-').strip()
50
+ desc = re.sub(r'\s+', ' ', desc)
51
+ if desc:
52
+ # Extract base service name
53
+ base_service = desc.split('-')[0].strip()
54
+ service_ports[base_service].append(port_num)
55
+ port_map[port_num] = desc
56
+ except ValueError:
57
+ continue
58
+
59
+ # Strategy 2: Line-by-line format
60
+ for line in content.split('\n'):
61
+ line = line.strip()
62
+ if not line or line.startswith('#'):
63
+ continue
64
+
65
+ # Skip if already matched by continuous pattern
66
+ if re.match(r'^\d+\s*-\s*[A-Za-z]', line):
67
+ continue
68
+
69
+ patterns = [
70
+ r'^(.+?)\s*[:=]\s*(\d+)', # e.g., MySQL: 3306
71
+ r'port\s*[:=]?\s*(\d+)\s+(.+)', # e.g., port 22 SSH
72
+ r'(\d+)\s*/\s*\w+\s+(.+)', # e.g., 22/tcp SSH
73
+ r'^(\d+)\s+(.+)$', # e.g., 22 SSH
74
+ ]
75
+
76
+ for pattern in patterns:
77
+ match = re.match(pattern, line, re.IGNORECASE)
78
+ if match:
79
+ groups = match.groups()
80
+
81
+ if groups[0].isdigit():
82
+ port_str, desc = groups[0], groups[1]
83
+ else:
84
+ desc, port_str = groups[0], groups[1]
85
+
86
  try:
87
  port_num = int(port_str)
88
  if 1 <= port_num <= 65535:
89
+ desc = re.sub(r'[^\w\s\-\.]+', '', desc).strip()
90
  desc = re.sub(r'\s+', ' ', desc)
91
  if desc:
 
92
  base_service = desc.split('-')[0].strip()
93
  service_ports[base_service].append(port_num)
94
  port_map[port_num] = desc
95
+ break
96
  except ValueError:
97
  continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
+ except requests.exceptions.RequestException as e:
100
+ print(f"⚠️ Error fetching port definitions from GitHub: {e}")
101
+ print("Using default port definitions.")
102
+ except Exception as e:
103
+ print(f"⚠️ Error parsing fetched port definitions: {e}")
104
+ print("Using default port definitions.")
 
 
 
 
 
 
 
 
 
105
 
106
  # Add multi-port info to descriptions
107
  for service, ports in service_ports.items():
 
119
  print(f"✅ Loaded {len(port_map)} port definitions")
120
  return port_map
121
 
122
+ # --- Rest of your code remains the same ---
123
 
124
+ # ... (IP Extraction, C2 Detection, Probe Target, Start Analysis, UI) ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  def start_analysis(file_obj, max_threads: int = 50, progress=gr.Progress()):
127
  """Main analysis with pure threading."""
 
130
 
131
  try:
132
  progress(0, desc="📋 Parsing port definitions...")
133
+ # Call load_custom_ports without a folder_path argument
134
+ port_map = load_custom_ports()
135
 
136
  progress(0.1, desc="🔍 Extracting IP addresses...")
137
  ips = extract_ips(file_obj.name)
 
264
  )
265
 
266
  with gr.Column(scale=1):
267
+ gr.Markdown(f"""
268
+ ### 🔧 Port Format Support (from {GITHUB_PORTS_RAW_URL.split('/')[-1]})
269
 
270
  **Continuous** (your format):
271
  ```
 
310
 
311
 
312
  if __name__ == "__main__":
313
+ # Removed local file creation, as we're now fetching from GitHub
314
+ # os.makedirs("ports", exist_ok=True)
315
+ # sample_file = "ports/common_ports.txt"
316
+ # if not os.path.exists(sample_file):
317
+ # with open(sample_file, 'w') as f:
318
+ # f.write("""# Common Ports
319
+ # 21 - FTP
320
+ # 22 - SSH
321
+ # 23 - Telnet
322
+ # 25 - SMTP
323
+ # 80 - HTTP
324
+ # 443 - HTTPS
325
+ # 3306 - MySQL
326
+ # 3307 - MySQL Alternate
327
+ # 3389 - RDP
328
+ # 5432 - PostgreSQL
329
+ # 5433 - PostgreSQL Alternate
330
+ # 8080 - HTTP Alt
331
+ # 8443 - HTTPS Alt
332
+ # """)
333
 
334
  demo.queue(max_size=10)
335
  demo.launch(