Skip to content

Commit a151a55

Browse files
committed
feat: 🎸 v0.3.0. Feature optimization
1 parent 1bb5a08 commit a151a55

File tree

3 files changed

+136
-23
lines changed

3 files changed

+136
-23
lines changed

‎README.md

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,36 @@ v0.2, 12/04/2023
55
**PentestGPT** is a penetration testing tool empowered by **ChatGPT**. It is designed to automate the penetration testing process. It is built on top of ChatGPT and operate in an interactive mode to guide penetration testers in both overall progress and specific operations.
66
A sample testing process of **PentestGPT** on a target VulnHub machine (Hackable II) is available at [here](./resources/PentestGPT_Hackable2.pdf).
77

8+
- Comparison to **Auto-GPT**.
9+
- Using [Auto-GPT](https://github.com/Torantulino/Auto-GPT) in security testing is good, but it is not optimized for security-related tasks.
10+
- **PentestGPT** is designed for penetration testing with a customized session interaction (see [here](./PentestGPT_design.md) for the detailed design).
11+
- Currently, **PentestGPT** does not rely on search engine. The "Google-enhanced" version of **PentestGPT** is under development.
812

913
## Contribute
10-
The project is still in its early stage. Feel free to raise any issues when using the tool.
14+
- The project is still in its early stage. Feel free to raise any issues when using the tool.
15+
- This project is for research purpose. Please contact me if you're interested in collaboration.
1116

1217
## Installation
1318
1. Install `requirements.txt` with `pip install -r requirements.txt`
14-
2. Install `chatgpt-wrapper` if you're non-plus members: `pip install git+https://github.com/mmabrouk/chatgpt-wrapper`. More details at: https://github.com/mmabrouk/chatgpt-wrapper. Note that the support for non-plus members are not optimized.
19+
2. (Deprecated: Will update support for non-plus member later.) ~~Install `chatgpt-wrapper` if you're non-plus members: `pip install git+https://github.com/mmabrouk/chatgpt-wrapper`. More details at: https://github.com/mmabrouk/chatgpt-wrapper. Note that the support for non-plus members are not optimized.~~
1520
3. Configure the keys in `config`. You may follow a sample by `cp config/chatgpt_config_sample.py. config/chatgpt_config.py`.
1621

1722

1823

1924
## Usage
2025
1. To start, run `python3 main.py`.
2126
2. The tool works similar to *msfconsole*. Follow the guidance to perform penetration testing.
22-
3. In general, PentestGPT intakes commands similar to chatGPT.
23-
- To intake multi-line inputs in the terminal, please use <Enter> for new line, and <Shift+Right-Arror> to submit the input.
24-
- The selection bar allows you to select a pre-defined options.
27+
3. In general, PentestGPT intakes commands similar to chatGPT. There are several basic commands.
28+
1. The commands are:
29+
- `help`: show the help message.
30+
- `next`: key in the test execution result and get the next step.
31+
- `more`: let **PentestGPT** to explain more details of the current step.
32+
- `todo`: show the todo list.
33+
- `discuss`: discuss with the **PentestGPT**.
34+
- `exit`: exit the tool.
35+
2. You can use <SHIFT + right arrow> to end your input (and <ENTER> is for next line).
36+
3. You may always use `TAB` to autocomplete the commands.
37+
4. When you're given a drop-down selection list, you can use cursor or arrow key to navigate the list. Press `ENTER` to select the item. Similarly, use <SHIFT + right arrow> to confirm selection.
2538

2639

2740
## Design Documentation
@@ -44,6 +57,9 @@ The handler is the main entry point of the penetration testing tool. It allows p
4457
3. Pass a human description.
4558

4659
## Update history
60+
### v0.3
61+
- Prompt usage optimization.
62+
- Documentation improvements.
4763
### v0.2
4864
- A major update to improve the terminal usage
4965
- Prompt optimization.

‎utils/pentest_gpt.py

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from prompts.prompt_class import PentestGPTPrompt
77
from utils.prompt_select import prompt_select, prompt_ask
88
from prompt_toolkit.formatted_text import HTML
9+
from utils.task_handler import main_task_entry, mainTaskCompleter
910

1011
import loguru
1112
import time, os, textwrap
@@ -47,6 +48,10 @@ def __init__(self):
4748
self.test_generation_session_id = None
4849
self.test_reasoning_session_id = None
4950
self.input_parsing_session_id = None
51+
self.chat_count = 0
52+
self.step_reasoning = (
53+
None # the response from the reasoning session for the current step
54+
)
5055

5156
def initialize(self):
5257
# initialize the backbone sessions and test the connection to chatGPT
@@ -122,17 +127,23 @@ def input_handler(self) -> str:
122127
response: str
123128
The response from the chatGPT model.
124129
"""
125-
request_option = prompt_select(
126-
title="> Please select your options with cursor: ",
127-
values=[
128-
("1", HTML('<style fg="cyan">Input test results</style>')),
129-
("2", HTML('<style fg="cyan">Ask for todos</style>')),
130-
("3", HTML('<style fg="cyan">Discuss with PentestGPT</style>')),
131-
("4", HTML('<style fg="cyan">Exit</style>')),
132-
],
133-
)
130+
self.chat_count += 1
131+
132+
request_option = main_task_entry()
133+
# request_option = prompt_select(
134+
# title=f"({self.chat_count}) > Please select your options with cursor: ",
135+
# values=[
136+
# ("1", HTML('<style fg="cyan">Input test results</style>')),
137+
# ("2", HTML('<style fg="cyan">Ask for todos</style>')),
138+
# ("3", HTML('<style fg="cyan">Discuss with PentestGPT</style>')),
139+
# ("4", HTML('<style fg="cyan">Exit</style>')),
140+
# ],
141+
# )
134142
# pass output
135-
if request_option == "1":
143+
if request_option == "help":
144+
print(mainTaskCompleter().task_details)
145+
146+
if request_option == "next":
136147
## (1) pass the information to input_parsing session.
137148
## Give a option list for user to choose from
138149
options = list(self.postfix_options.keys())
@@ -153,23 +164,39 @@ def input_handler(self) -> str:
153164
)
154165
## (2) pass the summarized information to the reasoning session.
155166
reasoning_response = self.reasoning_handler(parsed_input)
156-
## (3) pass the reasoning results to the test_generation session.
157-
generation_response = self.test_generation_handler(reasoning_response)
158-
## (4) print the results
167+
self.step_reasoning_response = reasoning_response
168+
169+
## (3) print the results
159170
self.console.print(
160171
"Based on the analysis, the following tasks are recommended:",
161172
style="bold green",
162173
)
163174
self.console.print(reasoning_response + "\n")
175+
response = reasoning_response
176+
177+
# generate more test details (beginner mode)
178+
elif request_option == "more":
179+
## (1) pass the reasoning results to the test_generation session.
180+
if self.step_reasoning_response is None:
181+
self.console.print(
182+
"You have not initialized the task yet. Please perform the basic testing following `next` option.",
183+
style="bold red",
184+
)
185+
return
186+
with self.console.status("[bold green] PentestGPT Thinking...") as status:
187+
generation_response = self.test_generation_handler(
188+
self.step_reasoning_response
189+
)
190+
164191
self.console.print(
165-
"You can follow the instructions below to complete the tasks.",
192+
"Below are the further details.",
166193
style="bold green",
167194
)
168195
self.console.print(generation_response + "\n")
169196
response = generation_response
170197

171-
# ask for sub tasks
172-
elif request_option == "2":
198+
# ask for task list (to-do list)
199+
elif request_option == "todo":
173200
## (1) ask the reasoning session to analyze the current situation, and list the top sub-tasks
174201
with self.console.status("[bold green] PentestGPT Thinking...") as status:
175202
reasoning_response = self.reasoning_handler(self.prompts.ask_todo)
@@ -190,7 +217,7 @@ def input_handler(self) -> str:
190217
response = reasoning_response
191218

192219
# pass other information, such as questions or some observations.
193-
elif request_option == "3":
220+
elif request_option == "discuss":
194221
## (1) Request for user multi-line input
195222
self.console.print("Please share your thoughts/questions with PentestGPT.")
196223
user_input = prompt_ask(
@@ -204,7 +231,7 @@ def input_handler(self) -> str:
204231
self.console.print(response + "\n", style="yellow")
205232

206233
# end
207-
elif request_option == "4":
234+
elif request_option == "quit":
208235
response = False
209236
self.console.print("Thank you for using PentestGPT!", style="bold green")
210237

@@ -249,6 +276,9 @@ def main(self):
249276
# 4. enter the main loop.
250277
while True:
251278
result = self.input_handler()
279+
self.console.print(
280+
"-----------------------------------------", style="bold white"
281+
)
252282
if not result: # end the session
253283
break
254284

‎utils/task_handler.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env python
2+
"""
3+
url: https://github.com/prompt-toolkit/python-prompt-toolkit/tree/master/examples/prompts/auto-completion
4+
Demonstration of a custom completer class and the possibility of styling
5+
completions independently by passing formatted text objects to the "display"
6+
and "display_meta" arguments of "Completion".
7+
"""
8+
from prompt_toolkit.completion import Completer, Completion
9+
from prompt_toolkit.formatted_text import HTML
10+
from prompt_toolkit.shortcuts import CompleteStyle, prompt
11+
12+
13+
class mainTaskCompleter(Completer):
14+
tasks = [
15+
"next",
16+
"more",
17+
"todo",
18+
"discuss",
19+
"help",
20+
"quit",
21+
]
22+
23+
task_meta = {
24+
"next": HTML("Go to the next step."),
25+
"more": HTML("Explain the task with more details."),
26+
"todo": HTML("Ask <b>PentestGPT</b> for todos."),
27+
"discuss": HTML("Discuss with <b>PentestGPT</b>."),
28+
"help": HTML("Show the help page."),
29+
"quit": HTML("End the current session."),
30+
}
31+
32+
task_details = """
33+
Below are the available tasks:
34+
- next: Continue to the next step by inputting the test results.
35+
- more: Explain the previous given task with more details.
36+
- todo: Ask PentestGPT for the task list and what to do next.
37+
- discuss: Discuss with PentestGPT. You can ask for help, discuss the task, or give any feedbacks.
38+
- help: Show this help page.
39+
- quit: End the current session."""
40+
41+
def get_completions(self, document, complete_event):
42+
word = document.get_word_before_cursor()
43+
for task in self.tasks:
44+
if task.startswith(word):
45+
yield Completion(
46+
task,
47+
start_position=-len(word),
48+
display=task,
49+
display_meta=self.task_meta.get(task),
50+
)
51+
52+
53+
def main_task_entry(text="> "):
54+
"""
55+
Entry point for the task prompt. Auto-complete
56+
"""
57+
task_completer = mainTaskCompleter()
58+
while True:
59+
result = prompt(text, completer=task_completer)
60+
if result not in task_completer.tasks:
61+
print("Invalid task, try again.")
62+
else:
63+
return result
64+
65+
66+
if __name__ == "__main__":
67+
main_task_entry()

0 commit comments

Comments
 (0)