cli-anything-godzilla 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.
- cli_anything_godzilla-1.0.0/PKG-INFO +9 -0
- cli_anything_godzilla-1.0.0/README.md +401 -0
- cli_anything_godzilla-1.0.0/cli_anything/godzilla/__init__.py +57 -0
- cli_anything_godzilla-1.0.0/cli_anything/godzilla/godzilla_cli.py +583 -0
- cli_anything_godzilla-1.0.0/cli_anything_godzilla.egg-info/PKG-INFO +9 -0
- cli_anything_godzilla-1.0.0/cli_anything_godzilla.egg-info/SOURCES.txt +10 -0
- cli_anything_godzilla-1.0.0/cli_anything_godzilla.egg-info/dependency_links.txt +1 -0
- cli_anything_godzilla-1.0.0/cli_anything_godzilla.egg-info/entry_points.txt +2 -0
- cli_anything_godzilla-1.0.0/cli_anything_godzilla.egg-info/requires.txt +3 -0
- cli_anything_godzilla-1.0.0/cli_anything_godzilla.egg-info/top_level.txt +1 -0
- cli_anything_godzilla-1.0.0/setup.cfg +4 -0
- cli_anything_godzilla-1.0.0/setup.py +24 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
# cli-anything-godzilla
|
|
2
|
+
|
|
3
|
+
[English](#english) | [简体中文](#简体中文)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## English
|
|
8
|
+
|
|
9
|
+
CLI harness for Godzilla Security Testing Tool.
|
|
10
|
+
|
|
11
|
+
> **Note**: This is a standalone CLI tool that works with the original Godzilla GUI tool.
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
- ✅ Complete project management (create, open, save, info)
|
|
16
|
+
- ✅ Shell management (add, list, update, remove, test connection)
|
|
17
|
+
- ✅ Short ID support (all shell commands support short IDs)
|
|
18
|
+
- ✅ C2 Profile management (load and validate)
|
|
19
|
+
- ✅ Interactive REPL mode with friendly UI
|
|
20
|
+
- ✅ JSON output mode for AI agent integration
|
|
21
|
+
- ✅ Compatible with original Godzilla project database
|
|
22
|
+
|
|
23
|
+
### Installation
|
|
24
|
+
|
|
25
|
+
#### Prerequisites
|
|
26
|
+
|
|
27
|
+
- Python 3.12+ (tested with Python 3.12.8)
|
|
28
|
+
- Java Runtime Environment (JRE) 11+
|
|
29
|
+
- Godzilla JAR file (Godzilla15.jar)
|
|
30
|
+
|
|
31
|
+
#### Install the CLI
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# From PyPI (when published)
|
|
35
|
+
pip install cli-anything-godzilla
|
|
36
|
+
|
|
37
|
+
# Or install locally for development
|
|
38
|
+
git clone https://github.com/fengchenzxc/cli-anything-godzilla.git
|
|
39
|
+
cd cli-anything-godzilla
|
|
40
|
+
pip install -e .
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
#### Verify Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
which cli-anything-godzilla
|
|
47
|
+
cli-anything-godzilla --help
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Usage
|
|
51
|
+
|
|
52
|
+
#### Start Interactive REPL Mode
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Start with no arguments (enter REPL mode)
|
|
56
|
+
cli-anything-godzilla
|
|
57
|
+
|
|
58
|
+
# Or specify a project
|
|
59
|
+
cli-anything-godzilla -p /path/to/project
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Project Management
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Create a new project
|
|
66
|
+
cli-anything-godzilla project new my-project -n "My Project" -d "Project description"
|
|
67
|
+
|
|
68
|
+
# Open an existing project
|
|
69
|
+
cli-anything-godzilla project open /path/to/project
|
|
70
|
+
|
|
71
|
+
# Show project information
|
|
72
|
+
cli-anything-godzilla project info
|
|
73
|
+
|
|
74
|
+
# List all projects
|
|
75
|
+
cli-anything-godzilla project list
|
|
76
|
+
|
|
77
|
+
# Close current project
|
|
78
|
+
cli-anything-godzilla project close
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### Shell Management
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Add a shell
|
|
85
|
+
cli-anything-godzilla shell add -u http://target.com/shell.jsp -p password
|
|
86
|
+
|
|
87
|
+
# List all shells
|
|
88
|
+
cli-anything-godzilla shell list
|
|
89
|
+
|
|
90
|
+
# Get shell details (supports short ID)
|
|
91
|
+
cli-anything-godzilla shell get 31f09e27
|
|
92
|
+
|
|
93
|
+
# Test shell connectivity (supports short ID)
|
|
94
|
+
cli-anything-godzilla shell test 31f09e27
|
|
95
|
+
|
|
96
|
+
# Update shell configuration
|
|
97
|
+
cli-anything-godzilla shell update 31f09e27 --remark "Updated remark"
|
|
98
|
+
|
|
99
|
+
# Remove a shell (supports short ID)
|
|
100
|
+
cli-anything-godzilla shell remove 31f09e27
|
|
101
|
+
|
|
102
|
+
# Export shells
|
|
103
|
+
cli-anything-godzilla shell export shells.json
|
|
104
|
+
|
|
105
|
+
# Import shells
|
|
106
|
+
cli-anything-godzilla shell import shells.json
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### C2 Profile Management
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# List available profiles
|
|
113
|
+
cli-anything-godzilla profile list
|
|
114
|
+
|
|
115
|
+
# Load a profile
|
|
116
|
+
cli-anything-godzilla profile load /path/to/profile.yml
|
|
117
|
+
|
|
118
|
+
# Validate a profile
|
|
119
|
+
cli-anything-godzilla profile validate /path/to/profile.yml
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### JSON Output Mode
|
|
123
|
+
|
|
124
|
+
All commands support `--json` flag for machine-readable output:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
cli-anything-godzilla --json shell list
|
|
128
|
+
cli-anything-godzilla --json shell get 31f09e27
|
|
129
|
+
cli-anything-godzilla --json project info
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### REPL Commands
|
|
133
|
+
|
|
134
|
+
When in interactive mode, use these commands:
|
|
135
|
+
|
|
136
|
+
| Command | Description |
|
|
137
|
+
|--------|-------------|
|
|
138
|
+
| `help` | Show available commands |
|
|
139
|
+
| `exit` | Exit REPL mode |
|
|
140
|
+
| `project info` | Show project information |
|
|
141
|
+
| `project list` | List all projects |
|
|
142
|
+
| `shell list` | List all shells |
|
|
143
|
+
| `shell get <id>` | Get shell details |
|
|
144
|
+
| `shell add <url> <password>` | Add new shell |
|
|
145
|
+
| `shell test <id>` | Test shell connectivity |
|
|
146
|
+
| `shell update <id> --remark "xxx"` | Update shell remark |
|
|
147
|
+
| `shell remove <id>` | Remove shell |
|
|
148
|
+
| `profile list` | List C2 profiles |
|
|
149
|
+
|
|
150
|
+
### Configuration
|
|
151
|
+
|
|
152
|
+
#### Supported Payload Types
|
|
153
|
+
|
|
154
|
+
- `JavaDynamicPayload` - Java dynamic payload
|
|
155
|
+
- `CSharpDynamicPayload` - C# dynamic payload
|
|
156
|
+
- `PhpDynamicPayload` - PHP dynamic payload
|
|
157
|
+
|
|
158
|
+
#### Supported Encryption Types
|
|
159
|
+
|
|
160
|
+
- `xor` - XOR encryption
|
|
161
|
+
- `aes128` - AES-128 encryption
|
|
162
|
+
- `aes256` - AES-256 encryption
|
|
163
|
+
- `base64` - Base64 encoding
|
|
164
|
+
- `hex` - Hexadecimal encoding
|
|
165
|
+
- `raw` - Raw data
|
|
166
|
+
- `rsa` - RSA encryption
|
|
167
|
+
|
|
168
|
+
### Running Tests
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Run unit tests
|
|
172
|
+
cd /path/to/agent-harness
|
|
173
|
+
python3.12 -m pytest cli_anything/godzilla/tests/test_core.py -v
|
|
174
|
+
|
|
175
|
+
# Run E2E tests
|
|
176
|
+
python3.12 -m pytest cli_anything/godzilla/tests/test_full_e2e.py -v -s
|
|
177
|
+
|
|
178
|
+
# Run with force-installed mode
|
|
179
|
+
CLI_ANYTHING_FORCE_INSTALLED=1 python3.12 -m pytest cli_anything/godzilla/tests/ -v -s
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 简体中文
|
|
185
|
+
|
|
186
|
+
CLI 命令行工具包,用于哥斯拉(Godzilla)WebShell 管理器的安全测试。
|
|
187
|
+
|
|
188
|
+
> **注意**: 本项目是一个独立的 CLI 工具,与原版哥斯拉 GUI 工具配合使用。
|
|
189
|
+
|
|
190
|
+
### 功能特性
|
|
191
|
+
|
|
192
|
+
- ✅ 完整的项目管理(创建、打开、保存、信息)
|
|
193
|
+
- ✅ Shell 管理(添加、查看、更新、删除、测试连接)
|
|
194
|
+
- ✅ 短 ID 支持(所有 shell 命令支持使用短 ID)
|
|
195
|
+
- ✅ C2 Profile 管理(加载和验证)
|
|
196
|
+
- ✅ 交互式 REPL 模式,界面友好
|
|
197
|
+
- ✅ JSON 输出模式(便于 AI 代理集成)
|
|
198
|
+
- ✅ 兼容原版哥斯拉项目数据库
|
|
199
|
+
|
|
200
|
+
### 安装
|
|
201
|
+
|
|
202
|
+
#### 前置要求
|
|
203
|
+
|
|
204
|
+
- Python 3.12+ (已测试 Python 3.12.8)
|
|
205
|
+
- Java Runtime Environment (JRE) 11+
|
|
206
|
+
- 哥斯拉 JAR 文件 (Godzilla15.jar)
|
|
207
|
+
|
|
208
|
+
#### 安装 CLI
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# 从 PyPI 安装 (发布后)
|
|
212
|
+
pip install cli-anything-godzilla
|
|
213
|
+
|
|
214
|
+
# 或本地开发安装
|
|
215
|
+
git clone https://github.com/fengchenzxc/cli-anything-godzilla.git
|
|
216
|
+
cd cli-anything-godzilla
|
|
217
|
+
pip install -e .
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
#### 验证安装
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
which cli-anything-godzilla
|
|
224
|
+
cli-anything-godzilla --help
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 使用方法
|
|
228
|
+
|
|
229
|
+
#### 启动交互式 REPL 模式
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# 无参数启动(进入 REPL 模式)
|
|
233
|
+
cli-anything-godzilla
|
|
234
|
+
|
|
235
|
+
# 指定项目启动
|
|
236
|
+
cli-anything-godzilla -p /path/to/project
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### 项目管理
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# 创建新项目
|
|
243
|
+
cli-anything-godzilla project new my-project -n "我的项目" -d "项目描述"
|
|
244
|
+
|
|
245
|
+
# 打开已有项目
|
|
246
|
+
cli-anything-godzilla project open /path/to/project
|
|
247
|
+
|
|
248
|
+
# 查看项目信息
|
|
249
|
+
cli-anything-godzilla project info
|
|
250
|
+
|
|
251
|
+
# 列出所有项目
|
|
252
|
+
cli-anything-godzilla project list
|
|
253
|
+
|
|
254
|
+
# 关闭当前项目
|
|
255
|
+
cli-anything-godzilla project close
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
#### Shell 管理
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# 添加 shell
|
|
262
|
+
cli-anything-godzilla shell add -u http://target.com/shell.jsp -p password
|
|
263
|
+
|
|
264
|
+
# 列出所有 shell
|
|
265
|
+
cli-anything-godzilla shell list
|
|
266
|
+
|
|
267
|
+
# 获取 shell 详情(支持短 ID)
|
|
268
|
+
cli-anything-godzilla shell get 31f09e27
|
|
269
|
+
|
|
270
|
+
# 测试 shell 连接(支持短 ID)
|
|
271
|
+
cli-anything-godzilla shell test 31f09e27
|
|
272
|
+
|
|
273
|
+
# 更新 shell 配置
|
|
274
|
+
cli-anything-godzilla shell update 31f09e27 --remark "更新备注"
|
|
275
|
+
|
|
276
|
+
# 删除 shell(支持短 ID)
|
|
277
|
+
cli-anything-godzilla shell remove 31f09e27
|
|
278
|
+
|
|
279
|
+
# 导出 shell
|
|
280
|
+
cli-anything-godzilla shell export shells.json
|
|
281
|
+
|
|
282
|
+
# 导入 shell
|
|
283
|
+
cli-anything-godzilla shell import shells.json
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
#### C2 Profile 管理
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
# 列出可用的 profiles
|
|
290
|
+
cli-anything-godzilla profile list
|
|
291
|
+
|
|
292
|
+
# 加载 profile
|
|
293
|
+
cli-anything-godzilla profile load /path/to/profile.yml
|
|
294
|
+
|
|
295
|
+
# 验证 profile
|
|
296
|
+
cli-anything-godzilla profile validate /path/to/profile.yml
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
#### JSON 输出模式
|
|
300
|
+
|
|
301
|
+
所有命令支持 `--json` 标志,输出机器可读格式:
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
cli-anything-godzilla --json shell list
|
|
305
|
+
cli-anything-godzilla --json shell get 31f09e27
|
|
306
|
+
cli-anything-godzilla --json project info
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### REPL 交互命令
|
|
310
|
+
|
|
311
|
+
在交互模式下,可使用以下命令:
|
|
312
|
+
|
|
313
|
+
| 命令 | 描述 |
|
|
314
|
+
|------|------|
|
|
315
|
+
| `help` | 显示可用命令 |
|
|
316
|
+
| `exit` | 退出 REPL 模式 |
|
|
317
|
+
| `project info` | 显示项目信息 |
|
|
318
|
+
| `project list` | 列出所有项目 |
|
|
319
|
+
| `shell list` | 列出所有 shell |
|
|
320
|
+
| `shell get <id>` | 获取 shell 详情 |
|
|
321
|
+
| `shell add <url> <password>` | 添加新 shell |
|
|
322
|
+
| `shell test <id>` | 测试 shell 连接 |
|
|
323
|
+
| `shell update <id> --remark "xxx"` | 更新 shell 备注 |
|
|
324
|
+
| `shell remove <id>` | 删除 shell |
|
|
325
|
+
| `profile list` | 列出 C2 profiles |
|
|
326
|
+
|
|
327
|
+
### 配置
|
|
328
|
+
|
|
329
|
+
#### 支持的载荷类型
|
|
330
|
+
|
|
331
|
+
- `JavaDynamicPayload` - Java 动态载荷
|
|
332
|
+
- `CSharpDynamicPayload` - C# 动态载荷
|
|
333
|
+
- `PhpDynamicPayload` - PHP 动态载荷
|
|
334
|
+
|
|
335
|
+
#### 支持的加密方式
|
|
336
|
+
|
|
337
|
+
- `xor` - XOR 加密
|
|
338
|
+
- `aes128` - AES-128 加密
|
|
339
|
+
- `aes256` - AES-256 加密
|
|
340
|
+
- `base64` - Base64 编码
|
|
341
|
+
- `hex` - 十六进制编码
|
|
342
|
+
- `raw` - 原始数据
|
|
343
|
+
- `rsa` - RSA 加密
|
|
344
|
+
|
|
345
|
+
### 运行测试
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
# 运行单元测试
|
|
349
|
+
cd /path/to/agent-harness
|
|
350
|
+
python3.12 -m pytest cli_anything/godzilla/tests/test_core.py -v
|
|
351
|
+
|
|
352
|
+
# 运行 E2E 测试
|
|
353
|
+
python3.12 -m pytest cli_anything/godzilla/tests/test_full_e2e.py -v -s
|
|
354
|
+
|
|
355
|
+
# 使用强制安装模式运行测试
|
|
356
|
+
CLI_ANYTHING_FORCE_INSTALLED=1 python3.12 -m pytest cli_anything/godzilla/tests/ -v -s
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### 兼容性
|
|
360
|
+
|
|
361
|
+
- 可直接打开原版哥斯拉创建的项目(自动生成配置文件)
|
|
362
|
+
- 数据库列名使用 camelCase(与原版哥斯拉保持一致)
|
|
363
|
+
- 支持 HTTP 请求头的 JSON 和纯文本两种格式
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Project Structure / 项目结构
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
cli_anything/godzilla/
|
|
371
|
+
├── __init__.py
|
|
372
|
+
├── godzilla_cli.py # Main CLI entry point / CLI 主入口
|
|
373
|
+
├── core/
|
|
374
|
+
│ ├── __init__.py
|
|
375
|
+
│ ├── project.py # Project management / 项目管理
|
|
376
|
+
│ ├── shell.py # Shell management / Shell 管理
|
|
377
|
+
│ ├── profile.py # C2 Profile management / C2 Profile 管理
|
|
378
|
+
│ └── database.py # Database operations / 数据库操作
|
|
379
|
+
├── utils/
|
|
380
|
+
│ ├── __init__.py
|
|
381
|
+
│ ├── godzilla_backend.py # Godzilla JAR integration / 哥斯拉 JAR 集成
|
|
382
|
+
│ └── repl_skin.py # REPL interface / REPL 界面
|
|
383
|
+
└── tests/
|
|
384
|
+
├── TEST.md # Test plan and results / 测试计划和结果
|
|
385
|
+
├── test_core.py # Unit tests / 单元测试
|
|
386
|
+
└── test_full_e2e.py # E2E tests / E2E 测试
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## License / 许可证
|
|
392
|
+
|
|
393
|
+
MIT License
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## Disclaimer / 免责声明
|
|
398
|
+
|
|
399
|
+
**English**: This tool is for authorized security testing and research purposes only. Unauthorized use is illegal.
|
|
400
|
+
|
|
401
|
+
**中文**: 本工具仅供安全研究和授权测试使用。使用本工具进行未经授权的测试是非法的。
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
cli-anything-godzilla: CLI harness for Godzilla WebShell Manager.
|
|
3
|
+
|
|
4
|
+
This package provides a stateful CLI interface to the Godzilla security testing tool.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
__version__ = "1.0.0"
|
|
8
|
+
__author__ = "cli-anything"
|
|
9
|
+
|
|
10
|
+
from cli_anything.godzilla.core.project import (
|
|
11
|
+
create_project,
|
|
12
|
+
open_project,
|
|
13
|
+
save_project,
|
|
14
|
+
close_project,
|
|
15
|
+
get_project_info,
|
|
16
|
+
list_projects,
|
|
17
|
+
)
|
|
18
|
+
from cli_anything.godzilla.core.shell import (
|
|
19
|
+
ShellEntity,
|
|
20
|
+
add_shell,
|
|
21
|
+
update_shell,
|
|
22
|
+
remove_shell,
|
|
23
|
+
list_shells,
|
|
24
|
+
get_shell,
|
|
25
|
+
test_shell,
|
|
26
|
+
)
|
|
27
|
+
from cli_anything.godzilla.core.profile import (
|
|
28
|
+
C2Profile,
|
|
29
|
+
load_profile,
|
|
30
|
+
save_profile,
|
|
31
|
+
list_profiles,
|
|
32
|
+
validate_profile,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
# Project management
|
|
37
|
+
"create_project",
|
|
38
|
+
"open_project",
|
|
39
|
+
"save_project",
|
|
40
|
+
"close_project",
|
|
41
|
+
"get_project_info",
|
|
42
|
+
"list_projects",
|
|
43
|
+
# Shell management
|
|
44
|
+
"ShellEntity",
|
|
45
|
+
"add_shell",
|
|
46
|
+
"update_shell",
|
|
47
|
+
"remove_shell",
|
|
48
|
+
"list_shells",
|
|
49
|
+
"get_shell",
|
|
50
|
+
"test_shell",
|
|
51
|
+
# Profile management
|
|
52
|
+
"C2Profile",
|
|
53
|
+
"load_profile",
|
|
54
|
+
"save_profile",
|
|
55
|
+
"list_profiles",
|
|
56
|
+
"validate_profile",
|
|
57
|
+
]
|
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
cli-anything-godzilla: CLI harness for Godzilla WebShell Manager.
|
|
4
|
+
|
|
5
|
+
A stateful CLI interface that allows AI agents to operate Godzilla
|
|
6
|
+
without needing a GUI.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
import json
|
|
11
|
+
import sys
|
|
12
|
+
import os
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Optional, Dict, List, Any
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
import yaml
|
|
18
|
+
except ImportError:
|
|
19
|
+
yaml = None
|
|
20
|
+
|
|
21
|
+
from cli_anything.godzilla.core.project import (
|
|
22
|
+
create_project,
|
|
23
|
+
open_project,
|
|
24
|
+
save_project,
|
|
25
|
+
close_project,
|
|
26
|
+
get_project_info,
|
|
27
|
+
list_projects,
|
|
28
|
+
get_current_project,
|
|
29
|
+
)
|
|
30
|
+
from cli_anything.godzilla.core.shell import (
|
|
31
|
+
add_shell,
|
|
32
|
+
update_shell,
|
|
33
|
+
remove_shell,
|
|
34
|
+
list_shells,
|
|
35
|
+
get_shell,
|
|
36
|
+
test_shell,
|
|
37
|
+
export_shells,
|
|
38
|
+
import_shells,
|
|
39
|
+
ShellEntity,
|
|
40
|
+
)
|
|
41
|
+
from cli_anything.godzilla.core.profile import (
|
|
42
|
+
load_profile,
|
|
43
|
+
list_profiles,
|
|
44
|
+
validate_profile,
|
|
45
|
+
C2Profile,
|
|
46
|
+
)
|
|
47
|
+
from cli_anything.godzilla.utils.repl_skin import ReplSkin
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Global context
|
|
51
|
+
@click.group(invoke_without_command=True)
|
|
52
|
+
@click.option("-p", "--project", "project_path", help="Path to project file")
|
|
53
|
+
@click.option("--jar", "--jar-path", "jar_path", help="Path to Godzilla JAR file")
|
|
54
|
+
@click.option("--json", "json_output", is_flag=True, help="Output in JSON format")
|
|
55
|
+
@click.pass_context
|
|
56
|
+
def cli(ctx, project_path: str, jar_path: str, json_output: bool):
|
|
57
|
+
"""Main CLI entry point."""
|
|
58
|
+
ctx.ensure_object(dict)
|
|
59
|
+
ctx.obj["project"] = project_path
|
|
60
|
+
ctx.obj["jar_path"] = jar_path
|
|
61
|
+
ctx.obj["json_flag"] = json_output
|
|
62
|
+
|
|
63
|
+
# Open project if path specified
|
|
64
|
+
if project_path:
|
|
65
|
+
try:
|
|
66
|
+
open_project(project_path)
|
|
67
|
+
except Exception as e:
|
|
68
|
+
click.echo(f"Error opening project: {e}", err=True)
|
|
69
|
+
|
|
70
|
+
# If no subcommand, enter REPL mode
|
|
71
|
+
if ctx.invoked_subcommand is None:
|
|
72
|
+
ctx.invoke(repl)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@cli.command()
|
|
76
|
+
def version():
|
|
77
|
+
"""Show version information."""
|
|
78
|
+
click.echo("cli-anything-godzilla v1.0.0")
|
|
79
|
+
click.echo("\033[36mA CLI harness for Godzilla Security Testing Tool\033[0m")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@cli.command()
|
|
83
|
+
def help_cmd():
|
|
84
|
+
"""Show comprehensive help."""
|
|
85
|
+
help_text = """
|
|
86
|
+
\033[36mcli-anything-godzilla\033[0m - CLI harness for Godzilla Security Testing Tool
|
|
87
|
+
|
|
88
|
+
\033[33mCommands:\033[0m
|
|
89
|
+
\033[32mproject\033[0m Project management (create, open, save, info)
|
|
90
|
+
\033[32mshell\033[0m Shell management (add, list, test, export, import)
|
|
91
|
+
\033[32mprofile\033[0m C2 Profile management (load, save, validate)
|
|
92
|
+
\033[32mrepl\033[0m Interactive REPL mode
|
|
93
|
+
\033[32mversion\033[0m Show version information
|
|
94
|
+
|
|
95
|
+
\033[33mExamples:\033[0m
|
|
96
|
+
# Create a new project
|
|
97
|
+
cli-anything-godzilla project new my-project
|
|
98
|
+
|
|
99
|
+
# Open existing project
|
|
100
|
+
cli-anything-godzilla project open ./project.json
|
|
101
|
+
|
|
102
|
+
# Add a shell interactively
|
|
103
|
+
cli-anything-godzilla
|
|
104
|
+
|
|
105
|
+
# List shells
|
|
106
|
+
cli-anything-godzilla shell list
|
|
107
|
+
|
|
108
|
+
\033[33mGlobal Options:\033[0m
|
|
109
|
+
-p, --project Path to project file
|
|
110
|
+
--jar Path to Godzilla JAR file
|
|
111
|
+
--json Output in JSON format
|
|
112
|
+
"""
|
|
113
|
+
click.echo(help_text)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# Project commands group
|
|
117
|
+
@cli.group("project")
|
|
118
|
+
def project_cli():
|
|
119
|
+
"""Project management commands."""
|
|
120
|
+
pass
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@project_cli.command("new")
|
|
124
|
+
@click.option("-n", "--name", required=True, help="Project name")
|
|
125
|
+
@click.option("-d", "--description", default="", help="Project description")
|
|
126
|
+
@click.option("-o", "--output", "output_path", help="Output directory path")
|
|
127
|
+
def project_new(name: str, description: str, output_path: Optional[str]):
|
|
128
|
+
"""Create a new project."""
|
|
129
|
+
try:
|
|
130
|
+
project = create_project(name=name, path=output_path, description=description)
|
|
131
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
132
|
+
skin.success(f"Created project: {name}")
|
|
133
|
+
skin.status("Path", str(project.project_path))
|
|
134
|
+
except Exception as e:
|
|
135
|
+
click.echo(f"Error: {e}", err=True)
|
|
136
|
+
sys.exit(1)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@project_cli.command("open")
|
|
140
|
+
@click.argument("path", required=True)
|
|
141
|
+
def project_open(path: str):
|
|
142
|
+
"""Open an existing project."""
|
|
143
|
+
try:
|
|
144
|
+
project = open_project(path)
|
|
145
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
146
|
+
skin.success(f"Opened project: {project.name}")
|
|
147
|
+
skin.status("Path", path)
|
|
148
|
+
except FileNotFoundError:
|
|
149
|
+
click.echo(f"Project not found: {path}", err=True)
|
|
150
|
+
sys.exit(1)
|
|
151
|
+
except Exception as e:
|
|
152
|
+
click.echo(f"Error: {e}", err=True)
|
|
153
|
+
sys.exit(1)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@project_cli.command("info")
|
|
157
|
+
@click.pass_context
|
|
158
|
+
def project_info(ctx):
|
|
159
|
+
"""Show current project information."""
|
|
160
|
+
project = get_current_project()
|
|
161
|
+
if not project:
|
|
162
|
+
click.echo("No project open. Use 'project open' first.")
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
info = get_project_info(project)
|
|
166
|
+
if ctx.obj.get("json_flag"):
|
|
167
|
+
click.echo(json.dumps(info, indent=2))
|
|
168
|
+
else:
|
|
169
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
170
|
+
skin.status("Name", info.get("name", "N/A"))
|
|
171
|
+
skin.status("Path", info.get("path", "N/A"))
|
|
172
|
+
skin.status("Shells", str(info.get("shell_count", 0)))
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@project_cli.command("list")
|
|
176
|
+
@click.pass_context
|
|
177
|
+
def project_list(ctx):
|
|
178
|
+
"""List all projects."""
|
|
179
|
+
projects = list_projects()
|
|
180
|
+
if ctx.obj.get("json_flag"):
|
|
181
|
+
click.echo(json.dumps(projects, indent=2))
|
|
182
|
+
else:
|
|
183
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
184
|
+
if not projects:
|
|
185
|
+
skin.info("No projects found")
|
|
186
|
+
return
|
|
187
|
+
for p in projects:
|
|
188
|
+
click.echo(f" {p['name']}: {p['path']}")
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@project_cli.command("close")
|
|
192
|
+
def project_close_cmd():
|
|
193
|
+
"""Close current project."""
|
|
194
|
+
project = get_current_project()
|
|
195
|
+
if not project:
|
|
196
|
+
click.echo("No project open.")
|
|
197
|
+
return
|
|
198
|
+
close_project(project)
|
|
199
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
200
|
+
skin.success("Project closed")
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
# Shell commands group
|
|
204
|
+
@cli.group("shell")
|
|
205
|
+
def shell_cli():
|
|
206
|
+
"""Shell management commands."""
|
|
207
|
+
pass
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@shell_cli.command("add")
|
|
211
|
+
@click.option("-u", "--url", required=True, help="Shell URL")
|
|
212
|
+
@click.option("-p", "--password", required=True, help="Shell password")
|
|
213
|
+
@click.option("-k", "--secret-key", default="", help="Secret key")
|
|
214
|
+
@click.option("--payload", default="JavaDynamicPayload", help="Payload type")
|
|
215
|
+
@click.option("--cryption", default="xor", help="Encryption method")
|
|
216
|
+
@click.option("--encoding", default="UTF-8", help="Character encoding")
|
|
217
|
+
@click.option("--remark", default="", help="Shell remark")
|
|
218
|
+
@click.pass_context
|
|
219
|
+
def shell_add(ctx, url: str, password: str, secret_key: str, payload: str, cryption: str, encoding: str, remark: str):
|
|
220
|
+
"""Add a new shell."""
|
|
221
|
+
project = get_current_project()
|
|
222
|
+
if not project:
|
|
223
|
+
click.echo("No project open. Use 'project open' first.", err=True)
|
|
224
|
+
sys.exit(1)
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
shell = add_shell(
|
|
228
|
+
url=url,
|
|
229
|
+
password=password,
|
|
230
|
+
secret_key=secret_key,
|
|
231
|
+
payload=payload,
|
|
232
|
+
cryption=cryption,
|
|
233
|
+
encoding=encoding,
|
|
234
|
+
remark=remark,
|
|
235
|
+
)
|
|
236
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
237
|
+
skin.success(f"Added shell: {shell.id}")
|
|
238
|
+
skin.status("URL", shell.url)
|
|
239
|
+
skin.status("Payload", shell.payload)
|
|
240
|
+
except Exception as e:
|
|
241
|
+
click.echo(f"Error: {e}", err=True)
|
|
242
|
+
sys.exit(1)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@shell_cli.command("list")
|
|
246
|
+
@click.pass_context
|
|
247
|
+
def shell_list(ctx):
|
|
248
|
+
"""List all shells."""
|
|
249
|
+
project = get_current_project()
|
|
250
|
+
if not project:
|
|
251
|
+
click.echo("No project open. Use 'project open' first.", err=True)
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
shells = list_shells()
|
|
255
|
+
if ctx.obj.get("json_flag"):
|
|
256
|
+
output = [s.to_dict() for s in shells]
|
|
257
|
+
click.echo(json.dumps(output, indent=2))
|
|
258
|
+
else:
|
|
259
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
260
|
+
if not shells:
|
|
261
|
+
skin.info("No shells configured")
|
|
262
|
+
return
|
|
263
|
+
for s in shells:
|
|
264
|
+
click.echo(f" {s.id[:8]}: {s.url} ({s.payload})")
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@shell_cli.command("get")
|
|
268
|
+
@click.argument("shell_id", required=True)
|
|
269
|
+
@click.pass_context
|
|
270
|
+
def shell_get(ctx, shell_id: str):
|
|
271
|
+
"""Get shell details."""
|
|
272
|
+
project = get_current_project()
|
|
273
|
+
if not project:
|
|
274
|
+
click.echo("No project open. Use 'project open' first.", err=True)
|
|
275
|
+
return
|
|
276
|
+
|
|
277
|
+
shell = get_shell(shell_id)
|
|
278
|
+
if not shell:
|
|
279
|
+
click.echo(f"Shell not found: {shell_id}", err=True)
|
|
280
|
+
return
|
|
281
|
+
|
|
282
|
+
if ctx.obj.get("json_flag"):
|
|
283
|
+
click.echo(json.dumps(shell.to_dict(), indent=2))
|
|
284
|
+
else:
|
|
285
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
286
|
+
skin.status("ID", shell.id)
|
|
287
|
+
skin.status("URL", shell.url)
|
|
288
|
+
skin.status("Payload", shell.payload)
|
|
289
|
+
skin.status("Cryption", shell.cryption)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
@shell_cli.command("update")
|
|
293
|
+
@click.argument("shell_id", required=True)
|
|
294
|
+
@click.option("--url", help="Update URL")
|
|
295
|
+
@click.option("--password", help="Update password")
|
|
296
|
+
@click.option("--remark", help="Update remark")
|
|
297
|
+
@click.pass_context
|
|
298
|
+
def shell_update(ctx, shell_id: str, url: Optional[str], password: Optional[str], remark: Optional[str]):
|
|
299
|
+
"""Update shell configuration."""
|
|
300
|
+
project = get_current_project()
|
|
301
|
+
if not project:
|
|
302
|
+
click.echo("No project open. Use 'project open' first.", err=True)
|
|
303
|
+
return
|
|
304
|
+
|
|
305
|
+
kwargs = {}
|
|
306
|
+
if url:
|
|
307
|
+
kwargs["url"] = url
|
|
308
|
+
if password:
|
|
309
|
+
kwargs["password"] = password
|
|
310
|
+
if remark:
|
|
311
|
+
kwargs["remark"] = remark
|
|
312
|
+
|
|
313
|
+
if not kwargs:
|
|
314
|
+
click.echo("No updates specified.")
|
|
315
|
+
return
|
|
316
|
+
|
|
317
|
+
success = update_shell(shell_id, **kwargs)
|
|
318
|
+
if success:
|
|
319
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
320
|
+
skin.success(f"Updated shell: {shell_id}")
|
|
321
|
+
else:
|
|
322
|
+
click.echo(f"Shell not found: {shell_id}", err=True)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
@shell_cli.command("remove")
|
|
326
|
+
@click.argument("shell_id", required=True)
|
|
327
|
+
@click.pass_context
|
|
328
|
+
def shell_remove(ctx, shell_id: str):
|
|
329
|
+
"""Remove a shell."""
|
|
330
|
+
project = get_current_project()
|
|
331
|
+
if not project:
|
|
332
|
+
click.echo("No project open. Use 'project open' first.", err=True)
|
|
333
|
+
return
|
|
334
|
+
|
|
335
|
+
success = remove_shell(shell_id)
|
|
336
|
+
if success:
|
|
337
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
338
|
+
skin.success(f"Removed shell: {shell_id}")
|
|
339
|
+
else:
|
|
340
|
+
click.echo(f"Shell not found: {shell_id}", err=True)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
@shell_cli.command("test")
|
|
344
|
+
@click.argument("shell_id", required=True)
|
|
345
|
+
@click.pass_context
|
|
346
|
+
def shell_test_cmd(ctx, shell_id: str):
|
|
347
|
+
"""Test shell connectivity."""
|
|
348
|
+
project = get_current_project()
|
|
349
|
+
if not project:
|
|
350
|
+
click.echo("No project open. Use 'project open' first.", err=True)
|
|
351
|
+
return
|
|
352
|
+
|
|
353
|
+
result = test_shell(shell_id)
|
|
354
|
+
if ctx.obj.get("json_flag"):
|
|
355
|
+
click.echo(json.dumps(result, indent=2))
|
|
356
|
+
else:
|
|
357
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
358
|
+
if result.get("success"):
|
|
359
|
+
skin.success("Shell connection successful")
|
|
360
|
+
else:
|
|
361
|
+
skin.error(f"Shell connection failed: {result.get('error')}")
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
@shell_cli.command("export")
|
|
365
|
+
@click.argument("output", required=True)
|
|
366
|
+
@click.option("-i", "--ids", help="Comma-separated shell IDs")
|
|
367
|
+
@click.pass_context
|
|
368
|
+
def shell_export(ctx, output: str, ids: Optional[str]):
|
|
369
|
+
"""Export shells to JSON file."""
|
|
370
|
+
project = get_current_project()
|
|
371
|
+
if not project:
|
|
372
|
+
click.echo("No project open. Use 'project open' first.", err=True)
|
|
373
|
+
return
|
|
374
|
+
|
|
375
|
+
shell_ids = ids.split(",") if ids else None
|
|
376
|
+
export_shells(output, shell_ids)
|
|
377
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
378
|
+
skin.success(f"Exported shells to {output}")
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
@shell_cli.command("import")
|
|
382
|
+
@click.argument("input_file", required=True)
|
|
383
|
+
@click.option("--overwrite", is_flag=True, help="Overwrite existing shells")
|
|
384
|
+
@click.pass_context
|
|
385
|
+
def shell_import(ctx, input_file: str, overwrite: bool):
|
|
386
|
+
"""Import shells from JSON file."""
|
|
387
|
+
project = get_current_project()
|
|
388
|
+
if not project:
|
|
389
|
+
click.echo("No project open. Use 'project open' first.", err=True)
|
|
390
|
+
return
|
|
391
|
+
|
|
392
|
+
count = import_shells(input_file, overwrite)
|
|
393
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
394
|
+
skin.success(f"Imported {count} shells")
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
# Profile commands group
|
|
398
|
+
@cli.group("profile")
|
|
399
|
+
def profile_cli():
|
|
400
|
+
"""C2 Profile management commands."""
|
|
401
|
+
pass
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
@profile_cli.command("list")
|
|
405
|
+
@click.pass_context
|
|
406
|
+
def profile_list(ctx):
|
|
407
|
+
"""List available C2 profiles."""
|
|
408
|
+
project = get_current_project()
|
|
409
|
+
profiles = []
|
|
410
|
+
|
|
411
|
+
if project and project.is_open:
|
|
412
|
+
profile_dir = Path(project.project_path) / "profile"
|
|
413
|
+
if profile_dir.exists():
|
|
414
|
+
for f in profile_dir.glob("*.profile"):
|
|
415
|
+
profiles.append({
|
|
416
|
+
"name": f.stem,
|
|
417
|
+
"path": str(f),
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
if ctx.obj.get("json_flag"):
|
|
421
|
+
click.echo(json.dumps(profiles, indent=2))
|
|
422
|
+
else:
|
|
423
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
424
|
+
if not profiles:
|
|
425
|
+
skin.info("No profiles found")
|
|
426
|
+
else:
|
|
427
|
+
for p in profiles:
|
|
428
|
+
click.echo(f" {p['name']}: {p['path']}")
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
@profile_cli.command("load")
|
|
432
|
+
@click.argument("path", required=True)
|
|
433
|
+
@click.pass_context
|
|
434
|
+
def profile_load(ctx, path: str):
|
|
435
|
+
"""Load a C2 profile from file."""
|
|
436
|
+
try:
|
|
437
|
+
profile = load_profile(path)
|
|
438
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
439
|
+
skin.success(f"Loaded profile: {profile.name}")
|
|
440
|
+
if ctx.obj.get("json_flag"):
|
|
441
|
+
click.echo(json.dumps(profile.to_dict(), indent=2))
|
|
442
|
+
except Exception as e:
|
|
443
|
+
click.echo(f"Error loading profile: {e}", err=True)
|
|
444
|
+
sys.exit(1)
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
@profile_cli.command("validate")
|
|
448
|
+
@click.argument("path", required=True)
|
|
449
|
+
@click.pass_context
|
|
450
|
+
def profile_validate(ctx, path: str):
|
|
451
|
+
"""Validate a C2 profile file."""
|
|
452
|
+
try:
|
|
453
|
+
with open(path, 'r') as f:
|
|
454
|
+
data = yaml.safe_load(f) if yaml else {}
|
|
455
|
+
errors = validate_profile(data)
|
|
456
|
+
if ctx.obj.get("json_flag"):
|
|
457
|
+
click.echo(json.dumps({"valid": len(errors) == 0, "errors": errors}, indent=2))
|
|
458
|
+
else:
|
|
459
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
460
|
+
if errors:
|
|
461
|
+
skin.error("Profile validation failed:")
|
|
462
|
+
for err in errors:
|
|
463
|
+
click.echo(f" - {err}")
|
|
464
|
+
else:
|
|
465
|
+
skin.success("Profile is valid")
|
|
466
|
+
except Exception as e:
|
|
467
|
+
click.echo(f"Error: {e}", err=True)
|
|
468
|
+
sys.exit(1)
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
# REPL command
|
|
472
|
+
@cli.command("repl")
|
|
473
|
+
@click.option("-p", "--project", "project_path", help="Path to project file")
|
|
474
|
+
@click.pass_context
|
|
475
|
+
def repl(ctx, project_path: Optional[str]):
|
|
476
|
+
"""Start interactive REPL mode."""
|
|
477
|
+
# Load project if specified
|
|
478
|
+
if project_path:
|
|
479
|
+
try:
|
|
480
|
+
open_project(project_path)
|
|
481
|
+
except Exception as e:
|
|
482
|
+
click.echo(f"Error opening project: {e}", err=True)
|
|
483
|
+
|
|
484
|
+
current_project = get_current_project()
|
|
485
|
+
skin = ReplSkin("godzilla", "1.0.0")
|
|
486
|
+
skin.print_banner()
|
|
487
|
+
|
|
488
|
+
if current_project:
|
|
489
|
+
skin.info(f"Project: {current_project.name}")
|
|
490
|
+
|
|
491
|
+
# Command registry for help
|
|
492
|
+
commands = {
|
|
493
|
+
"help": "Show this help",
|
|
494
|
+
"exit": "Exit REPL",
|
|
495
|
+
"project info": "Show project information",
|
|
496
|
+
"project list": "List all projects",
|
|
497
|
+
"shell list": "List all shells",
|
|
498
|
+
"shell get <id>": "Get shell details",
|
|
499
|
+
"shell add <url> <password>": "Add new shell",
|
|
500
|
+
"shell test <id>": "Test shell connectivity",
|
|
501
|
+
"profile list": "List C2 profiles",
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
skin.info("Type 'help' for available commands")
|
|
505
|
+
|
|
506
|
+
# Simple REPL loop
|
|
507
|
+
while True:
|
|
508
|
+
try:
|
|
509
|
+
line = input("godzilla> ")
|
|
510
|
+
if not line:
|
|
511
|
+
continue
|
|
512
|
+
|
|
513
|
+
line = line.strip()
|
|
514
|
+
if not line:
|
|
515
|
+
continue
|
|
516
|
+
|
|
517
|
+
# Handle commands
|
|
518
|
+
if line in ["exit", "quit", "q"]:
|
|
519
|
+
skin.print_goodbye()
|
|
520
|
+
break
|
|
521
|
+
elif line in ["help", "h", "?"]:
|
|
522
|
+
skin.help(commands)
|
|
523
|
+
elif line == "project info":
|
|
524
|
+
ctx.invoke(project_info)
|
|
525
|
+
elif line == "project list":
|
|
526
|
+
ctx.invoke(project_list)
|
|
527
|
+
elif line == "shell list":
|
|
528
|
+
ctx.invoke(shell_list)
|
|
529
|
+
elif line.startswith("shell get "):
|
|
530
|
+
# 支持 shell_id (支持短ID)
|
|
531
|
+
parts = line.split(maxsplit=2)
|
|
532
|
+
if len(parts) >= 3:
|
|
533
|
+
shell_id = parts[2].strip()
|
|
534
|
+
ctx.invoke(shell_get, shell_id=shell_id)
|
|
535
|
+
elif line.startswith("shell add "):
|
|
536
|
+
# Support url and password
|
|
537
|
+
parts = line.split(maxsplit=2)
|
|
538
|
+
if len(parts) >= 3:
|
|
539
|
+
url = parts[1].strip()
|
|
540
|
+
password = parts[2].strip()
|
|
541
|
+
ctx.invoke(shell_add, url=url, password=password)
|
|
542
|
+
elif line.startswith("shell test "):
|
|
543
|
+
# support shell_id (支持短ID)
|
|
544
|
+
parts = line.split(maxsplit=2)
|
|
545
|
+
if len(parts) >= 3:
|
|
546
|
+
shell_id = parts[2].strip()
|
|
547
|
+
ctx.invoke(shell_test_cmd, shell_id=shell_id)
|
|
548
|
+
elif line.startswith("shell update "):
|
|
549
|
+
# support shell update with short ID
|
|
550
|
+
parts = line.split(maxsplit=2)
|
|
551
|
+
if len(parts) >= 3:
|
|
552
|
+
shell_id = parts[2].strip()
|
|
553
|
+
# 简单的更新,只支持 shell update <id> --remark "xxx" 格式
|
|
554
|
+
if " --remark " in line:
|
|
555
|
+
remark_parts = line.split(" --remark ", 1)
|
|
556
|
+
remark = remark_parts[1].strip().strip('"')
|
|
557
|
+
ctx.invoke(shell_update, shell_id=shell_id, remark=remark)
|
|
558
|
+
elif line.startswith("shell remove "):
|
|
559
|
+
# support shell remove with short ID
|
|
560
|
+
parts = line.split(maxsplit=2)
|
|
561
|
+
if len(parts) >= 3:
|
|
562
|
+
shell_id = parts[2].strip()
|
|
563
|
+
ctx.invoke(shell_remove, shell_id=shell_id)
|
|
564
|
+
elif line == "profile list":
|
|
565
|
+
ctx.invoke(profile_list)
|
|
566
|
+
else:
|
|
567
|
+
skin.error(f"Unknown command: {line}")
|
|
568
|
+
skin.info("Type 'help' for available commands")
|
|
569
|
+
|
|
570
|
+
except KeyboardInterrupt:
|
|
571
|
+
skin.print_goodbye()
|
|
572
|
+
break
|
|
573
|
+
except Exception as e:
|
|
574
|
+
skin.error(f"Error: {e}")
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def main():
|
|
578
|
+
"""Entry point for CLI."""
|
|
579
|
+
cli()
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
if __name__ == "__main__":
|
|
583
|
+
main()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
cli_anything/godzilla/__init__.py
|
|
4
|
+
cli_anything/godzilla/godzilla_cli.py
|
|
5
|
+
cli_anything_godzilla.egg-info/PKG-INFO
|
|
6
|
+
cli_anything_godzilla.egg-info/SOURCES.txt
|
|
7
|
+
cli_anything_godzilla.egg-info/dependency_links.txt
|
|
8
|
+
cli_anything_godzilla.egg-info/entry_points.txt
|
|
9
|
+
cli_anything_godzilla.egg-info/requires.txt
|
|
10
|
+
cli_anything_godzilla.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cli_anything
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PyPI package configuration for cli-anything-godzilla.
|
|
3
|
+
|
|
4
|
+
This package provides a CLI harness for the Godzilla Security Testing Tool.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from setuptools import setup, find_namespace_packages
|
|
8
|
+
|
|
9
|
+
setup(
|
|
10
|
+
name="cli-anything-godzilla",
|
|
11
|
+
version="1.0.0",
|
|
12
|
+
packages=find_namespace_packages(include=["cli_anything.godzilla"]),
|
|
13
|
+
install_requires=[
|
|
14
|
+
"click>=8.0.0",
|
|
15
|
+
"prompt-toolkit>=3.0.0",
|
|
16
|
+
"pyyaml>=6.0.0",
|
|
17
|
+
],
|
|
18
|
+
entry_points={
|
|
19
|
+
"console_scripts": [
|
|
20
|
+
"cli-anything-godzilla=cli_anything.godzilla.godzilla_cli:main",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
python_requires=">=3.10",
|
|
24
|
+
)
|