gyntoolkit 2.1.1__tar.gz → 2.2.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.
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/PKG-INFO +56 -9
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/README.md +55 -8
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit/__init__.py +16 -5
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit/brute.py +6 -2
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit/cli.py +91 -3
- gyntoolkit-2.2.0/gyntoolkit/commands.py +312 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit/config.py +2 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit/core.py +1 -1
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit/export.py +90 -1
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit/i18n.py +53 -1
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit/recon.py +101 -0
- gyntoolkit-2.2.0/gyntoolkit/scan.py +305 -0
- gyntoolkit-2.2.0/gyntoolkit/web.py +125 -0
- gyntoolkit-2.2.0/gyntoolkit/wordlist.py +103 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit.egg-info/PKG-INFO +56 -9
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit.egg-info/SOURCES.txt +10 -1
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/pyproject.toml +1 -1
- gyntoolkit-2.2.0/tests/test_brute.py +30 -0
- gyntoolkit-2.2.0/tests/test_commands.py +56 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/tests/test_export.py +35 -0
- gyntoolkit-2.2.0/tests/test_scan_parse.py +47 -0
- gyntoolkit-2.2.0/tests/test_shodan.py +44 -0
- gyntoolkit-2.2.0/tests/test_web.py +67 -0
- gyntoolkit-2.2.0/tests/test_wordlist.py +69 -0
- gyntoolkit-2.1.1/gyntoolkit/scan.py +0 -150
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/LICENSE +0 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit/__main__.py +0 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit/ui.py +0 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit/utils.py +0 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit.egg-info/dependency_links.txt +0 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit.egg-info/entry_points.txt +0 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit.egg-info/requires.txt +0 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/gyntoolkit.egg-info/top_level.txt +0 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/setup.cfg +0 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/tests/test_config.py +0 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/tests/test_i18n.py +0 -0
- {gyntoolkit-2.1.1 → gyntoolkit-2.2.0}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gyntoolkit
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Canivete suíço de pentest — recon, port scan, CVE lookup e brute force.
|
|
5
5
|
Author: PH, Fl4vs
|
|
6
6
|
License-Expression: MIT
|
|
@@ -49,7 +49,7 @@ Dynamic: license-file
|
|
|
49
49
|
██████╗██╗ ██╗███╗ ██╗ ████████╗ ██████╗ ██████╗ ██╗ ██╗ ██╗██╗████████╗
|
|
50
50
|
██╔════╝╚██╗ ██╔╝████╗ ██║ ╚══██╔══╝██╔═══██╗██╔═══██╗██║ ██║ ██╔╝██║╚══██╔══╝
|
|
51
51
|
██║ ███╗╚████╔╝ ██╔██╗ ██║ ██║ ██║ ██║██║ ██║██║ █████╔╝ ██║ ██║
|
|
52
|
-
██║ ██║ ╚██╔╝ ██║╚██╗██║ ██║ ██║ ██║██║ ██║██║ ██╔═██╗ ██║ ██║ v2.
|
|
52
|
+
██║ ██║ ╚██╔╝ ██║╚██╗██║ ██║ ██║ ██║██║ ██║██║ ██╔═██╗ ██║ ██║ v2.2
|
|
53
53
|
╚██████╔╝ ██║ ██║ ╚████║ ██║ ╚██████╔╝╚██████╔╝███████╗██║ ██╗██║ ██║ by: PH,Fl4vs
|
|
54
54
|
╚═════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝
|
|
55
55
|
```
|
|
@@ -124,23 +124,30 @@ Dynamic: license-file
|
|
|
124
124
|
| 9 | **HIBP Breach Check** | Domain → known breaches via Have I Been Pwned |
|
|
125
125
|
| 10 | **MAC Vendor Lookup** | `api.macvendors.com` — OUI → vendor |
|
|
126
126
|
| 11 | **Traceroute (TCP)** | `scapy` — hops + RTT (needs privilege) |
|
|
127
|
+
| 12 | **DNS Zone Transfer (AXFR)** | `dnspython` — tries AXFR against each authoritative NS |
|
|
128
|
+
| 13 | **Web Content Discovery** | `aiohttp` — robots.txt / sitemap / security.txt + built-in path wordlist |
|
|
129
|
+
| 14 | **Shodan Host** | Full `api.shodan.io` host lookup (ports, CPEs, CVEs, tags) — needs `api_keys.shodan`; falls back to InternetDB hint without a key |
|
|
127
130
|
|
|
128
131
|
### `[2]` Brute Force
|
|
129
132
|
|
|
130
133
|
| # | Module | Details |
|
|
131
134
|
|---|--------|---------|
|
|
132
|
-
| 1 | **
|
|
133
|
-
| 2 | **
|
|
134
|
-
| 3 | **
|
|
135
|
+
| 1 | **Native wordlist** | Built-in CUPP-style generator (offline, no external clone) — case/leet variants, years, suffixes, term combos |
|
|
136
|
+
| 2 | **CUPP wordlist** | Optional wrapper for `cupp.py -i` |
|
|
137
|
+
| 3 | **SSH brute** | `paramiko`, async via `asyncio.to_thread`, concurrency `Semaphore`, delay |
|
|
138
|
+
| 4 | **HTTP brute** | `aiohttp` — Basic Auth or form POST with configurable `fail_signature` |
|
|
135
139
|
|
|
136
|
-
> Every attack requires typing
|
|
140
|
+
> Every attack requires typing the authorization word (`AUTHORIZE` / `AUTORIZO`)
|
|
141
|
+
> to confirm — no silent bypass.
|
|
137
142
|
|
|
138
143
|
### `[3]` Advanced Scanning
|
|
139
144
|
|
|
140
145
|
- **Port scan** — fast (Top 21 common ports) or full (1–65535)
|
|
141
146
|
- **SYN scan** (stealth) when privileged, automatic fallback to **TCP connect**
|
|
142
147
|
- **Banner grabbing** — async, parallel
|
|
143
|
-
- **CVE analysis** per service via **NVD API v2.0**
|
|
148
|
+
- **CVE analysis** per service via **NVD API v2.0** — parses product + version
|
|
149
|
+
from the banner and matches by **CPE** (`virtualMatchString`), falling back to
|
|
150
|
+
keyword search; rate-limited and deduplicated per banner
|
|
144
151
|
- **Host discovery** (ARP scan) by CIDR — e.g. `192.168.0.0/24`
|
|
145
152
|
- Automatic risk classification based on CVEs found
|
|
146
153
|
|
|
@@ -203,6 +210,46 @@ An interactive dark CLI opens with a numbered menu. Commands are entered at the
|
|
|
203
210
|
|
|
204
211
|
---
|
|
205
212
|
|
|
213
|
+
## Non-interactive CLI (scriptable)
|
|
214
|
+
|
|
215
|
+
Pass a subcommand to run a single action and print the result as JSON on stdout
|
|
216
|
+
(pipe-friendly) — no menu. Omit the subcommand to open the interactive menu.
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
gyntoolkit recon dns example.com --type MX # DNS lookup
|
|
220
|
+
gyntoolkit recon axfr example.com # zone transfer attempt
|
|
221
|
+
gyntoolkit recon webscan http://example.com # web content discovery
|
|
222
|
+
gyntoolkit recon shodan 1.1.1.1 # Shodan host (needs api_keys.shodan)
|
|
223
|
+
gyntoolkit recon ssl example.com --port 443 # TLS cert
|
|
224
|
+
gyntoolkit scan 127.0.0.1 --type fast # port scan + CVEs
|
|
225
|
+
gyntoolkit scan 192.168.0.0/24 # host discovery (CIDR)
|
|
226
|
+
gyntoolkit utils hash "text" --algo sha1
|
|
227
|
+
gyntoolkit utils jwt <token>
|
|
228
|
+
gyntoolkit wordlist --terms alice,fluffy,acme --years 1990,2020 --leet --save wl.txt
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Global flags (place after the subcommand): `-o/--output DIR` saves a report,
|
|
232
|
+
`-f/--format {json,html,csv,md}` picks its format, `-q/--quiet` silences stdout,
|
|
233
|
+
`--lang {en,pt}` overrides the language.
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
gyntoolkit scan scanme.example.com -o reports -f md # also save a Markdown report
|
|
237
|
+
gyntoolkit recon geo 1.1.1.1 -o reports -f csv -q # CSV only, no stdout
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Active attacks are available but require explicit authorization:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
gyntoolkit brute ssh HOST --users users.txt --passwords pass.txt --authorize
|
|
244
|
+
gyntoolkit brute http URL --users admin --passwords pass.txt --mode form \
|
|
245
|
+
--user-field user --pass-field pass --fail-signature "Invalid" --authorize
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Without `--authorize`, brute subcommands abort — you confirm you have **written
|
|
249
|
+
authorization** for the target.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
206
253
|
## Example
|
|
207
254
|
|
|
208
255
|
Target: the **local security lab** (never a third-party system).
|
|
@@ -256,8 +303,8 @@ Full walkthrough: [`docs/security-lab.md`](docs/security-lab.md) and
|
|
|
256
303
|
|
|
257
304
|
## Reports
|
|
258
305
|
|
|
259
|
-
After scans and recon lookups, the CLI offers to export results as **JSON
|
|
260
|
-
dark-themed **HTML report**. Files are written to
|
|
306
|
+
After scans and recon lookups, the CLI offers to export results as **JSON**, a
|
|
307
|
+
dark-themed **HTML report**, **CSV** or **Markdown**. Files are written to
|
|
261
308
|
`reports/<module>-<timestamp>.<fmt>` (configurable via `export.dir`; set
|
|
262
309
|
`export.auto: true` to export without prompting). Details in
|
|
263
310
|
[`docs/reports.md`](docs/reports.md).
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
██████╗██╗ ██╗███╗ ██╗ ████████╗ ██████╗ ██████╗ ██╗ ██╗ ██╗██╗████████╗
|
|
7
7
|
██╔════╝╚██╗ ██╔╝████╗ ██║ ╚══██╔══╝██╔═══██╗██╔═══██╗██║ ██║ ██╔╝██║╚══██╔══╝
|
|
8
8
|
██║ ███╗╚████╔╝ ██╔██╗ ██║ ██║ ██║ ██║██║ ██║██║ █████╔╝ ██║ ██║
|
|
9
|
-
██║ ██║ ╚██╔╝ ██║╚██╗██║ ██║ ██║ ██║██║ ██║██║ ██╔═██╗ ██║ ██║ v2.
|
|
9
|
+
██║ ██║ ╚██╔╝ ██║╚██╗██║ ██║ ██║ ██║██║ ██║██║ ██╔═██╗ ██║ ██║ v2.2
|
|
10
10
|
╚██████╔╝ ██║ ██║ ╚████║ ██║ ╚██████╔╝╚██████╔╝███████╗██║ ██╗██║ ██║ by: PH,Fl4vs
|
|
11
11
|
╚═════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝
|
|
12
12
|
```
|
|
@@ -81,23 +81,30 @@
|
|
|
81
81
|
| 9 | **HIBP Breach Check** | Domain → known breaches via Have I Been Pwned |
|
|
82
82
|
| 10 | **MAC Vendor Lookup** | `api.macvendors.com` — OUI → vendor |
|
|
83
83
|
| 11 | **Traceroute (TCP)** | `scapy` — hops + RTT (needs privilege) |
|
|
84
|
+
| 12 | **DNS Zone Transfer (AXFR)** | `dnspython` — tries AXFR against each authoritative NS |
|
|
85
|
+
| 13 | **Web Content Discovery** | `aiohttp` — robots.txt / sitemap / security.txt + built-in path wordlist |
|
|
86
|
+
| 14 | **Shodan Host** | Full `api.shodan.io` host lookup (ports, CPEs, CVEs, tags) — needs `api_keys.shodan`; falls back to InternetDB hint without a key |
|
|
84
87
|
|
|
85
88
|
### `[2]` Brute Force
|
|
86
89
|
|
|
87
90
|
| # | Module | Details |
|
|
88
91
|
|---|--------|---------|
|
|
89
|
-
| 1 | **
|
|
90
|
-
| 2 | **
|
|
91
|
-
| 3 | **
|
|
92
|
+
| 1 | **Native wordlist** | Built-in CUPP-style generator (offline, no external clone) — case/leet variants, years, suffixes, term combos |
|
|
93
|
+
| 2 | **CUPP wordlist** | Optional wrapper for `cupp.py -i` |
|
|
94
|
+
| 3 | **SSH brute** | `paramiko`, async via `asyncio.to_thread`, concurrency `Semaphore`, delay |
|
|
95
|
+
| 4 | **HTTP brute** | `aiohttp` — Basic Auth or form POST with configurable `fail_signature` |
|
|
92
96
|
|
|
93
|
-
> Every attack requires typing
|
|
97
|
+
> Every attack requires typing the authorization word (`AUTHORIZE` / `AUTORIZO`)
|
|
98
|
+
> to confirm — no silent bypass.
|
|
94
99
|
|
|
95
100
|
### `[3]` Advanced Scanning
|
|
96
101
|
|
|
97
102
|
- **Port scan** — fast (Top 21 common ports) or full (1–65535)
|
|
98
103
|
- **SYN scan** (stealth) when privileged, automatic fallback to **TCP connect**
|
|
99
104
|
- **Banner grabbing** — async, parallel
|
|
100
|
-
- **CVE analysis** per service via **NVD API v2.0**
|
|
105
|
+
- **CVE analysis** per service via **NVD API v2.0** — parses product + version
|
|
106
|
+
from the banner and matches by **CPE** (`virtualMatchString`), falling back to
|
|
107
|
+
keyword search; rate-limited and deduplicated per banner
|
|
101
108
|
- **Host discovery** (ARP scan) by CIDR — e.g. `192.168.0.0/24`
|
|
102
109
|
- Automatic risk classification based on CVEs found
|
|
103
110
|
|
|
@@ -160,6 +167,46 @@ An interactive dark CLI opens with a numbered menu. Commands are entered at the
|
|
|
160
167
|
|
|
161
168
|
---
|
|
162
169
|
|
|
170
|
+
## Non-interactive CLI (scriptable)
|
|
171
|
+
|
|
172
|
+
Pass a subcommand to run a single action and print the result as JSON on stdout
|
|
173
|
+
(pipe-friendly) — no menu. Omit the subcommand to open the interactive menu.
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
gyntoolkit recon dns example.com --type MX # DNS lookup
|
|
177
|
+
gyntoolkit recon axfr example.com # zone transfer attempt
|
|
178
|
+
gyntoolkit recon webscan http://example.com # web content discovery
|
|
179
|
+
gyntoolkit recon shodan 1.1.1.1 # Shodan host (needs api_keys.shodan)
|
|
180
|
+
gyntoolkit recon ssl example.com --port 443 # TLS cert
|
|
181
|
+
gyntoolkit scan 127.0.0.1 --type fast # port scan + CVEs
|
|
182
|
+
gyntoolkit scan 192.168.0.0/24 # host discovery (CIDR)
|
|
183
|
+
gyntoolkit utils hash "text" --algo sha1
|
|
184
|
+
gyntoolkit utils jwt <token>
|
|
185
|
+
gyntoolkit wordlist --terms alice,fluffy,acme --years 1990,2020 --leet --save wl.txt
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Global flags (place after the subcommand): `-o/--output DIR` saves a report,
|
|
189
|
+
`-f/--format {json,html,csv,md}` picks its format, `-q/--quiet` silences stdout,
|
|
190
|
+
`--lang {en,pt}` overrides the language.
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
gyntoolkit scan scanme.example.com -o reports -f md # also save a Markdown report
|
|
194
|
+
gyntoolkit recon geo 1.1.1.1 -o reports -f csv -q # CSV only, no stdout
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Active attacks are available but require explicit authorization:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
gyntoolkit brute ssh HOST --users users.txt --passwords pass.txt --authorize
|
|
201
|
+
gyntoolkit brute http URL --users admin --passwords pass.txt --mode form \
|
|
202
|
+
--user-field user --pass-field pass --fail-signature "Invalid" --authorize
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Without `--authorize`, brute subcommands abort — you confirm you have **written
|
|
206
|
+
authorization** for the target.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
163
210
|
## Example
|
|
164
211
|
|
|
165
212
|
Target: the **local security lab** (never a third-party system).
|
|
@@ -213,8 +260,8 @@ Full walkthrough: [`docs/security-lab.md`](docs/security-lab.md) and
|
|
|
213
260
|
|
|
214
261
|
## Reports
|
|
215
262
|
|
|
216
|
-
After scans and recon lookups, the CLI offers to export results as **JSON
|
|
217
|
-
dark-themed **HTML report**. Files are written to
|
|
263
|
+
After scans and recon lookups, the CLI offers to export results as **JSON**, a
|
|
264
|
+
dark-themed **HTML report**, **CSV** or **Markdown**. Files are written to
|
|
218
265
|
`reports/<module>-<timestamp>.<fmt>` (configurable via `export.dir`; set
|
|
219
266
|
`export.auto: true` to export without prompting). Details in
|
|
220
267
|
[`docs/reports.md`](docs/reports.md).
|
|
@@ -5,7 +5,7 @@ Este ``__init__`` re-exporta a API pública para manter compatibilidade com
|
|
|
5
5
|
``import gyntoolkit as g`` (usado pelo lab E2E) e pelo entry point do pyproject.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
__version__ = "2.
|
|
8
|
+
__version__ = "2.2.0"
|
|
9
9
|
|
|
10
10
|
from . import i18n, ui
|
|
11
11
|
from .brute import (
|
|
@@ -29,7 +29,7 @@ from .core import (
|
|
|
29
29
|
sanitize_input,
|
|
30
30
|
show_menu,
|
|
31
31
|
)
|
|
32
|
-
from .export import export_html, export_json, save_report
|
|
32
|
+
from .export import export_csv, export_html, export_json, export_md, save_report
|
|
33
33
|
from .recon import (
|
|
34
34
|
DNS_TYPES,
|
|
35
35
|
TECH_SIGNATURES,
|
|
@@ -41,20 +41,25 @@ from .recon import (
|
|
|
41
41
|
internetdb_lookup,
|
|
42
42
|
mac_vendor,
|
|
43
43
|
reverse_dns,
|
|
44
|
+
shodan_host,
|
|
44
45
|
ssl_inspect,
|
|
45
46
|
subdomain_enum,
|
|
46
47
|
traceroute,
|
|
47
48
|
whois_lookup,
|
|
49
|
+
zone_transfer,
|
|
48
50
|
)
|
|
49
51
|
from .scan import (
|
|
50
52
|
check_vulnerabilities,
|
|
51
53
|
connect_scan,
|
|
52
54
|
get_banner,
|
|
53
55
|
network_discovery,
|
|
56
|
+
parse_service,
|
|
54
57
|
perform_scan,
|
|
55
58
|
syn_scan,
|
|
56
59
|
)
|
|
57
60
|
from .utils import b64_decode, b64_encode, hash_file, hash_text, jwt_decode
|
|
61
|
+
from .web import COMMON_PATHS, web_discovery
|
|
62
|
+
from .wordlist import generate_wordlist
|
|
58
63
|
|
|
59
64
|
__all__ = [
|
|
60
65
|
"__version__",
|
|
@@ -63,18 +68,24 @@ __all__ = [
|
|
|
63
68
|
"clear_screen", "is_admin_windows", "sanitize_input", "show_menu",
|
|
64
69
|
# scan
|
|
65
70
|
"syn_scan", "connect_scan", "get_banner", "check_vulnerabilities",
|
|
66
|
-
"network_discovery", "perform_scan",
|
|
71
|
+
"parse_service", "network_discovery", "perform_scan",
|
|
67
72
|
# recon
|
|
68
73
|
"whois_lookup", "dns_lookup", "geo_ip", "reverse_dns", "subdomain_enum",
|
|
69
74
|
"ssl_inspect", "http_fingerprint", "internetdb_lookup", "hibp_breaches",
|
|
70
|
-
"mac_vendor", "traceroute", "
|
|
75
|
+
"mac_vendor", "traceroute", "zone_transfer", "shodan_host",
|
|
76
|
+
"escolher_tipo_dns", "DNS_TYPES", "TECH_SIGNATURES",
|
|
77
|
+
# web discovery
|
|
78
|
+
"web_discovery", "COMMON_PATHS",
|
|
79
|
+
# wordlist
|
|
80
|
+
"generate_wordlist",
|
|
71
81
|
# brute
|
|
72
82
|
"print_ethical_warning", "load_wordlist", "cupp_generate",
|
|
73
83
|
"ssh_bruteforce", "http_bruteforce",
|
|
74
84
|
# utils
|
|
75
85
|
"hash_text", "hash_file", "b64_encode", "b64_decode", "jwt_decode",
|
|
76
86
|
# config / export / ui
|
|
77
|
-
"CONFIG", "DEFAULTS", "load_config", "save_report",
|
|
87
|
+
"CONFIG", "DEFAULTS", "load_config", "save_report",
|
|
88
|
+
"export_json", "export_html", "export_csv", "export_md", "ui", "i18n",
|
|
78
89
|
# cli
|
|
79
90
|
"main_flow", "main_entry",
|
|
80
91
|
]
|
|
@@ -21,7 +21,9 @@ def print_ethical_warning(action: str) -> bool:
|
|
|
21
21
|
print(f"{Fore.RED}{i18n.t('brute.warn_crime')}{Style.RESET_ALL}")
|
|
22
22
|
print(f"{Fore.RED}{'=' * 60}{Style.RESET_ALL}")
|
|
23
23
|
confirm = input(f"{Fore.YELLOW}{i18n.t('brute.confirm')}{Style.RESET_ALL}").strip()
|
|
24
|
-
|
|
24
|
+
# Aceita a palavra localizada (en/pt) e o legado "AUTORIZO" como alias.
|
|
25
|
+
accepted = {i18n.t("brute.confirm_word").strip().upper(), "AUTORIZO"}
|
|
26
|
+
return confirm.upper() in accepted
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
def load_wordlist(path: str) -> list[str]:
|
|
@@ -158,7 +160,9 @@ async def http_bruteforce(
|
|
|
158
160
|
if mode == "basic":
|
|
159
161
|
auth = aiohttp.BasicAuth(u, p)
|
|
160
162
|
async with session.get(url, auth=auth) as r:
|
|
161
|
-
|
|
163
|
+
# Basic Auth: sucesso = 2xx. 401/403 = falha; 404/5xx
|
|
164
|
+
# NÃO são credencial válida (evita falso-positivo).
|
|
165
|
+
ok = 200 <= r.status < 300
|
|
162
166
|
else:
|
|
163
167
|
payload = {user_field: u, pass_field: p}
|
|
164
168
|
async with session.post(url, data=payload, allow_redirects=False) as r:
|
|
@@ -29,13 +29,17 @@ from .recon import (
|
|
|
29
29
|
internetdb_lookup,
|
|
30
30
|
mac_vendor,
|
|
31
31
|
reverse_dns,
|
|
32
|
+
shodan_host,
|
|
32
33
|
ssl_inspect,
|
|
33
34
|
subdomain_enum,
|
|
34
35
|
traceroute,
|
|
35
36
|
whois_lookup,
|
|
37
|
+
zone_transfer,
|
|
36
38
|
)
|
|
37
39
|
from .scan import network_discovery, perform_scan
|
|
38
40
|
from .utils import b64_decode, b64_encode, hash_file, hash_text, jwt_decode
|
|
41
|
+
from .web import web_discovery
|
|
42
|
+
from .wordlist import generate_wordlist
|
|
39
43
|
|
|
40
44
|
# Valores canônicos de scan_type (DATA, usados por perform_scan). Neutros de
|
|
41
45
|
# idioma; entradas localizadas (en/pt) são mapeadas por _normalize_scan_type.
|
|
@@ -113,6 +117,9 @@ async def main_flow():
|
|
|
113
117
|
i18n.t("menu.info.hibp"),
|
|
114
118
|
i18n.t("menu.info.macvendor"),
|
|
115
119
|
i18n.t("menu.info.traceroute"),
|
|
120
|
+
i18n.t("menu.info.axfr"),
|
|
121
|
+
i18n.t("menu.info.webscan"),
|
|
122
|
+
i18n.t("menu.info.shodan"),
|
|
116
123
|
])
|
|
117
124
|
|
|
118
125
|
if sub_choice == 1:
|
|
@@ -266,17 +273,84 @@ async def main_flow():
|
|
|
266
273
|
_offer_export({"target": target, "dport": dport, "hops": hops},
|
|
267
274
|
f"traceroute-{target}", f"Traceroute {target}")
|
|
268
275
|
|
|
276
|
+
elif sub_choice == 12:
|
|
277
|
+
domain = sanitize_input(input(_cyan("prompt.root_domain")), r"[A-Za-z0-9.-]")
|
|
278
|
+
with ui.status(i18n.t("status.axfr", d=domain)):
|
|
279
|
+
r = zone_transfer(domain)
|
|
280
|
+
if "erro" in r:
|
|
281
|
+
ui.error(r["erro"])
|
|
282
|
+
else:
|
|
283
|
+
if r.get("vulnerable"):
|
|
284
|
+
ui.error(i18n.t("msg.axfr_vulnerable"))
|
|
285
|
+
else:
|
|
286
|
+
ui.success(i18n.t("msg.axfr_safe"))
|
|
287
|
+
ui.print_kv(i18n.t("label.axfr", d=domain), r["nameservers"])
|
|
288
|
+
_offer_export(r, f"axfr-{domain}", f"Zone Transfer {domain}")
|
|
289
|
+
|
|
290
|
+
elif sub_choice == 13:
|
|
291
|
+
url = input(f"\n{Fore.CYAN}{i18n.t('prompt.url_http')}{Style.RESET_ALL}").strip()
|
|
292
|
+
with ui.status(i18n.t("status.webscan", u=url)):
|
|
293
|
+
r = await web_discovery(url)
|
|
294
|
+
if "erro" in r:
|
|
295
|
+
ui.error(r["erro"])
|
|
296
|
+
elif not r["found"]:
|
|
297
|
+
ui.notice(i18n.t("msg.webscan_none", u=url))
|
|
298
|
+
else:
|
|
299
|
+
rows = [
|
|
300
|
+
(f["status"], f["path"], f["length"], f.get("location") or "—")
|
|
301
|
+
for f in r["found"]
|
|
302
|
+
]
|
|
303
|
+
ui.print_table(i18n.t("label.webscan", u=r["base"], n=r["total"]),
|
|
304
|
+
i18n.t("table.webscan").split("|"), rows)
|
|
305
|
+
_offer_export(r, f"webscan-{url}", f"Web Discovery {url}")
|
|
306
|
+
|
|
307
|
+
elif sub_choice == 14:
|
|
308
|
+
target = sanitize_input(input(_cyan("prompt.ip_or_domain")), r"[A-Za-z0-9.:-]")
|
|
309
|
+
key = CONFIG.get("api_keys", {}).get("shodan", "")
|
|
310
|
+
with ui.status(i18n.t("status.shodan", t=target)):
|
|
311
|
+
info = shodan_host(target, api_key=key)
|
|
312
|
+
if "erro" in info:
|
|
313
|
+
ui.error(info["erro"])
|
|
314
|
+
elif "info" in info:
|
|
315
|
+
ui.notice(info["info"])
|
|
316
|
+
else:
|
|
317
|
+
ui.print_kv(i18n.t("label.shodan", t=target), info)
|
|
318
|
+
_offer_export(info, f"shodan-{target}", f"Shodan {target}")
|
|
319
|
+
|
|
269
320
|
elif choice == 2: # Brute Force
|
|
270
321
|
b = CONFIG["brute"]
|
|
271
322
|
sub_choice = show_menu(i18n.t("menu.brute.title"), [
|
|
272
323
|
i18n.t("menu.brute.cupp"),
|
|
273
324
|
i18n.t("menu.brute.ssh"),
|
|
274
325
|
i18n.t("menu.brute.http"),
|
|
326
|
+
i18n.t("menu.brute.genwl"),
|
|
275
327
|
])
|
|
276
328
|
|
|
277
329
|
if sub_choice == 1:
|
|
278
330
|
cupp_generate()
|
|
279
331
|
|
|
332
|
+
elif sub_choice == 4:
|
|
333
|
+
terms_raw = input(f"\n{Fore.CYAN}{i18n.t('prompt.wl_terms')}{Style.RESET_ALL}")
|
|
334
|
+
terms = [t for t in terms_raw.split(",") if t.strip()]
|
|
335
|
+
if not terms:
|
|
336
|
+
ui.error(i18n.t("msg.wl_empty"))
|
|
337
|
+
_pause()
|
|
338
|
+
continue
|
|
339
|
+
years_raw = input(f"{Fore.CYAN}{i18n.t('prompt.wl_years')}{Style.RESET_ALL}")
|
|
340
|
+
years = [y for y in years_raw.split(",") if y.strip()]
|
|
341
|
+
leet = input(f"{Fore.CYAN}{i18n.t('prompt.wl_leet')}{Style.RESET_ALL}").strip().lower() in ("y", "s")
|
|
342
|
+
save = input(f"{Fore.CYAN}{i18n.t('prompt.wl_save')}{Style.RESET_ALL}").strip()
|
|
343
|
+
words = generate_wordlist(terms, years=years, use_leet=leet)
|
|
344
|
+
ui.success(i18n.t("msg.wl_generated", n=len(words)))
|
|
345
|
+
if save:
|
|
346
|
+
try:
|
|
347
|
+
Path(save).expanduser().write_text("\n".join(words) + "\n", encoding="utf-8")
|
|
348
|
+
ui.success(i18n.t("msg.wl_saved", path=save))
|
|
349
|
+
except OSError as e:
|
|
350
|
+
ui.error(i18n.t("msg.export_fail", err=e))
|
|
351
|
+
else:
|
|
352
|
+
print("\n".join(words))
|
|
353
|
+
|
|
280
354
|
elif sub_choice == 2:
|
|
281
355
|
if not print_ethical_warning("Brute-force SSH"):
|
|
282
356
|
ui.error(i18n.t("msg.auth_not_confirmed"))
|
|
@@ -371,9 +445,13 @@ async def main_flow():
|
|
|
371
445
|
targets = [target]
|
|
372
446
|
|
|
373
447
|
report = {}
|
|
448
|
+
scan_concurrency = CONFIG["scan"].get("concurrency", 100)
|
|
449
|
+
nvd_key = CONFIG.get("api_keys", {}).get("nvd", "")
|
|
374
450
|
for host in targets:
|
|
375
451
|
with ui.status(i18n.t("status.scanning", h=host)):
|
|
376
|
-
results = await perform_scan(
|
|
452
|
+
results = await perform_scan(
|
|
453
|
+
host, scan_type, concurrency=scan_concurrency, nvd_api_key=nvd_key
|
|
454
|
+
)
|
|
377
455
|
report[host] = results
|
|
378
456
|
rows = [
|
|
379
457
|
(port, _scan_service_label(data["service"]), _scan_risk_label(data["risco"]),
|
|
@@ -437,8 +515,18 @@ async def main_flow():
|
|
|
437
515
|
|
|
438
516
|
|
|
439
517
|
def main_entry() -> None:
|
|
440
|
-
"""Entry point CLI (usado por pyproject scripts).
|
|
441
|
-
|
|
518
|
+
"""Entry point CLI (usado por pyproject scripts).
|
|
519
|
+
|
|
520
|
+
Com subcomando (``gyntoolkit recon dns ...``) roda a CLI não-interativa e
|
|
521
|
+
sai. Sem subcomando, abre o menu interativo clássico.
|
|
522
|
+
"""
|
|
523
|
+
from . import commands
|
|
524
|
+
|
|
525
|
+
rc = commands.run()
|
|
526
|
+
if rc != -1: # subcomando executado (ou erro) → não abre o menu
|
|
527
|
+
sys.exit(rc)
|
|
528
|
+
|
|
529
|
+
# Sem subcomando: menu interativo. i18n já foi resolvido em commands.run().
|
|
442
530
|
try:
|
|
443
531
|
if os.name == 'posix' and os.geteuid() != 0:
|
|
444
532
|
print(f"\n{Fore.RED}{i18n.t('warn.need_root')}{Style.RESET_ALL}")
|