pentool 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pentool-1.0.0/LICENSE +34 -0
- pentool-1.0.0/PKG-INFO +155 -0
- pentool-1.0.0/README.md +111 -0
- pentool-1.0.0/pentool/__init__.py +4 -0
- pentool-1.0.0/pentool/__main__.py +17 -0
- pentool-1.0.0/pentool/api/__init__.py +45 -0
- pentool-1.0.0/pentool/api/base_api.py +52 -0
- pentool-1.0.0/pentool/api/comparer_api.py +23 -0
- pentool-1.0.0/pentool/api/decoder_api.py +28 -0
- pentool-1.0.0/pentool/api/intruder_api.py +209 -0
- pentool-1.0.0/pentool/api/proxy_api.py +319 -0
- pentool-1.0.0/pentool/api/repeater_api.py +118 -0
- pentool-1.0.0/pentool/api/scanner_api.py +336 -0
- pentool-1.0.0/pentool/api/sequencer_api.py +21 -0
- pentool-1.0.0/pentool/api/spider_api.py +126 -0
- pentool-1.0.0/pentool/api/target_api.py +121 -0
- pentool-1.0.0/pentool/cli/__init__.py +1 -0
- pentool-1.0.0/pentool/cli/main.py +100 -0
- pentool-1.0.0/pentool/cli/project.py +90 -0
- pentool-1.0.0/pentool/cli/proxy.py +185 -0
- pentool-1.0.0/pentool/cli/scan.py +118 -0
- pentool-1.0.0/pentool/core/__init__.py +1 -0
- pentool-1.0.0/pentool/core/config.py +184 -0
- pentool-1.0.0/pentool/core/crash_reporter.py +75 -0
- pentool-1.0.0/pentool/core/database.py +139 -0
- pentool-1.0.0/pentool/core/event_bus.py +232 -0
- pentool-1.0.0/pentool/core/events.py +164 -0
- pentool-1.0.0/pentool/core/features.py +410 -0
- pentool-1.0.0/pentool/core/license.py +294 -0
- pentool-1.0.0/pentool/core/logging.py +59 -0
- pentool-1.0.0/pentool/core/plugin_manager.py +332 -0
- pentool-1.0.0/pentool/core/project.py +37 -0
- pentool-1.0.0/pentool/core/storage_interface.py +311 -0
- pentool-1.0.0/pentool/core/updater.py +96 -0
- pentool-1.0.0/pentool/core/utils.py +61 -0
- pentool-1.0.0/pentool/modules/__init__.py +1 -0
- pentool-1.0.0/pentool/modules/comparer.py +177 -0
- pentool-1.0.0/pentool/modules/decoder.py +281 -0
- pentool-1.0.0/pentool/modules/intruder.py +432 -0
- pentool-1.0.0/pentool/modules/intruder_turbo.py +190 -0
- pentool-1.0.0/pentool/modules/match_replace.py +146 -0
- pentool-1.0.0/pentool/modules/proxy.py +803 -0
- pentool-1.0.0/pentool/modules/repeater.py +237 -0
- pentool-1.0.0/pentool/modules/scanner/__init__.py +7 -0
- pentool-1.0.0/pentool/modules/scanner/ai_analyzer.py +230 -0
- pentool-1.0.0/pentool/modules/scanner/base.py +173 -0
- pentool-1.0.0/pentool/modules/scanner/baseline.py +101 -0
- pentool-1.0.0/pentool/modules/scanner/checks/__init__.py +47 -0
- pentool-1.0.0/pentool/modules/scanner/checks/broken_auth.py +231 -0
- pentool-1.0.0/pentool/modules/scanner/checks/cors.py +209 -0
- pentool-1.0.0/pentool/modules/scanner/checks/dom_xss.py +114 -0
- pentool-1.0.0/pentool/modules/scanner/checks/graphql.py +110 -0
- pentool-1.0.0/pentool/modules/scanner/checks/header_injection.py +262 -0
- pentool-1.0.0/pentool/modules/scanner/checks/headers.py +75 -0
- pentool-1.0.0/pentool/modules/scanner/checks/helpers.py +358 -0
- pentool-1.0.0/pentool/modules/scanner/checks/info_leak.py +68 -0
- pentool-1.0.0/pentool/modules/scanner/checks/jwt_none.py +238 -0
- pentool-1.0.0/pentool/modules/scanner/checks/lfi.py +186 -0
- pentool-1.0.0/pentool/modules/scanner/checks/nosql_injection.py +92 -0
- pentool-1.0.0/pentool/modules/scanner/checks/oauth.py +123 -0
- pentool-1.0.0/pentool/modules/scanner/checks/open_redirect.py +168 -0
- pentool-1.0.0/pentool/modules/scanner/checks/path_traversal.py +229 -0
- pentool-1.0.0/pentool/modules/scanner/checks/prototype_pollution.py +88 -0
- pentool-1.0.0/pentool/modules/scanner/checks/rce.py +338 -0
- pentool-1.0.0/pentool/modules/scanner/checks/sensitive_data.py +74 -0
- pentool-1.0.0/pentool/modules/scanner/checks/sqli.py +546 -0
- pentool-1.0.0/pentool/modules/scanner/checks/ssrf.py +273 -0
- pentool-1.0.0/pentool/modules/scanner/checks/ssti.py +353 -0
- pentool-1.0.0/pentool/modules/scanner/checks/xss.py +622 -0
- pentool-1.0.0/pentool/modules/scanner/checks/xxe.py +240 -0
- pentool-1.0.0/pentool/modules/scanner/engine.py +407 -0
- pentool-1.0.0/pentool/modules/scanner/fingerprint.py +169 -0
- pentool-1.0.0/pentool/modules/scanner/helpers.py +94 -0
- pentool-1.0.0/pentool/modules/scanner/mutator.py +378 -0
- pentool-1.0.0/pentool/modules/scanner/oob.py +104 -0
- pentool-1.0.0/pentool/modules/scanner/passive.py +114 -0
- pentool-1.0.0/pentool/modules/scanner/payloads.py +224 -0
- pentool-1.0.0/pentool/modules/scanner/report.py +117 -0
- pentool-1.0.0/pentool/modules/sequencer.py +500 -0
- pentool-1.0.0/pentool/modules/spider.py +702 -0
- pentool-1.0.0/pentool/modules/target.py +190 -0
- pentool-1.0.0/pentool/modules/websocket_handler.py +259 -0
- pentool-1.0.0/pentool/plugins/__init__.py +7 -0
- pentool-1.0.0/pentool/plugins/builtin/__init__.py +1 -0
- pentool-1.0.0/pentool/plugins/builtin/payloads_pro.py +404 -0
- pentool-1.0.0/pentool/plugins/builtin/reports_pro.py +450 -0
- pentool-1.0.0/pentool/plugins/builtin/scanner_pro.py +308 -0
- pentool-1.0.0/pentool/plugins/example_plugin.py +75 -0
- pentool-1.0.0/pentool/project_to_txt.py +67 -0
- pentool-1.0.0/pentool/services/__init__.py +1 -0
- pentool-1.0.0/pentool/services/base_service.py +64 -0
- pentool-1.0.0/pentool/services/intruder_service.py +108 -0
- pentool-1.0.0/pentool/services/proxy_service.py +232 -0
- pentool-1.0.0/pentool/services/repeater_service.py +111 -0
- pentool-1.0.0/pentool/services/scan_service.py +340 -0
- pentool-1.0.0/pentool/storage/__init__.py +0 -0
- pentool-1.0.0/pentool/storage/http_storage.py +522 -0
- pentool-1.0.0/pentool/storage/large_body_handler.py +54 -0
- pentool-1.0.0/pentool/storage/lru_cache.py +49 -0
- pentool-1.0.0/pentool/t.py +213 -0
- pentool-1.0.0/pentool/tui/__init__.py +1 -0
- pentool-1.0.0/pentool/tui/app.py +1438 -0
- pentool-1.0.0/pentool/tui/constants.py +79 -0
- pentool-1.0.0/pentool/tui/dialogs/__init__.py +0 -0
- pentool-1.0.0/pentool/tui/dialogs/cert_dialog.py +81 -0
- pentool-1.0.0/pentool/tui/dialogs/file_selector.py +227 -0
- pentool-1.0.0/pentool/tui/dialogs/load_from_proxy.py +125 -0
- pentool-1.0.0/pentool/tui/dialogs/match_replace_dialog.py +229 -0
- pentool-1.0.0/pentool/tui/dialogs/project_dialog.py +82 -0
- pentool-1.0.0/pentool/tui/dialogs/scope_dialog.py +225 -0
- pentool-1.0.0/pentool/tui/messages.py +121 -0
- pentool-1.0.0/pentool/tui/mixins/__init__.py +0 -0
- pentool-1.0.0/pentool/tui/mixins/app_mixin.py +61 -0
- pentool-1.0.0/pentool/tui/mixins/dialog_cancel.py +25 -0
- pentool-1.0.0/pentool/tui/mixins/request_context_menu.py +285 -0
- pentool-1.0.0/pentool/tui/mixins/tab_rename.py +101 -0
- pentool-1.0.0/pentool/tui/screens/__init__.py +31 -0
- pentool-1.0.0/pentool/tui/screens/comparer/__init__.py +3 -0
- pentool-1.0.0/pentool/tui/screens/comparer/screen.py +233 -0
- pentool-1.0.0/pentool/tui/screens/dashboard/__init__.py +2 -0
- pentool-1.0.0/pentool/tui/screens/dashboard/live_dashboard.py +741 -0
- pentool-1.0.0/pentool/tui/screens/dashboard/screen.py +820 -0
- pentool-1.0.0/pentool/tui/screens/decoder/__init__.py +3 -0
- pentool-1.0.0/pentool/tui/screens/decoder/screen.py +311 -0
- pentool-1.0.0/pentool/tui/screens/extensions/__init__.py +3 -0
- pentool-1.0.0/pentool/tui/screens/extensions/screen.py +24 -0
- pentool-1.0.0/pentool/tui/screens/intruder/__init__.py +3 -0
- pentool-1.0.0/pentool/tui/screens/intruder/screen.py +1362 -0
- pentool-1.0.0/pentool/tui/screens/proxy/__init__.py +3 -0
- pentool-1.0.0/pentool/tui/screens/proxy/screen.py +1664 -0
- pentool-1.0.0/pentool/tui/screens/repeater/__init__.py +3 -0
- pentool-1.0.0/pentool/tui/screens/repeater/screen.py +646 -0
- pentool-1.0.0/pentool/tui/screens/scanner/__init__.py +3 -0
- pentool-1.0.0/pentool/tui/screens/scanner/screen.py +1984 -0
- pentool-1.0.0/pentool/tui/screens/sequencer/__init__.py +3 -0
- pentool-1.0.0/pentool/tui/screens/sequencer/screen.py +520 -0
- pentool-1.0.0/pentool/tui/screens/settings/__init__.py +5 -0
- pentool-1.0.0/pentool/tui/screens/settings/hotkeys.py +134 -0
- pentool-1.0.0/pentool/tui/screens/settings/screen.py +543 -0
- pentool-1.0.0/pentool/tui/screens/spider/__init__.py +3 -0
- pentool-1.0.0/pentool/tui/screens/spider/screen.py +385 -0
- pentool-1.0.0/pentool/tui/screens/target/__init__.py +4 -0
- pentool-1.0.0/pentool/tui/screens/target/screen.py +361 -0
- pentool-1.0.0/pentool/tui/screens/terminal/__init__.py +5 -0
- pentool-1.0.0/pentool/tui/screens/terminal/screen.py +181 -0
- pentool-1.0.0/pentool/tui/widgets/__init__.py +1 -0
- pentool-1.0.0/pentool/tui/widgets/context_menu.py +148 -0
- pentool-1.0.0/pentool/tui/widgets/filter_bar.py +206 -0
- pentool-1.0.0/pentool/tui/widgets/inspector_panel.py +112 -0
- pentool-1.0.0/pentool/tui/widgets/menu.py +86 -0
- pentool-1.0.0/pentool/tui/widgets/menu_bar.py +238 -0
- pentool-1.0.0/pentool/tui/widgets/module_tabs.py +73 -0
- pentool-1.0.0/pentool/tui/widgets/payload_drop_zone.py +66 -0
- pentool-1.0.0/pentool/tui/widgets/request_editor.py +504 -0
- pentool-1.0.0/pentool/tui/widgets/resize_handle.py +116 -0
- pentool-1.0.0/pentool/tui/widgets/search_bar.py +113 -0
- pentool-1.0.0/pentool/tui/widgets/statusbar.py +99 -0
- pentool-1.0.0/pentool/tui/widgets/toolbar_button.py +76 -0
- pentool-1.0.0/pentool/utils/__init__.py +1 -0
- pentool-1.0.0/pentool/utils/cert.py +361 -0
- pentool-1.0.0/pentool/utils/coder.py +170 -0
- pentool-1.0.0/pentool/utils/copy_as.py +251 -0
- pentool-1.0.0/pentool/utils/diff.py +91 -0
- pentool-1.0.0/pentool/utils/http_client.py +175 -0
- pentool-1.0.0/pentool/utils/parser.py +227 -0
- pentool-1.0.0/pentool/utils/terminal_check.py +32 -0
- pentool-1.0.0/pentool.egg-info/PKG-INFO +155 -0
- pentool-1.0.0/pentool.egg-info/SOURCES.txt +172 -0
- pentool-1.0.0/pentool.egg-info/dependency_links.txt +1 -0
- pentool-1.0.0/pentool.egg-info/entry_points.txt +2 -0
- pentool-1.0.0/pentool.egg-info/requires.txt +17 -0
- pentool-1.0.0/pentool.egg-info/top_level.txt +1 -0
- pentool-1.0.0/pyproject.toml +109 -0
- pentool-1.0.0/setup.cfg +4 -0
pentool-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
GNU AFFERO GENERAL PUBLIC LICENSE
|
|
2
|
+
Version 3, 19 November 2007
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2026 Pentool Project
|
|
5
|
+
|
|
6
|
+
This program is free software: you can redistribute it and/or modify
|
|
7
|
+
it under the terms of the GNU Affero General Public License as published
|
|
8
|
+
by the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
(at your option) any later version.
|
|
10
|
+
|
|
11
|
+
This program is distributed in the hope that it will be useful,
|
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
GNU Affero General Public License for more details.
|
|
15
|
+
|
|
16
|
+
You should have received a copy of the GNU Affero General Public License
|
|
17
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
Additional Terms:
|
|
22
|
+
|
|
23
|
+
This software is dual-licensed:
|
|
24
|
+
|
|
25
|
+
1. Community Edition: AGPL-3.0 (this license)
|
|
26
|
+
- Free for personal and open-source use
|
|
27
|
+
- Source code modifications must be shared
|
|
28
|
+
|
|
29
|
+
2. Commercial/PRO Edition: Commercial License
|
|
30
|
+
- Contact: sales@pentool.dev
|
|
31
|
+
- For proprietary/closed-source use
|
|
32
|
+
- Includes enterprise features and support
|
|
33
|
+
|
|
34
|
+
For commercial licensing inquiries, please contact: sales@pentool.dev
|
pentool-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pentool
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Modern Web Pentesting TUI - Professional security testing tool
|
|
5
|
+
Author-email: Pentool Team <dev@pentool.pro>
|
|
6
|
+
License: AGPL-3.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/pentool/pentool
|
|
8
|
+
Project-URL: Documentation, https://pentool.dev/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/pentool/pentool
|
|
10
|
+
Project-URL: Issues, https://github.com/pentool/pentool/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/pentool/pentool/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: pentesting,security,burp,proxy,scanner,intruder
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Information Technology
|
|
16
|
+
Classifier: Topic :: Security
|
|
17
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Environment :: Console
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: textual>=0.40.0
|
|
28
|
+
Requires-Dist: aiohttp>=3.9.0
|
|
29
|
+
Requires-Dist: aiosqlite>=0.19.0
|
|
30
|
+
Requires-Dist: beautifulsoup4>=4.12.0
|
|
31
|
+
Requires-Dist: click>=8.1.0
|
|
32
|
+
Requires-Dist: cryptography>=41.0.0
|
|
33
|
+
Requires-Dist: pyyaml>=6.0
|
|
34
|
+
Requires-Dist: rich>=13.0.0
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-timeout>=2.1.0; extra == "dev"
|
|
40
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
41
|
+
Requires-Dist: mypy>=1.5.0; extra == "dev"
|
|
42
|
+
Requires-Dist: pre-commit>=3.4.0; extra == "dev"
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
|
|
45
|
+
# 🔐 Pentool — Modern Web Pentesting TUI
|
|
46
|
+
|
|
47
|
+
[](https://badge.fury.io/py/pentool)
|
|
48
|
+
[](https://pypi.org/project/pentool/)
|
|
49
|
+
[](LICENSE)
|
|
50
|
+
[](https://github.com/docx/pentool/actions)
|
|
51
|
+
|
|
52
|
+
**Pentool** is a fast, modular web security testing tool with a terminal UI. Built for pentesters and security researchers who prefer working in the terminal.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install pentool
|
|
56
|
+
pentool
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## ✨ Features
|
|
62
|
+
|
|
63
|
+
- **🌐 Proxy** — Intercept and modify HTTP/HTTPS traffic in real time, manage scope, apply match & replace rules
|
|
64
|
+
- **🔄 Repeater** — Replay requests with any modifications, persist tabs between sessions
|
|
65
|
+
- **💥 Intruder** — Automated attacks with 4 strategies: Sniper, Battering Ram, Pitchfork, Cluster Bomb
|
|
66
|
+
- **🚀 Turbo Intruder** — 10× speed via HTTP Keep-Alive and connection pooling (100–200 req/sec)
|
|
67
|
+
- **🔍 Scanner** — Detect SQLi, XSS, SSTI, LFI, RCE, SSRF, XXE and more (active + passive modes)
|
|
68
|
+
- **🕷 Spider** — Crawl sites automatically, collect pages, forms and JS endpoints
|
|
69
|
+
- **🎯 Target / Site Map** — Build a site map and manage testing scope from the UI
|
|
70
|
+
- **🔐 Decoder + Comparer + Sequencer** — Encode/decode, diff requests, analyze token entropy
|
|
71
|
+
- **🧩 Plugin system** — Extend functionality without recompiling
|
|
72
|
+
- **⚡ Async core** — Fully async, optimized for high load
|
|
73
|
+
- **🆓 Open Source + PRO** — Free base, optional PRO license for advanced features
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 📦 Installation
|
|
78
|
+
|
|
79
|
+
**Requirements:** Python 3.10+, Linux / macOS / Windows
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install pentool
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
From source:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
git clone https://github.com/docx/pentool.git
|
|
89
|
+
cd pentool
|
|
90
|
+
pip install -e ".[dev]"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 🚀 Quick Start
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Launch the TUI
|
|
99
|
+
pentool
|
|
100
|
+
|
|
101
|
+
# Start proxy on custom port
|
|
102
|
+
pentool proxy start --port 8080
|
|
103
|
+
|
|
104
|
+
# Run active scan
|
|
105
|
+
pentool scan active --url https://example.com
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 💰 Pricing
|
|
111
|
+
|
|
112
|
+
| Plan | Price | Features |
|
|
113
|
+
|------|-------|----------|
|
|
114
|
+
| **Free** | $0 | Proxy, Repeater, Intruder, Decoder |
|
|
115
|
+
| **Lite** | $29/mo | + Scanner, Spider, Match & Replace |
|
|
116
|
+
| **Medium** | $99/mo | + WebSocket, Plugins, Turbo Mode |
|
|
117
|
+
| **Full** | $299/mo | + PRO Reports, API, Unlimited |
|
|
118
|
+
|
|
119
|
+
[Get PRO license →](https://pentool.pro)
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 🤝 Support the project
|
|
124
|
+
|
|
125
|
+
Pentool is developed in free time. If it helps your work, consider supporting:
|
|
126
|
+
|
|
127
|
+
- [GitHub Sponsors](https://github.com/sponsors/docx)
|
|
128
|
+
- [Buy PRO license](https://pentool.pro) — also supports development
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 📖 Documentation
|
|
133
|
+
|
|
134
|
+
- [Quick Start](docs/QUICKSTART.md)
|
|
135
|
+
- [User Guide](docs/user/)
|
|
136
|
+
- [Architecture](docs/ARCHITECTURE_AUDIT.md)
|
|
137
|
+
- [API Reference](docs/API_CONTRACTS.md)
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 🧪 Tests
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
pytest tests/unit/ -q
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 🤝 Contributing
|
|
150
|
+
|
|
151
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Report vulnerabilities to security@pentool.pro.
|
|
152
|
+
|
|
153
|
+
## 📄 License
|
|
154
|
+
|
|
155
|
+
Community Edition: [AGPL-3.0](LICENSE) · PRO Edition: Commercial
|
pentool-1.0.0/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# 🔐 Pentool — Modern Web Pentesting TUI
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/py/pentool)
|
|
4
|
+
[](https://pypi.org/project/pentool/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://github.com/docx/pentool/actions)
|
|
7
|
+
|
|
8
|
+
**Pentool** is a fast, modular web security testing tool with a terminal UI. Built for pentesters and security researchers who prefer working in the terminal.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install pentool
|
|
12
|
+
pentool
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## ✨ Features
|
|
18
|
+
|
|
19
|
+
- **🌐 Proxy** — Intercept and modify HTTP/HTTPS traffic in real time, manage scope, apply match & replace rules
|
|
20
|
+
- **🔄 Repeater** — Replay requests with any modifications, persist tabs between sessions
|
|
21
|
+
- **💥 Intruder** — Automated attacks with 4 strategies: Sniper, Battering Ram, Pitchfork, Cluster Bomb
|
|
22
|
+
- **🚀 Turbo Intruder** — 10× speed via HTTP Keep-Alive and connection pooling (100–200 req/sec)
|
|
23
|
+
- **🔍 Scanner** — Detect SQLi, XSS, SSTI, LFI, RCE, SSRF, XXE and more (active + passive modes)
|
|
24
|
+
- **🕷 Spider** — Crawl sites automatically, collect pages, forms and JS endpoints
|
|
25
|
+
- **🎯 Target / Site Map** — Build a site map and manage testing scope from the UI
|
|
26
|
+
- **🔐 Decoder + Comparer + Sequencer** — Encode/decode, diff requests, analyze token entropy
|
|
27
|
+
- **🧩 Plugin system** — Extend functionality without recompiling
|
|
28
|
+
- **⚡ Async core** — Fully async, optimized for high load
|
|
29
|
+
- **🆓 Open Source + PRO** — Free base, optional PRO license for advanced features
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 📦 Installation
|
|
34
|
+
|
|
35
|
+
**Requirements:** Python 3.10+, Linux / macOS / Windows
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install pentool
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
From source:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
git clone https://github.com/docx/pentool.git
|
|
45
|
+
cd pentool
|
|
46
|
+
pip install -e ".[dev]"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 🚀 Quick Start
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Launch the TUI
|
|
55
|
+
pentool
|
|
56
|
+
|
|
57
|
+
# Start proxy on custom port
|
|
58
|
+
pentool proxy start --port 8080
|
|
59
|
+
|
|
60
|
+
# Run active scan
|
|
61
|
+
pentool scan active --url https://example.com
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 💰 Pricing
|
|
67
|
+
|
|
68
|
+
| Plan | Price | Features |
|
|
69
|
+
|------|-------|----------|
|
|
70
|
+
| **Free** | $0 | Proxy, Repeater, Intruder, Decoder |
|
|
71
|
+
| **Lite** | $29/mo | + Scanner, Spider, Match & Replace |
|
|
72
|
+
| **Medium** | $99/mo | + WebSocket, Plugins, Turbo Mode |
|
|
73
|
+
| **Full** | $299/mo | + PRO Reports, API, Unlimited |
|
|
74
|
+
|
|
75
|
+
[Get PRO license →](https://pentool.pro)
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 🤝 Support the project
|
|
80
|
+
|
|
81
|
+
Pentool is developed in free time. If it helps your work, consider supporting:
|
|
82
|
+
|
|
83
|
+
- [GitHub Sponsors](https://github.com/sponsors/docx)
|
|
84
|
+
- [Buy PRO license](https://pentool.pro) — also supports development
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 📖 Documentation
|
|
89
|
+
|
|
90
|
+
- [Quick Start](docs/QUICKSTART.md)
|
|
91
|
+
- [User Guide](docs/user/)
|
|
92
|
+
- [Architecture](docs/ARCHITECTURE_AUDIT.md)
|
|
93
|
+
- [API Reference](docs/API_CONTRACTS.md)
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 🧪 Tests
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pytest tests/unit/ -q
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 🤝 Contributing
|
|
106
|
+
|
|
107
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Report vulnerabilities to security@pentool.pro.
|
|
108
|
+
|
|
109
|
+
## 📄 License
|
|
110
|
+
|
|
111
|
+
Community Edition: [AGPL-3.0](LICENSE) · PRO Edition: Commercial
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Точка входа: без аргументов — TUI, с аргументами — CLI."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def main() -> None:
|
|
7
|
+
"""Запустить TUI или CLI в зависимости от аргументов."""
|
|
8
|
+
if len(sys.argv) > 1:
|
|
9
|
+
from pentool.cli.main import cli
|
|
10
|
+
cli()
|
|
11
|
+
else:
|
|
12
|
+
from pentool.tui.app import PentoolApp
|
|
13
|
+
PentoolApp().run()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if __name__ == "__main__":
|
|
17
|
+
main()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""API-слой pentool — публичный интерфейс между modules/ и TUI/CLI.
|
|
2
|
+
|
|
3
|
+
TUI и CLI импортируют только из pentool.api, не из pentool.modules напрямую.
|
|
4
|
+
Это позволяет независимо менять логику и отображение.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pentool.api.proxy_api import ProxyAPI, InterceptedRequest, MatchReplaceRule
|
|
8
|
+
from pentool.api.repeater_api import RepeaterAPI
|
|
9
|
+
from pentool.api.scanner_api import ScannerAPI
|
|
10
|
+
from pentool.api.intruder_api import IntruderAPI, IntruderConfig, IntruderAttack
|
|
11
|
+
from pentool.api.spider_api import SpiderAPI
|
|
12
|
+
from pentool.api.target_api import TargetAPI
|
|
13
|
+
# Decoder/Comparer/Sequencer — функциональные API без класса-обёртки
|
|
14
|
+
from pentool.api.decoder_api import ( # noqa: F401
|
|
15
|
+
OPERATIONS, OP_LABELS, DecoderChain,
|
|
16
|
+
decode_op, decode_smart, encode_op, run_chain,
|
|
17
|
+
)
|
|
18
|
+
from pentool.api.comparer_api import ( # noqa: F401
|
|
19
|
+
compare, compare_lines, CompareStats, DiffLine, DiffResult,
|
|
20
|
+
)
|
|
21
|
+
from pentool.api.sequencer_api import ( # noqa: F401
|
|
22
|
+
Sequencer, SequencerReport, token_entropy, charset_size,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
# Proxy
|
|
27
|
+
"ProxyAPI", "InterceptedRequest", "MatchReplaceRule",
|
|
28
|
+
# Repeater
|
|
29
|
+
"RepeaterAPI",
|
|
30
|
+
# Scanner
|
|
31
|
+
"ScannerAPI",
|
|
32
|
+
# Intruder
|
|
33
|
+
"IntruderAPI", "IntruderConfig", "IntruderAttack",
|
|
34
|
+
# Spider
|
|
35
|
+
"SpiderAPI",
|
|
36
|
+
# Target
|
|
37
|
+
"TargetAPI",
|
|
38
|
+
# Decoder
|
|
39
|
+
"OPERATIONS", "OP_LABELS", "DecoderChain",
|
|
40
|
+
"decode_op", "decode_smart", "encode_op", "run_chain",
|
|
41
|
+
# Comparer
|
|
42
|
+
"compare", "compare_lines", "CompareStats", "DiffLine", "DiffResult",
|
|
43
|
+
# Sequencer
|
|
44
|
+
"Sequencer", "SequencerReport", "token_entropy", "charset_size",
|
|
45
|
+
]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""ExportableAPI — base mixin for API classes supporting project persistence.
|
|
2
|
+
|
|
3
|
+
All API classes that implement export_project_data/import_project_data should
|
|
4
|
+
inherit from this mixin for type consistency and documentation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ExportableAPI(ABC):
|
|
13
|
+
"""Mixin for API classes that support project data export/import.
|
|
14
|
+
|
|
15
|
+
Subclasses must implement export_project_data and import_project_data.
|
|
16
|
+
These methods are called by core.project.save_project/load_project.
|
|
17
|
+
|
|
18
|
+
Usage::
|
|
19
|
+
|
|
20
|
+
class MyAPI(ExportableAPI):
|
|
21
|
+
def export_project_data(self) -> dict:
|
|
22
|
+
return {"my_data": [...]}
|
|
23
|
+
|
|
24
|
+
def import_project_data(self, data: dict) -> int:
|
|
25
|
+
items = data.get("my_data", [])
|
|
26
|
+
# restore items
|
|
27
|
+
return len(items)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def export_project_data(self) -> dict:
|
|
32
|
+
"""Export module state to a serializable dict.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
dict: Module-specific data structure (e.g., {"results": [...]}).
|
|
36
|
+
Must be JSON-serializable (no datetime, use .isoformat()).
|
|
37
|
+
"""
|
|
38
|
+
raise NotImplementedError
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def import_project_data(self, data: dict) -> int | tuple[int, str]:
|
|
42
|
+
"""Import module state from a loaded project dict.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
data: The module's block from project.json (e.g., data["intruder"]).
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
int: Number of items loaded successfully.
|
|
49
|
+
OR
|
|
50
|
+
tuple[int, str]: (count, error_message) — empty string if OK.
|
|
51
|
+
"""
|
|
52
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""ComparerAPI — публичный интерфейс Comparer для TUI.
|
|
2
|
+
|
|
3
|
+
TUI-экраны импортируют только этот модуль,
|
|
4
|
+
не modules/comparer.py напрямую.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pentool.modules.comparer import ( # noqa: F401
|
|
10
|
+
compare,
|
|
11
|
+
compare_lines,
|
|
12
|
+
CompareStats,
|
|
13
|
+
DiffLine,
|
|
14
|
+
DiffResult,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"compare",
|
|
19
|
+
"compare_lines",
|
|
20
|
+
"CompareStats",
|
|
21
|
+
"DiffLine",
|
|
22
|
+
"DiffResult",
|
|
23
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""DecoderAPI — публичный интерфейс Decoder/Encoder для TUI.
|
|
2
|
+
|
|
3
|
+
TUI-экраны импортируют только этот модуль,
|
|
4
|
+
не modules/decoder.py напрямую.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
# Реэкспорт всего публичного из modules/decoder
|
|
10
|
+
from pentool.modules.decoder import ( # noqa: F401
|
|
11
|
+
OPERATIONS,
|
|
12
|
+
OP_LABELS,
|
|
13
|
+
DecoderChain,
|
|
14
|
+
decode_op,
|
|
15
|
+
decode_smart,
|
|
16
|
+
encode_op,
|
|
17
|
+
run_chain,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"OPERATIONS",
|
|
22
|
+
"OP_LABELS",
|
|
23
|
+
"DecoderChain",
|
|
24
|
+
"decode_op",
|
|
25
|
+
"decode_smart",
|
|
26
|
+
"encode_op",
|
|
27
|
+
"run_chain",
|
|
28
|
+
]
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""Публичный API Intruder-модуля для TUI и CLI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from pentool.modules.intruder import (
|
|
8
|
+
AttackType,
|
|
9
|
+
IntruderAttack,
|
|
10
|
+
IntruderConfig,
|
|
11
|
+
IntruderResult,
|
|
12
|
+
count_markers,
|
|
13
|
+
extract_marker_defaults,
|
|
14
|
+
generate_char_payloads,
|
|
15
|
+
generate_numeric_payloads,
|
|
16
|
+
load_payloads_from_file,
|
|
17
|
+
process_payload,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"IntruderAPI",
|
|
22
|
+
"AttackType",
|
|
23
|
+
"IntruderAttack",
|
|
24
|
+
"IntruderConfig",
|
|
25
|
+
"IntruderResult",
|
|
26
|
+
"count_markers",
|
|
27
|
+
"extract_marker_defaults",
|
|
28
|
+
"generate_char_payloads",
|
|
29
|
+
"generate_numeric_payloads",
|
|
30
|
+
"load_payloads_from_file",
|
|
31
|
+
"process_payload",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class IntruderAPI:
|
|
36
|
+
"""Публичный интерфейс Intruder-модуля.
|
|
37
|
+
|
|
38
|
+
Тонкая обёртка над IntruderAttack.
|
|
39
|
+
Не знает о Textual.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(self, db_path: str | None = None) -> None:
|
|
43
|
+
self._db_path = db_path
|
|
44
|
+
self._attack: IntruderAttack | None = None
|
|
45
|
+
|
|
46
|
+
async def start_attack(
|
|
47
|
+
self,
|
|
48
|
+
config: IntruderConfig,
|
|
49
|
+
on_result=None,
|
|
50
|
+
on_progress=None,
|
|
51
|
+
turbo_mode: bool = False,
|
|
52
|
+
) -> str:
|
|
53
|
+
"""Запустить атаку. Возвращает attack_id.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
config: Конфиг атаки.
|
|
57
|
+
on_result: Callback(IntruderResult) — вызывается на каждый результат.
|
|
58
|
+
on_progress: Callback(done, total) — вызывается при обновлении прогресса.
|
|
59
|
+
turbo_mode: Использовать Turbo Mode (HTTP Keep-Alive, connection pooling).
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
str: attack_id (UUID).
|
|
63
|
+
"""
|
|
64
|
+
if turbo_mode:
|
|
65
|
+
# Turbo Mode: connection pooling + Keep-Alive
|
|
66
|
+
from pentool.modules.intruder_turbo import TurboIntruderAttack
|
|
67
|
+
self._attack = TurboIntruderAttack(config)
|
|
68
|
+
else:
|
|
69
|
+
# Обычный режим
|
|
70
|
+
self._attack = IntruderAttack(config, db_path=self._db_path)
|
|
71
|
+
|
|
72
|
+
_on_result = on_result if on_result else lambda r: None
|
|
73
|
+
_on_progress = on_progress if on_progress else lambda d, t: None
|
|
74
|
+
|
|
75
|
+
import asyncio
|
|
76
|
+
asyncio.create_task(self._attack.run(_on_result, _on_progress))
|
|
77
|
+
return self._attack.attack_id if hasattr(self._attack, 'attack_id') else "turbo"
|
|
78
|
+
|
|
79
|
+
async def pause(self) -> None:
|
|
80
|
+
"""Поставить атаку на паузу."""
|
|
81
|
+
if self._attack:
|
|
82
|
+
await self._attack.pause()
|
|
83
|
+
|
|
84
|
+
async def resume(self) -> None:
|
|
85
|
+
"""Возобновить атаку после паузы."""
|
|
86
|
+
if self._attack:
|
|
87
|
+
await self._attack.resume()
|
|
88
|
+
|
|
89
|
+
async def stop(self) -> None:
|
|
90
|
+
"""Остановить атаку."""
|
|
91
|
+
if self._attack:
|
|
92
|
+
await self._attack.stop()
|
|
93
|
+
|
|
94
|
+
def get_results(self) -> list[IntruderResult]:
|
|
95
|
+
"""Получить список результатов текущей атаки."""
|
|
96
|
+
if self._attack:
|
|
97
|
+
# Turbo mode использует get_results(), обычный - results property
|
|
98
|
+
if hasattr(self._attack, 'get_results'):
|
|
99
|
+
return self._attack.get_results()
|
|
100
|
+
return self._attack.results
|
|
101
|
+
return []
|
|
102
|
+
|
|
103
|
+
def get_progress(self) -> tuple[int, int]:
|
|
104
|
+
"""Вернуть (done, total) текущей атаки."""
|
|
105
|
+
if self._attack:
|
|
106
|
+
return self._attack.progress
|
|
107
|
+
return (0, 0)
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def is_running(self) -> bool:
|
|
111
|
+
"""Возвращает True если атака сейчас выполняется."""
|
|
112
|
+
return bool(self._attack and self._attack.is_running)
|
|
113
|
+
|
|
114
|
+
async def load_payloads(self, path: str) -> list[str]:
|
|
115
|
+
"""Загрузить payload'ы из файла."""
|
|
116
|
+
return load_payloads_from_file(path)
|
|
117
|
+
|
|
118
|
+
async def generate_numeric(self, start: int, end: int, step: int = 1) -> list[str]:
|
|
119
|
+
"""Сгенерировать числовые payload'ы."""
|
|
120
|
+
return generate_numeric_payloads(start, end, step)
|
|
121
|
+
|
|
122
|
+
async def generate_chars(
|
|
123
|
+
self, charset: str, min_len: int, max_len: int
|
|
124
|
+
) -> list[str]:
|
|
125
|
+
"""Сгенерировать символьные payload'ы."""
|
|
126
|
+
return generate_char_payloads(charset, min_len, max_len)
|
|
127
|
+
|
|
128
|
+
def export_csv(self, path: str) -> None:
|
|
129
|
+
"""Экспортировать результаты в CSV."""
|
|
130
|
+
if self._attack:
|
|
131
|
+
self._attack.export_csv(path)
|
|
132
|
+
|
|
133
|
+
# ── Project persistence ────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
def export_project_data(self) -> dict:
|
|
136
|
+
"""Экспортировать результаты Intruder в сериализуемый dict.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
dict с ключом "results" — список IntruderResult в виде dict.
|
|
140
|
+
"""
|
|
141
|
+
results = self.get_results()
|
|
142
|
+
return {
|
|
143
|
+
"results": [
|
|
144
|
+
{
|
|
145
|
+
"id": r.id,
|
|
146
|
+
"attack_id": r.attack_id,
|
|
147
|
+
"request_number": r.request_number,
|
|
148
|
+
"payload_values": r.payload_values,
|
|
149
|
+
"request_raw": r.request_raw,
|
|
150
|
+
"response_status": r.response_status,
|
|
151
|
+
"response_length": r.response_length,
|
|
152
|
+
"response_time_ms": r.response_time_ms,
|
|
153
|
+
"error": r.error,
|
|
154
|
+
"timestamp": r.timestamp.isoformat(),
|
|
155
|
+
}
|
|
156
|
+
for r in results
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
def import_project_data(self, data: dict) -> int:
|
|
161
|
+
"""Импортировать результаты Intruder из загруженного dict проекта.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
data: Блок "intruder" из project.json ({"results": [...]}).
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Количество загруженных результатов.
|
|
168
|
+
"""
|
|
169
|
+
from datetime import datetime, timezone
|
|
170
|
+
from pentool.modules.intruder import IntruderResult
|
|
171
|
+
|
|
172
|
+
results_data = data.get("results", [])
|
|
173
|
+
# Создаём фиктивный attack для хранения результатов
|
|
174
|
+
# без реального запуска атаки
|
|
175
|
+
if self._attack is None:
|
|
176
|
+
# Ленивая инициализация — просто храним в атрибуте
|
|
177
|
+
self._restored_results: list[IntruderResult] = []
|
|
178
|
+
else:
|
|
179
|
+
self._restored_results = []
|
|
180
|
+
|
|
181
|
+
loaded = 0
|
|
182
|
+
for rd in results_data:
|
|
183
|
+
try:
|
|
184
|
+
ts_raw = rd.get("timestamp", "")
|
|
185
|
+
try:
|
|
186
|
+
ts = datetime.fromisoformat(ts_raw)
|
|
187
|
+
except Exception:
|
|
188
|
+
ts = datetime.now(timezone.utc)
|
|
189
|
+
result = IntruderResult(
|
|
190
|
+
id=rd.get("id", ""),
|
|
191
|
+
attack_id=rd.get("attack_id", ""),
|
|
192
|
+
request_number=rd.get("request_number", 0),
|
|
193
|
+
payload_values=rd.get("payload_values", []),
|
|
194
|
+
request_raw=rd.get("request_raw", ""),
|
|
195
|
+
response_status=rd.get("response_status"),
|
|
196
|
+
response_length=rd.get("response_length"),
|
|
197
|
+
response_time_ms=rd.get("response_time_ms"),
|
|
198
|
+
error=rd.get("error"),
|
|
199
|
+
timestamp=ts,
|
|
200
|
+
)
|
|
201
|
+
if hasattr(self, "_restored_results"):
|
|
202
|
+
self._restored_results.append(result)
|
|
203
|
+
loaded += 1
|
|
204
|
+
except Exception as exc:
|
|
205
|
+
from pentool.core.logging import get_logger
|
|
206
|
+
get_logger(__name__).warning(
|
|
207
|
+
"IntruderAPI.import_project_data: skip result: %s", exc
|
|
208
|
+
)
|
|
209
|
+
return loaded
|