nmapui 3.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.
- nmapui-3.0.0/LICENSE +21 -0
- nmapui-3.0.0/PKG-INFO +216 -0
- nmapui-3.0.0/README.md +181 -0
- nmapui-3.0.0/nmapui.egg-info/PKG-INFO +216 -0
- nmapui-3.0.0/nmapui.egg-info/SOURCES.txt +14 -0
- nmapui-3.0.0/nmapui.egg-info/dependency_links.txt +1 -0
- nmapui-3.0.0/nmapui.egg-info/entry_points.txt +2 -0
- nmapui-3.0.0/nmapui.egg-info/requires.txt +3 -0
- nmapui-3.0.0/nmapui.egg-info/top_level.txt +1 -0
- nmapui-3.0.0/pyproject.toml +48 -0
- nmapui-3.0.0/setup.cfg +4 -0
- nmapui-3.0.0/setup.py +62 -0
- nmapui-3.0.0/tests/test_diff.py +103 -0
- nmapui-3.0.0/tests/test_explainer.py +74 -0
- nmapui-3.0.0/tests/test_storage.py +93 -0
- nmapui-3.0.0/tests/test_vuln_parser.py +95 -0
nmapui-3.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shiv Dutt Choubey
|
|
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.
|
nmapui-3.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nmapui
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: A modern, learnable GUI for nmap — scan profiles, vuln highlighting, scan diff, a built-in flag explainer, and guided lessons.
|
|
5
|
+
Home-page: https://github.com/shivduttchoubey/nmapui
|
|
6
|
+
Author: Your Name
|
|
7
|
+
Author-email: Shiv Dutt Choubey <shivduttchoubey@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/shivduttchoubey/nmapui
|
|
10
|
+
Project-URL: Issues, https://github.com/shivduttchoubey/nmapui/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/shivduttchoubey/nmapui/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: nmap,network,scanner,security,gui,tkinter,learning
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Topic :: System :: Networking
|
|
22
|
+
Classifier: Topic :: Security
|
|
23
|
+
Classifier: Environment :: X11 Applications
|
|
24
|
+
Classifier: Intended Audience :: System Administrators
|
|
25
|
+
Classifier: Intended Audience :: Education
|
|
26
|
+
Requires-Python: >=3.9
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
31
|
+
Dynamic: author
|
|
32
|
+
Dynamic: home-page
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
Dynamic: requires-python
|
|
35
|
+
|
|
36
|
+
# nmapui
|
|
37
|
+
|
|
38
|
+
**A modern, learnable GUI for nmap.** Replaces Zenmap with a dark-themed
|
|
39
|
+
interface that teaches you nmap as you use it — no command memorization,
|
|
40
|
+
no manual lookups, persistent settings across sessions.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install nmapui
|
|
44
|
+
nmapui
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
[](https://github.com/shivduttchoubey/nmapui/actions)
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Why this exists
|
|
53
|
+
|
|
54
|
+
Zenmap (the official nmap GUI) hasn't meaningfully changed in over a decade.
|
|
55
|
+
Using it well still means knowing `-sV`, `-T4`, `--script vuln`, etc. by heart.
|
|
56
|
+
nmapui keeps the real power of nmap but removes the memorization requirement —
|
|
57
|
+
and adds the pieces a learner or a day-to-day sysadmin actually wants:
|
|
58
|
+
favorites, history that survives a restart, vulnerability triage, and a
|
|
59
|
+
built-in tutorial.
|
|
60
|
+
|
|
61
|
+
| | Zenmap | nmapui |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| Dark, modern UI | ✗ | ✓ |
|
|
64
|
+
| Plain-English scan profiles | partial | ✓ 10 profiles |
|
|
65
|
+
| Live command preview | ✗ | ✓ |
|
|
66
|
+
| Flag-by-flag command explainer | ✗ | ✓ |
|
|
67
|
+
| Guided lessons / practice mode | ✗ | ✓ |
|
|
68
|
+
| Vulnerability tab (CVE + severity) | ✗ | ✓ |
|
|
69
|
+
| Scan diff / compare | ✗ | ✓ |
|
|
70
|
+
| Favorite targets | ✗ | ✓ |
|
|
71
|
+
| Settings/history persist across restarts | ✗ | ✓ (`~/.nmapui/`) |
|
|
72
|
+
| Export CSV / JSON | ✗ | ✓ |
|
|
73
|
+
| Searchable cheatsheet | ✗ | ✓ |
|
|
74
|
+
| Zero third-party dependencies | ✓ | ✓ |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Requirements
|
|
79
|
+
|
|
80
|
+
- Python 3.9+ (tkinter ships with most standard installs)
|
|
81
|
+
- The `nmap` binary on your PATH
|
|
82
|
+
- macOS: `brew install nmap`
|
|
83
|
+
- Ubuntu/Debian: `sudo apt install nmap`
|
|
84
|
+
- Windows: [nmap.org/download](https://nmap.org/download) (check "Add to PATH" during install)
|
|
85
|
+
- Winget on Windows: winget install -e --id Insecure.Nmap
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Features
|
|
91
|
+
|
|
92
|
+
### Scanner
|
|
93
|
+
10 plain-English scan profiles (Quick Ping, Common Ports, Full Port Scan,
|
|
94
|
+
Service Detection, OS Detection, Intense, Stealth SYN, UDP, Vuln Scripts,
|
|
95
|
+
Custom), a live command preview that updates as you adjust options, and a
|
|
96
|
+
results view split into Summary / Ports / Raw Output / Export tabs.
|
|
97
|
+
|
|
98
|
+
### Favorites
|
|
99
|
+
Save a target with a name ("Home Router", "Lab Server") from the Scanner
|
|
100
|
+
tab. Favorites persist in `~/.nmapui/favorites.json` and show up in a
|
|
101
|
+
dropdown next to the target field — no more retyping IPs.
|
|
102
|
+
|
|
103
|
+
### Explain
|
|
104
|
+
Paste any nmap command — your own, or one you copied from a forum post —
|
|
105
|
+
and get a flag-by-flag plain-English breakdown before you run it, including
|
|
106
|
+
a warning note on flags that are noisy, intrusive, or privileged.
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Input: nmap -sS -T4 -A --script vuln 192.168.1.0/24
|
|
110
|
+
|
|
111
|
+
-sS → TCP SYN scan ("stealth" scan)... [Note: Requires root/admin privileges]
|
|
112
|
+
-T4 → Aggressive timing...
|
|
113
|
+
-A → Aggressive scan, shorthand for -O -sV -sC --traceroute... [Note: noisy]
|
|
114
|
+
--script vuln → Run NSE vulnerability-category scripts... [Note: intrusive]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Learn
|
|
118
|
+
A short guided curriculum: what a port scan actually is, how to pick the
|
|
119
|
+
right scan for a situation, how to read the results, and how to scan
|
|
120
|
+
responsibly. Each lesson has a "Try it" button that loads a real command
|
|
121
|
+
against `scanme.nmap.org` — the official Nmap project practice host — so
|
|
122
|
+
you can learn without needing your own server or anyone's permission.
|
|
123
|
+
|
|
124
|
+
### Vulns
|
|
125
|
+
After any scan using `--script vuln` (or the Vuln Scripts profile), NSE
|
|
126
|
+
output is automatically parsed into a sortable, filterable table:
|
|
127
|
+
severity (CRITICAL/HIGH/MEDIUM/LOW/INFO), CVE numbers, CVSS scores, and a
|
|
128
|
+
detail panel with the full script output for each finding.
|
|
129
|
+
|
|
130
|
+
### Diff
|
|
131
|
+
Run two scans — say, before and after a firewall change — then compare
|
|
132
|
+
them. See exactly which hosts appeared or vanished, which ports opened or
|
|
133
|
+
closed, and which service versions changed.
|
|
134
|
+
|
|
135
|
+
### History
|
|
136
|
+
Every scan is logged with timestamp, target, command, and result counts.
|
|
137
|
+
Summary metadata (not full raw output) persists to disk in
|
|
138
|
+
`~/.nmapui/history.json`, so your log survives closing the app.
|
|
139
|
+
|
|
140
|
+
### Cheatsheet
|
|
141
|
+
24 common nmap flags with plain-English descriptions, instant search
|
|
142
|
+
filter, click-to-copy.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## CLI
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
nmapui # launch the GUI
|
|
150
|
+
nmapui --version # print version
|
|
151
|
+
nmapui --config-dir # print where settings/history/favorites live
|
|
152
|
+
nmapui --reset-config # reset saved settings to defaults
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Project layout
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
nmapui/
|
|
161
|
+
├── nmapui/
|
|
162
|
+
│ ├── __init__.py # package root (lazy-imports the GUI)
|
|
163
|
+
│ ├── __main__.py # CLI entry point
|
|
164
|
+
│ ├── gui.py # Tkinter application (UI layer)
|
|
165
|
+
│ ├── vuln_parser.py # NSE output parsing + severity classification
|
|
166
|
+
│ ├── diff.py # Scan comparison engine
|
|
167
|
+
│ ├── explainer.py # Flag-by-flag command explanations
|
|
168
|
+
│ ├── lessons.py # Content for the Learn tab
|
|
169
|
+
│ └── storage.py # Persistent settings/favorites/history
|
|
170
|
+
├── tests/ # Unit tests (no tkinter required to run)
|
|
171
|
+
├── .github/workflows/ # CI
|
|
172
|
+
├── pyproject.toml
|
|
173
|
+
├── LICENSE
|
|
174
|
+
├── CHANGELOG.md
|
|
175
|
+
└── CONTRIBUTING.md
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The logic modules (`diff.py`, `vuln_parser.py`, `explainer.py`, `storage.py`)
|
|
179
|
+
have no tkinter dependency and are independently unit tested — `gui.py` is
|
|
180
|
+
the only file that needs a display.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Running tests
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
pip install -e ".[dev]"
|
|
188
|
+
pytest
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
33 tests, no `nmap` binary or display required.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Publishing to PyPI
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pip install build twine
|
|
199
|
+
python -m build
|
|
200
|
+
twine upload dist/*
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Legal note
|
|
206
|
+
|
|
207
|
+
nmapui is a GUI front-end only — all scanning is performed by the `nmap`
|
|
208
|
+
binary on your system. Only scan networks and hosts you own or have
|
|
209
|
+
explicit permission to test. Unauthorized network scanning may be illegal
|
|
210
|
+
in your jurisdiction. The Learn tab's practice exercises use
|
|
211
|
+
`scanme.nmap.org`, a host the Nmap project explicitly maintains for this
|
|
212
|
+
purpose — be reasonable with it (light scans only).
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
MIT — see [LICENSE](LICENSE).
|
nmapui-3.0.0/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# nmapui
|
|
2
|
+
|
|
3
|
+
**A modern, learnable GUI for nmap.** Replaces Zenmap with a dark-themed
|
|
4
|
+
interface that teaches you nmap as you use it — no command memorization,
|
|
5
|
+
no manual lookups, persistent settings across sessions.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install nmapui
|
|
9
|
+
nmapui
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
[](https://github.com/shivduttchoubey/nmapui/actions)
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Why this exists
|
|
18
|
+
|
|
19
|
+
Zenmap (the official nmap GUI) hasn't meaningfully changed in over a decade.
|
|
20
|
+
Using it well still means knowing `-sV`, `-T4`, `--script vuln`, etc. by heart.
|
|
21
|
+
nmapui keeps the real power of nmap but removes the memorization requirement —
|
|
22
|
+
and adds the pieces a learner or a day-to-day sysadmin actually wants:
|
|
23
|
+
favorites, history that survives a restart, vulnerability triage, and a
|
|
24
|
+
built-in tutorial.
|
|
25
|
+
|
|
26
|
+
| | Zenmap | nmapui |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| Dark, modern UI | ✗ | ✓ |
|
|
29
|
+
| Plain-English scan profiles | partial | ✓ 10 profiles |
|
|
30
|
+
| Live command preview | ✗ | ✓ |
|
|
31
|
+
| Flag-by-flag command explainer | ✗ | ✓ |
|
|
32
|
+
| Guided lessons / practice mode | ✗ | ✓ |
|
|
33
|
+
| Vulnerability tab (CVE + severity) | ✗ | ✓ |
|
|
34
|
+
| Scan diff / compare | ✗ | ✓ |
|
|
35
|
+
| Favorite targets | ✗ | ✓ |
|
|
36
|
+
| Settings/history persist across restarts | ✗ | ✓ (`~/.nmapui/`) |
|
|
37
|
+
| Export CSV / JSON | ✗ | ✓ |
|
|
38
|
+
| Searchable cheatsheet | ✗ | ✓ |
|
|
39
|
+
| Zero third-party dependencies | ✓ | ✓ |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Requirements
|
|
44
|
+
|
|
45
|
+
- Python 3.9+ (tkinter ships with most standard installs)
|
|
46
|
+
- The `nmap` binary on your PATH
|
|
47
|
+
- macOS: `brew install nmap`
|
|
48
|
+
- Ubuntu/Debian: `sudo apt install nmap`
|
|
49
|
+
- Windows: [nmap.org/download](https://nmap.org/download) (check "Add to PATH" during install)
|
|
50
|
+
- Winget on Windows: winget install -e --id Insecure.Nmap
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
### Scanner
|
|
58
|
+
10 plain-English scan profiles (Quick Ping, Common Ports, Full Port Scan,
|
|
59
|
+
Service Detection, OS Detection, Intense, Stealth SYN, UDP, Vuln Scripts,
|
|
60
|
+
Custom), a live command preview that updates as you adjust options, and a
|
|
61
|
+
results view split into Summary / Ports / Raw Output / Export tabs.
|
|
62
|
+
|
|
63
|
+
### Favorites
|
|
64
|
+
Save a target with a name ("Home Router", "Lab Server") from the Scanner
|
|
65
|
+
tab. Favorites persist in `~/.nmapui/favorites.json` and show up in a
|
|
66
|
+
dropdown next to the target field — no more retyping IPs.
|
|
67
|
+
|
|
68
|
+
### Explain
|
|
69
|
+
Paste any nmap command — your own, or one you copied from a forum post —
|
|
70
|
+
and get a flag-by-flag plain-English breakdown before you run it, including
|
|
71
|
+
a warning note on flags that are noisy, intrusive, or privileged.
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Input: nmap -sS -T4 -A --script vuln 192.168.1.0/24
|
|
75
|
+
|
|
76
|
+
-sS → TCP SYN scan ("stealth" scan)... [Note: Requires root/admin privileges]
|
|
77
|
+
-T4 → Aggressive timing...
|
|
78
|
+
-A → Aggressive scan, shorthand for -O -sV -sC --traceroute... [Note: noisy]
|
|
79
|
+
--script vuln → Run NSE vulnerability-category scripts... [Note: intrusive]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Learn
|
|
83
|
+
A short guided curriculum: what a port scan actually is, how to pick the
|
|
84
|
+
right scan for a situation, how to read the results, and how to scan
|
|
85
|
+
responsibly. Each lesson has a "Try it" button that loads a real command
|
|
86
|
+
against `scanme.nmap.org` — the official Nmap project practice host — so
|
|
87
|
+
you can learn without needing your own server or anyone's permission.
|
|
88
|
+
|
|
89
|
+
### Vulns
|
|
90
|
+
After any scan using `--script vuln` (or the Vuln Scripts profile), NSE
|
|
91
|
+
output is automatically parsed into a sortable, filterable table:
|
|
92
|
+
severity (CRITICAL/HIGH/MEDIUM/LOW/INFO), CVE numbers, CVSS scores, and a
|
|
93
|
+
detail panel with the full script output for each finding.
|
|
94
|
+
|
|
95
|
+
### Diff
|
|
96
|
+
Run two scans — say, before and after a firewall change — then compare
|
|
97
|
+
them. See exactly which hosts appeared or vanished, which ports opened or
|
|
98
|
+
closed, and which service versions changed.
|
|
99
|
+
|
|
100
|
+
### History
|
|
101
|
+
Every scan is logged with timestamp, target, command, and result counts.
|
|
102
|
+
Summary metadata (not full raw output) persists to disk in
|
|
103
|
+
`~/.nmapui/history.json`, so your log survives closing the app.
|
|
104
|
+
|
|
105
|
+
### Cheatsheet
|
|
106
|
+
24 common nmap flags with plain-English descriptions, instant search
|
|
107
|
+
filter, click-to-copy.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## CLI
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
nmapui # launch the GUI
|
|
115
|
+
nmapui --version # print version
|
|
116
|
+
nmapui --config-dir # print where settings/history/favorites live
|
|
117
|
+
nmapui --reset-config # reset saved settings to defaults
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Project layout
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
nmapui/
|
|
126
|
+
├── nmapui/
|
|
127
|
+
│ ├── __init__.py # package root (lazy-imports the GUI)
|
|
128
|
+
│ ├── __main__.py # CLI entry point
|
|
129
|
+
│ ├── gui.py # Tkinter application (UI layer)
|
|
130
|
+
│ ├── vuln_parser.py # NSE output parsing + severity classification
|
|
131
|
+
│ ├── diff.py # Scan comparison engine
|
|
132
|
+
│ ├── explainer.py # Flag-by-flag command explanations
|
|
133
|
+
│ ├── lessons.py # Content for the Learn tab
|
|
134
|
+
│ └── storage.py # Persistent settings/favorites/history
|
|
135
|
+
├── tests/ # Unit tests (no tkinter required to run)
|
|
136
|
+
├── .github/workflows/ # CI
|
|
137
|
+
├── pyproject.toml
|
|
138
|
+
├── LICENSE
|
|
139
|
+
├── CHANGELOG.md
|
|
140
|
+
└── CONTRIBUTING.md
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The logic modules (`diff.py`, `vuln_parser.py`, `explainer.py`, `storage.py`)
|
|
144
|
+
have no tkinter dependency and are independently unit tested — `gui.py` is
|
|
145
|
+
the only file that needs a display.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Running tests
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
pip install -e ".[dev]"
|
|
153
|
+
pytest
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
33 tests, no `nmap` binary or display required.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Publishing to PyPI
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
pip install build twine
|
|
164
|
+
python -m build
|
|
165
|
+
twine upload dist/*
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Legal note
|
|
171
|
+
|
|
172
|
+
nmapui is a GUI front-end only — all scanning is performed by the `nmap`
|
|
173
|
+
binary on your system. Only scan networks and hosts you own or have
|
|
174
|
+
explicit permission to test. Unauthorized network scanning may be illegal
|
|
175
|
+
in your jurisdiction. The Learn tab's practice exercises use
|
|
176
|
+
`scanme.nmap.org`, a host the Nmap project explicitly maintains for this
|
|
177
|
+
purpose — be reasonable with it (light scans only).
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nmapui
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: A modern, learnable GUI for nmap — scan profiles, vuln highlighting, scan diff, a built-in flag explainer, and guided lessons.
|
|
5
|
+
Home-page: https://github.com/shivduttchoubey/nmapui
|
|
6
|
+
Author: Your Name
|
|
7
|
+
Author-email: Shiv Dutt Choubey <shivduttchoubey@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/shivduttchoubey/nmapui
|
|
10
|
+
Project-URL: Issues, https://github.com/shivduttchoubey/nmapui/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/shivduttchoubey/nmapui/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: nmap,network,scanner,security,gui,tkinter,learning
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Topic :: System :: Networking
|
|
22
|
+
Classifier: Topic :: Security
|
|
23
|
+
Classifier: Environment :: X11 Applications
|
|
24
|
+
Classifier: Intended Audience :: System Administrators
|
|
25
|
+
Classifier: Intended Audience :: Education
|
|
26
|
+
Requires-Python: >=3.9
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
31
|
+
Dynamic: author
|
|
32
|
+
Dynamic: home-page
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
Dynamic: requires-python
|
|
35
|
+
|
|
36
|
+
# nmapui
|
|
37
|
+
|
|
38
|
+
**A modern, learnable GUI for nmap.** Replaces Zenmap with a dark-themed
|
|
39
|
+
interface that teaches you nmap as you use it — no command memorization,
|
|
40
|
+
no manual lookups, persistent settings across sessions.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install nmapui
|
|
44
|
+
nmapui
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
[](https://github.com/shivduttchoubey/nmapui/actions)
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Why this exists
|
|
53
|
+
|
|
54
|
+
Zenmap (the official nmap GUI) hasn't meaningfully changed in over a decade.
|
|
55
|
+
Using it well still means knowing `-sV`, `-T4`, `--script vuln`, etc. by heart.
|
|
56
|
+
nmapui keeps the real power of nmap but removes the memorization requirement —
|
|
57
|
+
and adds the pieces a learner or a day-to-day sysadmin actually wants:
|
|
58
|
+
favorites, history that survives a restart, vulnerability triage, and a
|
|
59
|
+
built-in tutorial.
|
|
60
|
+
|
|
61
|
+
| | Zenmap | nmapui |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| Dark, modern UI | ✗ | ✓ |
|
|
64
|
+
| Plain-English scan profiles | partial | ✓ 10 profiles |
|
|
65
|
+
| Live command preview | ✗ | ✓ |
|
|
66
|
+
| Flag-by-flag command explainer | ✗ | ✓ |
|
|
67
|
+
| Guided lessons / practice mode | ✗ | ✓ |
|
|
68
|
+
| Vulnerability tab (CVE + severity) | ✗ | ✓ |
|
|
69
|
+
| Scan diff / compare | ✗ | ✓ |
|
|
70
|
+
| Favorite targets | ✗ | ✓ |
|
|
71
|
+
| Settings/history persist across restarts | ✗ | ✓ (`~/.nmapui/`) |
|
|
72
|
+
| Export CSV / JSON | ✗ | ✓ |
|
|
73
|
+
| Searchable cheatsheet | ✗ | ✓ |
|
|
74
|
+
| Zero third-party dependencies | ✓ | ✓ |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Requirements
|
|
79
|
+
|
|
80
|
+
- Python 3.9+ (tkinter ships with most standard installs)
|
|
81
|
+
- The `nmap` binary on your PATH
|
|
82
|
+
- macOS: `brew install nmap`
|
|
83
|
+
- Ubuntu/Debian: `sudo apt install nmap`
|
|
84
|
+
- Windows: [nmap.org/download](https://nmap.org/download) (check "Add to PATH" during install)
|
|
85
|
+
- Winget on Windows: winget install -e --id Insecure.Nmap
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Features
|
|
91
|
+
|
|
92
|
+
### Scanner
|
|
93
|
+
10 plain-English scan profiles (Quick Ping, Common Ports, Full Port Scan,
|
|
94
|
+
Service Detection, OS Detection, Intense, Stealth SYN, UDP, Vuln Scripts,
|
|
95
|
+
Custom), a live command preview that updates as you adjust options, and a
|
|
96
|
+
results view split into Summary / Ports / Raw Output / Export tabs.
|
|
97
|
+
|
|
98
|
+
### Favorites
|
|
99
|
+
Save a target with a name ("Home Router", "Lab Server") from the Scanner
|
|
100
|
+
tab. Favorites persist in `~/.nmapui/favorites.json` and show up in a
|
|
101
|
+
dropdown next to the target field — no more retyping IPs.
|
|
102
|
+
|
|
103
|
+
### Explain
|
|
104
|
+
Paste any nmap command — your own, or one you copied from a forum post —
|
|
105
|
+
and get a flag-by-flag plain-English breakdown before you run it, including
|
|
106
|
+
a warning note on flags that are noisy, intrusive, or privileged.
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Input: nmap -sS -T4 -A --script vuln 192.168.1.0/24
|
|
110
|
+
|
|
111
|
+
-sS → TCP SYN scan ("stealth" scan)... [Note: Requires root/admin privileges]
|
|
112
|
+
-T4 → Aggressive timing...
|
|
113
|
+
-A → Aggressive scan, shorthand for -O -sV -sC --traceroute... [Note: noisy]
|
|
114
|
+
--script vuln → Run NSE vulnerability-category scripts... [Note: intrusive]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Learn
|
|
118
|
+
A short guided curriculum: what a port scan actually is, how to pick the
|
|
119
|
+
right scan for a situation, how to read the results, and how to scan
|
|
120
|
+
responsibly. Each lesson has a "Try it" button that loads a real command
|
|
121
|
+
against `scanme.nmap.org` — the official Nmap project practice host — so
|
|
122
|
+
you can learn without needing your own server or anyone's permission.
|
|
123
|
+
|
|
124
|
+
### Vulns
|
|
125
|
+
After any scan using `--script vuln` (or the Vuln Scripts profile), NSE
|
|
126
|
+
output is automatically parsed into a sortable, filterable table:
|
|
127
|
+
severity (CRITICAL/HIGH/MEDIUM/LOW/INFO), CVE numbers, CVSS scores, and a
|
|
128
|
+
detail panel with the full script output for each finding.
|
|
129
|
+
|
|
130
|
+
### Diff
|
|
131
|
+
Run two scans — say, before and after a firewall change — then compare
|
|
132
|
+
them. See exactly which hosts appeared or vanished, which ports opened or
|
|
133
|
+
closed, and which service versions changed.
|
|
134
|
+
|
|
135
|
+
### History
|
|
136
|
+
Every scan is logged with timestamp, target, command, and result counts.
|
|
137
|
+
Summary metadata (not full raw output) persists to disk in
|
|
138
|
+
`~/.nmapui/history.json`, so your log survives closing the app.
|
|
139
|
+
|
|
140
|
+
### Cheatsheet
|
|
141
|
+
24 common nmap flags with plain-English descriptions, instant search
|
|
142
|
+
filter, click-to-copy.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## CLI
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
nmapui # launch the GUI
|
|
150
|
+
nmapui --version # print version
|
|
151
|
+
nmapui --config-dir # print where settings/history/favorites live
|
|
152
|
+
nmapui --reset-config # reset saved settings to defaults
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Project layout
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
nmapui/
|
|
161
|
+
├── nmapui/
|
|
162
|
+
│ ├── __init__.py # package root (lazy-imports the GUI)
|
|
163
|
+
│ ├── __main__.py # CLI entry point
|
|
164
|
+
│ ├── gui.py # Tkinter application (UI layer)
|
|
165
|
+
│ ├── vuln_parser.py # NSE output parsing + severity classification
|
|
166
|
+
│ ├── diff.py # Scan comparison engine
|
|
167
|
+
│ ├── explainer.py # Flag-by-flag command explanations
|
|
168
|
+
│ ├── lessons.py # Content for the Learn tab
|
|
169
|
+
│ └── storage.py # Persistent settings/favorites/history
|
|
170
|
+
├── tests/ # Unit tests (no tkinter required to run)
|
|
171
|
+
├── .github/workflows/ # CI
|
|
172
|
+
├── pyproject.toml
|
|
173
|
+
├── LICENSE
|
|
174
|
+
├── CHANGELOG.md
|
|
175
|
+
└── CONTRIBUTING.md
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The logic modules (`diff.py`, `vuln_parser.py`, `explainer.py`, `storage.py`)
|
|
179
|
+
have no tkinter dependency and are independently unit tested — `gui.py` is
|
|
180
|
+
the only file that needs a display.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Running tests
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
pip install -e ".[dev]"
|
|
188
|
+
pytest
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
33 tests, no `nmap` binary or display required.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Publishing to PyPI
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pip install build twine
|
|
199
|
+
python -m build
|
|
200
|
+
twine upload dist/*
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Legal note
|
|
206
|
+
|
|
207
|
+
nmapui is a GUI front-end only — all scanning is performed by the `nmap`
|
|
208
|
+
binary on your system. Only scan networks and hosts you own or have
|
|
209
|
+
explicit permission to test. Unauthorized network scanning may be illegal
|
|
210
|
+
in your jurisdiction. The Learn tab's practice exercises use
|
|
211
|
+
`scanme.nmap.org`, a host the Nmap project explicitly maintains for this
|
|
212
|
+
purpose — be reasonable with it (light scans only).
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
nmapui.egg-info/PKG-INFO
|
|
6
|
+
nmapui.egg-info/SOURCES.txt
|
|
7
|
+
nmapui.egg-info/dependency_links.txt
|
|
8
|
+
nmapui.egg-info/entry_points.txt
|
|
9
|
+
nmapui.egg-info/requires.txt
|
|
10
|
+
nmapui.egg-info/top_level.txt
|
|
11
|
+
tests/test_diff.py
|
|
12
|
+
tests/test_explainer.py
|
|
13
|
+
tests/test_storage.py
|
|
14
|
+
tests/test_vuln_parser.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "nmapui"
|
|
7
|
+
version = "3.0.0"
|
|
8
|
+
description = "A modern, learnable GUI for nmap — scan profiles, vuln highlighting, scan diff, a built-in flag explainer, and guided lessons."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
authors = [{ name = "Shiv Dutt Choubey", email = "shivduttchoubey@gmail.com" }]
|
|
12
|
+
keywords = ["nmap", "network", "scanner", "security", "gui", "tkinter", "learning"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.9",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Topic :: System :: Networking",
|
|
23
|
+
"Topic :: Security",
|
|
24
|
+
"Environment :: X11 Applications",
|
|
25
|
+
"Intended Audience :: System Administrators",
|
|
26
|
+
"Intended Audience :: Education",
|
|
27
|
+
]
|
|
28
|
+
requires-python = ">=3.9"
|
|
29
|
+
# No third-party runtime deps — tkinter is stdlib, nmap is a system binary.
|
|
30
|
+
dependencies = []
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
dev = ["pytest>=7.0"]
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
nmapui = "nmapui.__main__:main"
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/shivduttchoubey/nmapui"
|
|
40
|
+
Issues = "https://github.com/shivduttchoubey/nmapui/issues"
|
|
41
|
+
Changelog = "https://github.com/shivduttchoubey/nmapui/blob/main/CHANGELOG.md"
|
|
42
|
+
|
|
43
|
+
[tool.setuptools.packages.find]
|
|
44
|
+
where = ["."]
|
|
45
|
+
include = ["nmapui*"]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
nmapui-3.0.0/setup.cfg
ADDED
nmapui-3.0.0/setup.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
setup.py for nmapui
|
|
3
|
+
-------------------
|
|
4
|
+
This file exists alongside pyproject.toml for compatibility with older
|
|
5
|
+
pip versions, editable installs, and tools that still look for setup.py.
|
|
6
|
+
All canonical metadata lives in pyproject.toml — this file just calls
|
|
7
|
+
through to setuptools so both workflows work.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
pip install . # normal install
|
|
11
|
+
pip install -e . # editable / dev install
|
|
12
|
+
pip install -e ".[dev]" # editable + dev deps (pytest)
|
|
13
|
+
python setup.py --version # quick version check (legacy)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from setuptools import setup, find_packages
|
|
17
|
+
|
|
18
|
+
setup(
|
|
19
|
+
name="nmapui",
|
|
20
|
+
version="3.0.0",
|
|
21
|
+
description=(
|
|
22
|
+
"A modern, learnable GUI for nmap — scan profiles, vuln highlighting, "
|
|
23
|
+
"scan diff, a built-in flag explainer, and guided lessons."
|
|
24
|
+
),
|
|
25
|
+
long_description=open("README.md", encoding="utf-8").read(),
|
|
26
|
+
long_description_content_type="text/markdown",
|
|
27
|
+
author="Your Name",
|
|
28
|
+
author_email="shivduttchoubey@gmail.com",
|
|
29
|
+
url="https://github.com/shivduttchoubey/nmapui",
|
|
30
|
+
license="MIT",
|
|
31
|
+
packages=find_packages(exclude=["tests*"]),
|
|
32
|
+
python_requires=">=3.9",
|
|
33
|
+
install_requires=[], # zero runtime deps — tkinter is stdlib
|
|
34
|
+
extras_require={
|
|
35
|
+
"dev": ["pytest>=7.0"],
|
|
36
|
+
},
|
|
37
|
+
entry_points={
|
|
38
|
+
"console_scripts": [
|
|
39
|
+
"nmapui = nmapui.__main__:main",
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
classifiers=[
|
|
43
|
+
"Development Status :: 4 - Beta",
|
|
44
|
+
"Programming Language :: Python :: 3",
|
|
45
|
+
"Programming Language :: Python :: 3.9",
|
|
46
|
+
"Programming Language :: Python :: 3.10",
|
|
47
|
+
"Programming Language :: Python :: 3.11",
|
|
48
|
+
"Programming Language :: Python :: 3.12",
|
|
49
|
+
"License :: OSI Approved :: MIT License",
|
|
50
|
+
"Operating System :: OS Independent",
|
|
51
|
+
"Topic :: System :: Networking",
|
|
52
|
+
"Topic :: Security",
|
|
53
|
+
"Environment :: X11 Applications",
|
|
54
|
+
"Intended Audience :: System Administrators",
|
|
55
|
+
"Intended Audience :: Education",
|
|
56
|
+
],
|
|
57
|
+
keywords="nmap network scanner security gui tkinter learning",
|
|
58
|
+
project_urls={
|
|
59
|
+
"Issues": "https://github.com/shivduttchoubey/nmapui/issues",
|
|
60
|
+
"Changelog": "https://github.com/shivduttchoubey/nmapui/blob/main/CHANGELOG.md",
|
|
61
|
+
},
|
|
62
|
+
)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Tests for nmapui.diff"""
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
5
|
+
|
|
6
|
+
from nmapui.diff import diff_scans
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def make_host(host, ports):
|
|
10
|
+
return {"host": host, "ports": ports, "os": "", "state": "up"}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def make_port(port, proto, state, service="", version=""):
|
|
14
|
+
return {"port": port, "proto": proto, "state": state, "service": service, "version": version}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_no_changes():
|
|
18
|
+
old = [make_host("1.2.3.4", [make_port("22", "tcp", "open", "ssh")])]
|
|
19
|
+
new = [make_host("1.2.3.4", [make_port("22", "tcp", "open", "ssh")])]
|
|
20
|
+
result = diff_scans(old, new)
|
|
21
|
+
assert not result.has_changes
|
|
22
|
+
assert result.unchanged_hosts == 1
|
|
23
|
+
assert result.unchanged_ports == 1
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_new_host_appeared():
|
|
27
|
+
old = []
|
|
28
|
+
new = [make_host("1.2.3.5", [make_port("80", "tcp", "open", "http")])]
|
|
29
|
+
result = diff_scans(old, new)
|
|
30
|
+
appeared = [h for h in result.host_changes if h.change == "appeared"]
|
|
31
|
+
assert len(appeared) == 1
|
|
32
|
+
assert appeared[0].host == "1.2.3.5"
|
|
33
|
+
# New host's open port should also be logged
|
|
34
|
+
opened = [p for p in result.port_changes if p.change == "opened"]
|
|
35
|
+
assert len(opened) == 1
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_host_disappeared():
|
|
39
|
+
old = [make_host("1.2.3.4", [make_port("22", "tcp", "open")])]
|
|
40
|
+
new = []
|
|
41
|
+
result = diff_scans(old, new)
|
|
42
|
+
disappeared = [h for h in result.host_changes if h.change == "disappeared"]
|
|
43
|
+
assert len(disappeared) == 1
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_port_opened():
|
|
47
|
+
old = [make_host("1.2.3.4", [make_port("22", "tcp", "open")])]
|
|
48
|
+
new = [make_host("1.2.3.4", [make_port("22", "tcp", "open"), make_port("80", "tcp", "open", "http")])]
|
|
49
|
+
result = diff_scans(old, new)
|
|
50
|
+
opened = [p for p in result.port_changes if p.change == "opened"]
|
|
51
|
+
assert len(opened) == 1
|
|
52
|
+
assert opened[0].port == "80"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_port_closed():
|
|
56
|
+
old = [make_host("1.2.3.4", [make_port("22", "tcp", "open"), make_port("80", "tcp", "open")])]
|
|
57
|
+
new = [make_host("1.2.3.4", [make_port("22", "tcp", "open")])]
|
|
58
|
+
result = diff_scans(old, new)
|
|
59
|
+
closed = [p for p in result.port_changes if p.change == "closed"]
|
|
60
|
+
assert len(closed) == 1
|
|
61
|
+
assert closed[0].port == "80"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_version_changed():
|
|
65
|
+
old = [make_host("1.2.3.4", [make_port("22", "tcp", "open", "ssh", "OpenSSH 7.0")])]
|
|
66
|
+
new = [make_host("1.2.3.4", [make_port("22", "tcp", "open", "ssh", "OpenSSH 8.2")])]
|
|
67
|
+
result = diff_scans(old, new)
|
|
68
|
+
changed = [p for p in result.port_changes if p.change == "version_changed"]
|
|
69
|
+
assert len(changed) == 1
|
|
70
|
+
assert changed[0].old_val == "OpenSSH 7.0"
|
|
71
|
+
assert changed[0].new_val == "OpenSSH 8.2"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_state_changed():
|
|
75
|
+
old = [make_host("1.2.3.4", [make_port("22", "tcp", "open")])]
|
|
76
|
+
new = [make_host("1.2.3.4", [make_port("22", "tcp", "filtered")])]
|
|
77
|
+
result = diff_scans(old, new)
|
|
78
|
+
changed = [p for p in result.port_changes if p.change == "state_changed"]
|
|
79
|
+
assert len(changed) == 1
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_summary_text_no_changes():
|
|
83
|
+
old = [make_host("1.2.3.4", [make_port("22", "tcp", "open")])]
|
|
84
|
+
new = [make_host("1.2.3.4", [make_port("22", "tcp", "open")])]
|
|
85
|
+
result = diff_scans(old, new)
|
|
86
|
+
assert "No changes" in result.summary
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
if __name__ == "__main__":
|
|
90
|
+
import traceback
|
|
91
|
+
tests = [v for k, v in list(globals().items()) if k.startswith("test_")]
|
|
92
|
+
passed = failed = 0
|
|
93
|
+
for t in tests:
|
|
94
|
+
try:
|
|
95
|
+
t()
|
|
96
|
+
passed += 1
|
|
97
|
+
print(f"PASS: {t.__name__}")
|
|
98
|
+
except Exception:
|
|
99
|
+
failed += 1
|
|
100
|
+
print(f"FAIL: {t.__name__}")
|
|
101
|
+
traceback.print_exc()
|
|
102
|
+
print(f"\n{passed} passed, {failed} failed")
|
|
103
|
+
sys.exit(1 if failed else 0)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Tests for nmapui.explainer"""
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
5
|
+
|
|
6
|
+
from nmapui.explainer import explain_command, explain_command_text
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_explains_basic_flags():
|
|
10
|
+
results = explain_command("nmap -sV -T4 192.168.1.1")
|
|
11
|
+
flags = [r.flag for r in results]
|
|
12
|
+
assert "-sV" in flags
|
|
13
|
+
assert "-T4" in flags
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_strips_leading_nmap():
|
|
17
|
+
results_with = explain_command("nmap -sn 10.0.0.1")
|
|
18
|
+
results_without = explain_command("-sn 10.0.0.1")
|
|
19
|
+
assert len(results_with) == len(results_without)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_target_is_skipped():
|
|
23
|
+
results = explain_command("nmap -sn scanme.nmap.org")
|
|
24
|
+
flags = [r.flag for r in results]
|
|
25
|
+
assert "scanme.nmap.org" not in flags
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_combined_flag_with_value():
|
|
29
|
+
results = explain_command("nmap --top-ports 100 192.168.1.1")
|
|
30
|
+
combined = [r.flag for r in results if "top-ports" in r.flag]
|
|
31
|
+
assert len(combined) == 1
|
|
32
|
+
assert "100" in combined[0]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_risky_flag_has_risk_note():
|
|
36
|
+
results = explain_command("nmap --script vuln 192.168.1.1")
|
|
37
|
+
script_results = [r for r in results if "script" in r.flag]
|
|
38
|
+
assert len(script_results) == 1
|
|
39
|
+
assert script_results[0].risk_note is not None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_unrecognized_flag_gets_generic_note():
|
|
43
|
+
results = explain_command("nmap --totally-made-up-flag 192.168.1.1")
|
|
44
|
+
matches = [r for r in results if r.flag == "--totally-made-up-flag"]
|
|
45
|
+
assert len(matches) == 1
|
|
46
|
+
assert "Unrecognized" in matches[0].explanation
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_explain_command_text_empty_for_no_flags():
|
|
50
|
+
text = explain_command_text("nmap 192.168.1.1")
|
|
51
|
+
assert "No recognized flags" in text
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_explain_command_text_nonempty_for_flags():
|
|
55
|
+
text = explain_command_text("nmap -A 192.168.1.1")
|
|
56
|
+
assert len(text) > 0
|
|
57
|
+
assert "-A" in text
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
if __name__ == "__main__":
|
|
61
|
+
import traceback
|
|
62
|
+
tests = [v for k, v in list(globals().items()) if k.startswith("test_")]
|
|
63
|
+
passed = failed = 0
|
|
64
|
+
for t in tests:
|
|
65
|
+
try:
|
|
66
|
+
t()
|
|
67
|
+
passed += 1
|
|
68
|
+
print(f"PASS: {t.__name__}")
|
|
69
|
+
except Exception:
|
|
70
|
+
failed += 1
|
|
71
|
+
print(f"FAIL: {t.__name__}")
|
|
72
|
+
traceback.print_exc()
|
|
73
|
+
print(f"\n{passed} passed, {failed} failed")
|
|
74
|
+
sys.exit(1 if failed else 0)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Tests for nmapui.storage — uses a temp HOME so we never touch real ~/.nmapui"""
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
import tempfile
|
|
5
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
6
|
+
|
|
7
|
+
# Redirect HOME before importing storage, so _app_dir() resolves to a sandbox.
|
|
8
|
+
_tmp_home = tempfile.mkdtemp(prefix="nmapui_test_home_")
|
|
9
|
+
os.environ["HOME"] = _tmp_home
|
|
10
|
+
|
|
11
|
+
from nmapui import storage
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_settings_roundtrip():
|
|
15
|
+
settings = storage.load_settings()
|
|
16
|
+
settings["last_timing"] = "T1 – Sneaky"
|
|
17
|
+
storage.save_settings(settings)
|
|
18
|
+
reloaded = storage.load_settings()
|
|
19
|
+
assert reloaded["last_timing"] == "T1 – Sneaky"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_settings_has_defaults():
|
|
23
|
+
storage.reset_settings()
|
|
24
|
+
settings = storage.load_settings()
|
|
25
|
+
assert settings["last_profile_index"] == 1
|
|
26
|
+
assert settings["verbose"] is True
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_favorites_add_and_load():
|
|
30
|
+
storage.save_favorites([])
|
|
31
|
+
storage.add_favorite("Home Router", "192.168.1.1")
|
|
32
|
+
favs = storage.load_favorites()
|
|
33
|
+
assert any(f["name"] == "Home Router" and f["target"] == "192.168.1.1" for f in favs)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_favorites_remove():
|
|
37
|
+
storage.save_favorites([])
|
|
38
|
+
storage.add_favorite("Test Box", "10.0.0.5")
|
|
39
|
+
storage.remove_favorite("Test Box")
|
|
40
|
+
favs = storage.load_favorites()
|
|
41
|
+
assert not any(f["name"] == "Test Box" for f in favs)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_favorites_replace_same_name():
|
|
45
|
+
storage.save_favorites([])
|
|
46
|
+
storage.add_favorite("Server", "1.1.1.1")
|
|
47
|
+
storage.add_favorite("Server", "2.2.2.2")
|
|
48
|
+
favs = storage.load_favorites()
|
|
49
|
+
matching = [f for f in favs if f["name"] == "Server"]
|
|
50
|
+
assert len(matching) == 1
|
|
51
|
+
assert matching[0]["target"] == "2.2.2.2"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_history_append_and_load():
|
|
55
|
+
storage.clear_history()
|
|
56
|
+
storage.append_history_entry({"ts": "12:00:00", "target": "1.2.3.4", "cmd": "nmap 1.2.3.4",
|
|
57
|
+
"hosts": 1, "open_ports": 2, "vuln_count": 0})
|
|
58
|
+
history = storage.load_history()
|
|
59
|
+
assert len(history) == 1
|
|
60
|
+
assert history[0]["target"] == "1.2.3.4"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_history_caps_length():
|
|
64
|
+
storage.clear_history()
|
|
65
|
+
for i in range(storage.MAX_HISTORY_ENTRIES + 10):
|
|
66
|
+
storage.append_history_entry({"ts": str(i), "target": "x", "cmd": "nmap x",
|
|
67
|
+
"hosts": 0, "open_ports": 0, "vuln_count": 0})
|
|
68
|
+
history = storage.load_history()
|
|
69
|
+
assert len(history) == storage.MAX_HISTORY_ENTRIES
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_storage_summary_keys():
|
|
73
|
+
summary = storage.storage_summary()
|
|
74
|
+
assert "location" in summary
|
|
75
|
+
assert "history_entries" in summary
|
|
76
|
+
assert "favorites" in summary
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if __name__ == "__main__":
|
|
80
|
+
import traceback
|
|
81
|
+
tests = [v for k, v in list(globals().items()) if k.startswith("test_")]
|
|
82
|
+
passed = failed = 0
|
|
83
|
+
for t in tests:
|
|
84
|
+
try:
|
|
85
|
+
t()
|
|
86
|
+
passed += 1
|
|
87
|
+
print(f"PASS: {t.__name__}")
|
|
88
|
+
except Exception:
|
|
89
|
+
failed += 1
|
|
90
|
+
print(f"FAIL: {t.__name__}")
|
|
91
|
+
traceback.print_exc()
|
|
92
|
+
print(f"\n{passed} passed, {failed} failed")
|
|
93
|
+
sys.exit(1 if failed else 0)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Tests for nmapui.vuln_parser"""
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
5
|
+
|
|
6
|
+
from nmapui.vuln_parser import parse_vulns, _classify_severity, _extract_cves, _extract_cvss
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
SAMPLE_OUTPUT = """
|
|
10
|
+
Nmap scan report for 192.168.1.10
|
|
11
|
+
Host is up (0.0010s latency).
|
|
12
|
+
PORT STATE SERVICE
|
|
13
|
+
80/tcp open http
|
|
14
|
+
| http-vuln-cve2021-1234: VULNERABLE:
|
|
15
|
+
| Apache mod_cgi Remote Code Execution
|
|
16
|
+
| State: VULNERABLE
|
|
17
|
+
| IDs: CVE-2021-1234
|
|
18
|
+
| Risk factor: High CVSS: 9.8
|
|
19
|
+
|_ This is a critical remote code execution vulnerability.
|
|
20
|
+
443/tcp open https
|
|
21
|
+
| ssl-cert: Subject: commonName=example.com
|
|
22
|
+
|_SHA-1: aabbccdd
|
|
23
|
+
|
|
24
|
+
Nmap scan report for 192.168.1.11
|
|
25
|
+
Host is up.
|
|
26
|
+
PORT STATE SERVICE
|
|
27
|
+
22/tcp open ssh
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_classify_severity_critical():
|
|
32
|
+
assert _classify_severity("CVSS: 9.8 remote code execution") == "CRITICAL"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_classify_severity_high():
|
|
36
|
+
assert _classify_severity("sql injection found") == "HIGH"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_classify_severity_medium():
|
|
40
|
+
assert _classify_severity("cross-site scripting possible") == "MEDIUM"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_classify_severity_info_fallback():
|
|
44
|
+
assert _classify_severity("just some informational text") == "INFO"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_extract_cves():
|
|
48
|
+
cves = _extract_cves("Known issues: CVE-2021-1234 and cve-2020-9999")
|
|
49
|
+
assert "CVE-2021-1234" in cves
|
|
50
|
+
assert len(cves) == 2
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_extract_cvss():
|
|
54
|
+
assert _extract_cvss("Risk factor: High CVSS: 9.8") == "9.8"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_parse_vulns_finds_finding():
|
|
58
|
+
findings = parse_vulns(SAMPLE_OUTPUT)
|
|
59
|
+
assert len(findings) >= 1
|
|
60
|
+
f = findings[0]
|
|
61
|
+
assert f.host == "192.168.1.10"
|
|
62
|
+
assert f.port == "80/tcp"
|
|
63
|
+
assert "CVE-2021-1234" in f.cves
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_parse_vulns_severity_sorted():
|
|
67
|
+
findings = parse_vulns(SAMPLE_OUTPUT)
|
|
68
|
+
# CRITICAL findings (if any) should come before lower severities
|
|
69
|
+
severities = [f.severity for f in findings]
|
|
70
|
+
from nmapui.vuln_parser import SEVERITY_ORDER
|
|
71
|
+
ranks = [SEVERITY_ORDER.get(s, 99) for s in severities]
|
|
72
|
+
assert ranks == sorted(ranks)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_parse_vulns_no_script_output():
|
|
76
|
+
text = "Nmap scan report for 1.2.3.4\nPORT STATE SERVICE\n80/tcp open http\n"
|
|
77
|
+
findings = parse_vulns(text)
|
|
78
|
+
assert findings == []
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
import traceback
|
|
83
|
+
tests = [v for k, v in list(globals().items()) if k.startswith("test_")]
|
|
84
|
+
passed = failed = 0
|
|
85
|
+
for t in tests:
|
|
86
|
+
try:
|
|
87
|
+
t()
|
|
88
|
+
passed += 1
|
|
89
|
+
print(f"PASS: {t.__name__}")
|
|
90
|
+
except Exception:
|
|
91
|
+
failed += 1
|
|
92
|
+
print(f"FAIL: {t.__name__}")
|
|
93
|
+
traceback.print_exc()
|
|
94
|
+
print(f"\n{passed} passed, {failed} failed")
|
|
95
|
+
sys.exit(1 if failed else 0)
|