porthawk 2.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.
porthawk-2.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PortHawk Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: porthawk
3
+ Version: 2.0.0
4
+ Summary: Fast multi-threaded port scanner - Nmap alternative
5
+ Author: shivarajp24
6
+ Requires-Python: >=3.10
7
+ License-File: LICENSE
8
+ Dynamic: author
9
+ Dynamic: license-file
10
+ Dynamic: requires-python
11
+ Dynamic: summary
@@ -0,0 +1,237 @@
1
+ # PortHawk 🦅
2
+
3
+ ## PortHawk — Nmap Alternative | Python Port Scanner | Network Security Tool
4
+
5
+ Keywords: port scanner, nmap alternative, python port scanner,
6
+ network scanner, vulnerability scanner, open source security tool,
7
+ port scanning tool, ethical hacking tool, penetration testing
8
+ A fast, multi-threaded port scanner written in pure Python — no dependencies required.
9
+
10
+ ```
11
+ ____ _ _ _ _
12
+ | _ \ ___ _ __| |_| | | | __ ___ _| | __
13
+ | |_) / _ \| '__| __| |_| |/ _` \ \ /\ / / |/ /
14
+ | __/ (_) | | | |_| _ | (_| |\ V V /| <
15
+ |_| \___/|_| \__|_| |_|\__,_| \_/\_/ |_|\_\
16
+ ```
17
+
18
+ > ⚠️ **Legal Notice:** Only scan systems you own or have explicit written permission to test. Unauthorized port scanning may violate laws (Computer Fraud and Abuse Act, IT Act, etc.) in your jurisdiction.
19
+
20
+ ---
21
+
22
+ ## Features
23
+
24
+ - **TCP & UDP scanning** — connect scan (no root needed) and UDP probing
25
+ - **Banner grabbing** — identify services running on open ports
26
+ - **CIDR support** — scan entire subnets (e.g. `10.0.0.0/24`)
27
+ - **Flexible port specs** — ranges, lists, named sets (`common`, `all`)
28
+ - **Multi-threaded** — up to 500 concurrent threads
29
+ - **Multiple output formats** — colored terminal table, JSON, CSV
30
+ - **Zero dependencies** — pure Python standard library only
31
+
32
+ ---
33
+
34
+ ## Installation
35
+
36
+ ### From PyPI (once published)
37
+ ```bash
38
+ pip install porthawk
39
+ ```
40
+
41
+ ### From source
42
+ ```bash
43
+ git clone https://github.com/shivarajp24/porthawk.git
44
+ cd porthawk
45
+ pip install -e .
46
+ ```
47
+
48
+ ### Run without installing
49
+ ```bash
50
+ python -m portscanner.cli <target>
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Usage
56
+
57
+ ### Basic scan (top common ports)
58
+ ```bash
59
+ porthawk scanme.nmap.org
60
+ ```
61
+
62
+ ### Specific ports
63
+ ```bash
64
+ porthawk 192.168.1.1 -p 22,80,443,8080
65
+ ```
66
+
67
+ ### Port range with banner grabbing
68
+ ```bash
69
+ porthawk 10.0.0.1 -p 1-1000 --banner
70
+ ```
71
+
72
+ ### Full scan with more threads
73
+ ```bash
74
+ porthawk 192.168.1.1 -p all --threads 300 --timeout 0.5
75
+ ```
76
+
77
+ ### Scan an entire subnet
78
+ ```bash
79
+ porthawk 192.168.1.0/24 -p common
80
+ ```
81
+
82
+ ### UDP scan
83
+ ```bash
84
+ porthawk 192.168.1.1 -p 53,67,68,69,123,161 --scan-type udp
85
+ ```
86
+
87
+ ### Save results to JSON
88
+ ```bash
89
+ porthawk 192.168.1.1 -p common --output results.json --format json
90
+ ```
91
+
92
+ ### Save results to CSV
93
+ ```bash
94
+ porthawk 192.168.1.1 -p 1-1000 --output results.csv --format csv
95
+ ```
96
+
97
+ ---
98
+
99
+ ## CLI Reference
100
+
101
+ ```
102
+ usage: porthawk [-h] [-p PORTS] [-t N] [--timeout SEC]
103
+ [--scan-type {tcp,udp}] [--banner] [--show-closed]
104
+ [-o FILE] [-f {text,json,csv}] [--no-color] [-v]
105
+ target
106
+
107
+ positional arguments:
108
+ target IP, hostname, or CIDR block
109
+
110
+ options:
111
+ -p, --ports PORTS Ports: '80', '20-25', '22,80,443', 'common', 'all'
112
+ (default: common)
113
+ -t, --threads N Concurrent threads (default: 100, max: 500)
114
+ --timeout SEC Socket timeout in seconds (default: 1.0)
115
+ --scan-type {tcp,udp} tcp or udp (default: tcp)
116
+ --banner Grab service banners from open ports
117
+ --show-closed Also show closed/filtered ports
118
+ -o, --output FILE Save results to file
119
+ -f, --format FORMAT Output format: text, json, csv (default: text)
120
+ --no-color Disable colored output
121
+ -v, --version Show version and exit
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Using as a Python Library
127
+
128
+ ```python
129
+ from portscanner import Scanner, parse_ports
130
+
131
+ ports = parse_ports("22,80,443,8000-8090")
132
+
133
+ scanner = Scanner(
134
+ host="192.168.1.1",
135
+ ports=ports,
136
+ scan_type="tcp",
137
+ threads=150,
138
+ timeout=1.0,
139
+ grab_banners=True,
140
+ )
141
+
142
+ result = scanner.run()
143
+
144
+ print(f"Scanned {result.host} in {result.duration}s")
145
+ for port in result.open_ports:
146
+ print(f" {port.port}/tcp {port.service} {port.banner}")
147
+ ```
148
+
149
+ ### Scan a CIDR with callback
150
+ ```python
151
+ from portscanner import Scanner, parse_ports, expand_cidr
152
+
153
+ ports = parse_ports("22,80,443")
154
+
155
+ for ip in expand_cidr("192.168.1.0/24"):
156
+ scanner = Scanner(host=ip, ports=ports, threads=50)
157
+ result = scanner.run(callback=lambda r: print(r) if r.state == "open" else None)
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Sample Output
163
+
164
+ ```
165
+ PORT STATE SERVICE LATENCY BANNER
166
+ -------------------------------------------------------
167
+ 22 open SSH 4.2ms SSH-2.0-OpenSSH_8.9p1
168
+ 80 open HTTP 2.1ms HTTP/1.1 200 OK
169
+ 443 open HTTPS 3.8ms HTTP/1.1 200 OK
170
+ 8080 open HTTP-Alt 2.9ms
171
+
172
+ 4 open port(s) found on scanme.nmap.org in 3.41s
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Running Tests
178
+
179
+ ```bash
180
+ pip install pytest
181
+ pytest tests/ -v
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Project Structure
187
+
188
+ ```
189
+ porthawk/
190
+ ├── portscanner/
191
+ │ ├── __init__.py # Public API
192
+ │ ├── scanner.py # Core scan engine (TCP, UDP, banner)
193
+ │ ├── utils.py # Port parsing, CIDR expansion, host resolution
194
+ │ ├── output.py # Table, JSON, CSV formatters
195
+ │ └── cli.py # argparse CLI entry point
196
+ ├── tests/
197
+ │ ├── test_scanner.py
198
+ │ └── test_utils.py
199
+ ├── pyproject.toml
200
+ ├── LICENSE
201
+ └── README.md
202
+ ```
203
+
204
+ ---
205
+
206
+ ## Comparison with Nmap
207
+
208
+ | Feature | PortHawk | Nmap |
209
+ |----------------------|-----------------|-----------------|
210
+ | Language | Python (pure) | C |
211
+ | Root required (TCP) | No | No (connect) |
212
+ | Root required (SYN) | — | Yes |
213
+ | OS fingerprinting | No | Yes |
214
+ | Script engine (NSE) | No | Yes |
215
+ | Banner grabbing | Basic | Advanced |
216
+ | Dependencies | None | libpcap |
217
+ | Install | `pip install` | System package |
218
+ | Output formats | Table/JSON/CSV | Many |
219
+
220
+ PortHawk is lighter and easier to embed in Python scripts; Nmap is more feature-complete for professional pentesting.
221
+
222
+ ---
223
+
224
+ ## Contributing
225
+
226
+ Pull requests welcome! Please open an issue first for major changes.
227
+
228
+ 1. Fork the repo
229
+ 2. Create a feature branch: `git checkout -b feature/my-feature`
230
+ 3. Run tests: `pytest tests/ -v`
231
+ 4. Submit a PR
232
+
233
+ ---
234
+
235
+ ## License
236
+
237
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: porthawk
3
+ Version: 2.0.0
4
+ Summary: Fast multi-threaded port scanner - Nmap alternative
5
+ Author: shivarajp24
6
+ Requires-Python: >=3.10
7
+ License-File: LICENSE
8
+ Dynamic: author
9
+ Dynamic: license-file
10
+ Dynamic: requires-python
11
+ Dynamic: summary
@@ -0,0 +1,23 @@
1
+ LICENSE
2
+ README.md
3
+ setup.py
4
+ porthawk.egg-info/PKG-INFO
5
+ porthawk.egg-info/SOURCES.txt
6
+ porthawk.egg-info/dependency_links.txt
7
+ porthawk.egg-info/entry_points.txt
8
+ porthawk.egg-info/top_level.txt
9
+ portscanner/__init__.py
10
+ portscanner/advanced_scan.py
11
+ portscanner/bruteforce.py
12
+ portscanner/cli.py
13
+ portscanner/discovery.py
14
+ portscanner/intel.py
15
+ portscanner/notify.py
16
+ portscanner/output.py
17
+ portscanner/proxy.py
18
+ portscanner/report.py
19
+ portscanner/scanner.py
20
+ portscanner/utils.py
21
+ portscanner/version.py
22
+ portscanner/vuln.py
23
+ portscanner/web_vuln.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ porthawk = portscanner.cli:main
@@ -0,0 +1 @@
1
+ portscanner
@@ -0,0 +1,12 @@
1
+ """PortHawk — A fast, multi-threaded port scanner."""
2
+
3
+ __version__ = "2.0.0"
4
+ __author__ = "shivarajp24"
5
+
6
+ from .scanner import Scanner, ScanResult, PortResult
7
+ from .utils import parse_ports, expand_cidr, resolve_host
8
+
9
+ __all__ = [
10
+ "Scanner", "ScanResult", "PortResult",
11
+ "parse_ports", "expand_cidr", "resolve_host",
12
+ ]
@@ -0,0 +1,219 @@
1
+ """
2
+ Advanced scanning: IP range, random order, service fingerprinting,
3
+ WAF detection, CDN detection, subdomain enumeration.
4
+ """
5
+
6
+ import socket
7
+ import random
8
+ import re
9
+ import urllib.request
10
+ import urllib.error
11
+ import ssl
12
+ import ipaddress
13
+ from concurrent.futures import ThreadPoolExecutor, as_completed
14
+
15
+
16
+ # ─── IP RANGE SCAN ──────────────────────────────────────────────────────────
17
+
18
+ def parse_ip_range(ip_range: str) -> list:
19
+ """Parse 192.168.1.1-254 into list of IPs."""
20
+ if "-" in ip_range:
21
+ base, end = ip_range.rsplit(".", 1)
22
+ start_end = end.split("-")
23
+ if len(start_end) == 2:
24
+ start, stop = int(start_end[0]), int(start_end[1])
25
+ return [f"{base}.{i}" for i in range(start, stop + 1)]
26
+ return [ip_range]
27
+
28
+
29
+ # ─── SERVICE FINGERPRINTING ─────────────────────────────────────────────────
30
+
31
+ FINGERPRINTS = {
32
+ b"SSH": "OpenSSH",
33
+ b"220": "FTP/SMTP",
34
+ b"HTTP": "HTTP Server",
35
+ b"220 ProFTPD": "ProFTPD",
36
+ b"220 FileZilla": "FileZilla FTP",
37
+ b"RFB": "VNC",
38
+ b"* OK": "IMAP",
39
+ b"+OK": "POP3",
40
+ b"AMQP": "RabbitMQ",
41
+ b"\xff\xfb": "Telnet",
42
+ }
43
+
44
+ def fingerprint_service(ip: str, port: int, timeout: float = 2.0) -> str:
45
+ """Deep service fingerprinting."""
46
+ try:
47
+ with socket.create_connection((ip, port), timeout=timeout) as s:
48
+ s.settimeout(timeout)
49
+ try:
50
+ banner = s.recv(1024)
51
+ except Exception:
52
+ banner = b""
53
+ for sig, name in FINGERPRINTS.items():
54
+ if sig in banner:
55
+ return name
56
+ # HTTP probe
57
+ try:
58
+ s.sendall(b"HEAD / HTTP/1.0\r\n\r\n")
59
+ resp = s.recv(1024)
60
+ if b"HTTP" in resp:
61
+ server = re.search(rb"Server: (.+)", resp)
62
+ if server:
63
+ return server.group(1).decode(errors="ignore").strip()
64
+ return "HTTP Server"
65
+ except Exception:
66
+ pass
67
+ if banner:
68
+ return banner[:50].decode(errors="ignore").strip()
69
+ except Exception:
70
+ pass
71
+ return ""
72
+
73
+
74
+ # ─── WAF DETECTION ──────────────────────────────────────────────────────────
75
+
76
+ WAF_SIGNATURES = {
77
+ "Cloudflare": ["cloudflare", "cf-ray", "__cfduid"],
78
+ "AWS WAF": ["awswaf", "x-amzn-requestid"],
79
+ "Akamai": ["akamai", "akamaighost"],
80
+ "Sucuri": ["sucuri", "x-sucuri-id"],
81
+ "ModSecurity": ["mod_security", "modsecurity"],
82
+ "Wordfence": ["wordfence"],
83
+ "Imperva": ["imperva", "incapsula", "visid_incap"],
84
+ "Barracuda": ["barracuda"],
85
+ "F5 BIG-IP": ["bigip", "f5"],
86
+ "Nginx WAF": ["naxsi"],
87
+ }
88
+
89
+ def detect_waf(host: str, port: int = 80, timeout: float = 5.0) -> str:
90
+ """Detect Web Application Firewall."""
91
+ scheme = "https" if port in (443, 8443) else "http"
92
+ url = f"{scheme}://{host}:{port}/?<script>alert(1)</script>"
93
+ try:
94
+ ctx = ssl.create_default_context()
95
+ ctx.check_hostname = False
96
+ ctx.verify_mode = ssl.CERT_NONE
97
+ req = urllib.request.Request(url, headers={"User-Agent": "PortHawk/2.0"})
98
+ with urllib.request.urlopen(req, timeout=timeout, context=ctx) as r:
99
+ headers_str = str(r.headers).lower()
100
+ body = r.read(2048).decode(errors="ignore").lower()
101
+ combined = headers_str + body
102
+ for waf, sigs in WAF_SIGNATURES.items():
103
+ if any(s in combined for s in sigs):
104
+ return waf
105
+ except urllib.error.HTTPError as e:
106
+ headers_str = str(e.headers).lower() if e.headers else ""
107
+ for waf, sigs in WAF_SIGNATURES.items():
108
+ if any(s in headers_str for s in sigs):
109
+ return waf
110
+ except Exception:
111
+ pass
112
+ return "None detected"
113
+
114
+
115
+ # ─── CDN DETECTION ──────────────────────────────────────────────────────────
116
+
117
+ CDN_SIGNATURES = {
118
+ "Cloudflare": ["cloudflare.com", "cf-ray"],
119
+ "Akamai": ["akamai", "akamaitech"],
120
+ "Fastly": ["fastly", "x-fastly"],
121
+ "Amazon CloudFront": ["cloudfront.net", "x-amz-cf-id"],
122
+ "Google CDN": ["google", "x-goog"],
123
+ "Azure CDN": ["azure", "x-msedge"],
124
+ "Sucuri": ["sucuri.net"],
125
+ }
126
+
127
+ def detect_cdn(host: str, port: int = 80, timeout: float = 5.0) -> str:
128
+ """Detect CDN provider."""
129
+ scheme = "https" if port in (443, 8443) else "http"
130
+ url = f"{scheme}://{host}:{port}/"
131
+ try:
132
+ ctx = ssl.create_default_context()
133
+ ctx.check_hostname = False
134
+ ctx.verify_mode = ssl.CERT_NONE
135
+ req = urllib.request.Request(url, headers={"User-Agent": "PortHawk/2.0"})
136
+ with urllib.request.urlopen(req, timeout=timeout, context=ctx) as r:
137
+ headers_str = str(r.headers).lower()
138
+ for cdn, sigs in CDN_SIGNATURES.items():
139
+ if any(s in headers_str for s in sigs):
140
+ return cdn
141
+ except Exception:
142
+ pass
143
+ return "None detected"
144
+
145
+
146
+ # ─── SUBDOMAIN ENUMERATION ──────────────────────────────────────────────────
147
+
148
+ COMMON_SUBDOMAINS = [
149
+ "www", "mail", "ftp", "admin", "api", "dev", "test", "staging",
150
+ "blog", "shop", "app", "portal", "vpn", "ssh", "smtp", "pop",
151
+ "imap", "ns1", "ns2", "mx", "remote", "webmail", "cpanel",
152
+ "dashboard", "manage", "git", "jenkins", "gitlab", "jira",
153
+ "confluence", "docs", "cdn", "media", "static", "assets",
154
+ "beta", "alpha", "demo", "backup", "secure", "login", "auth",
155
+ ]
156
+
157
+ def enumerate_subdomains(domain: str, threads: int = 50, timeout: float = 2.0) -> list:
158
+ """Enumerate common subdomains."""
159
+ found = []
160
+
161
+ def check(sub):
162
+ host = f"{sub}.{domain}"
163
+ try:
164
+ ip = socket.gethostbyname(host)
165
+ return {"subdomain": host, "ip": ip}
166
+ except Exception:
167
+ return None
168
+
169
+ with ThreadPoolExecutor(max_workers=threads) as ex:
170
+ futures = {ex.submit(check, sub): sub for sub in COMMON_SUBDOMAINS}
171
+ for f in as_completed(futures):
172
+ result = f.result()
173
+ if result:
174
+ found.append(result)
175
+
176
+ return sorted(found, key=lambda x: x["subdomain"])
177
+
178
+
179
+ # ─── GEOIP ──────────────────────────────────────────────────────────────────
180
+
181
+ def geoip_lookup(ip: str, timeout: float = 5.0) -> dict:
182
+ """GeoIP lookup using ip-api.com (free, no key needed)."""
183
+ try:
184
+ url = f"http://ip-api.com/json/{ip}?fields=country,regionName,city,isp,org,as"
185
+ req = urllib.request.Request(url, headers={"User-Agent": "PortHawk/2.0"})
186
+ with urllib.request.urlopen(req, timeout=timeout) as r:
187
+ import json
188
+ data = json.loads(r.read())
189
+ return {
190
+ "country": data.get("country", ""),
191
+ "region": data.get("regionName", ""),
192
+ "city": data.get("city", ""),
193
+ "isp": data.get("isp", ""),
194
+ "org": data.get("org", ""),
195
+ "asn": data.get("as", ""),
196
+ }
197
+ except Exception as e:
198
+ return {"error": str(e)}
199
+
200
+
201
+ # ─── EMAIL HARVESTING ────────────────────────────────────────────────────────
202
+
203
+ def harvest_emails(host: str, port: int = 80, timeout: float = 5.0) -> list:
204
+ """Find email addresses from web page source."""
205
+ scheme = "https" if port in (443, 8443) else "http"
206
+ url = f"{scheme}://{host}:{port}/"
207
+ emails = set()
208
+ try:
209
+ ctx = ssl.create_default_context()
210
+ ctx.check_hostname = False
211
+ ctx.verify_mode = ssl.CERT_NONE
212
+ req = urllib.request.Request(url, headers={"User-Agent": "PortHawk/2.0"})
213
+ with urllib.request.urlopen(req, timeout=timeout, context=ctx) as r:
214
+ body = r.read(65536).decode(errors="ignore")
215
+ found = re.findall(r"[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}", body)
216
+ emails.update(found)
217
+ except Exception:
218
+ pass
219
+ return list(emails)