Skip to content

Commit 40442a4

Browse files
feat: initial access check (#104)
* feat: enhance command state classification for initial access detection * fix: improve prompt clarity for initial access detection * docs: update graph visualization * feat: enhance command output classification with detailed priority order for initial access detection * fix: clarify command state classification rules and enforce error handling for unknown states * docs: update graph visualization * fix: improve prompt clarity in command state classifier by formatting multiline instructions * docs: update graph visualization --------- Co-authored-by: GitHub Action <action@github.com>
1 parent d39af7c commit 40442a4

File tree

4 files changed

+91
-21
lines changed

4 files changed

+91
-21
lines changed

wish-command-generation-api/docs/graph.svg

Lines changed: 9 additions & 9 deletions
Loading

wish-log-analysis-api/docs/graph.svg

Lines changed: 4 additions & 4 deletions
Loading

wish-log-analysis-api/src/wish_log_analysis_api/nodes/command_state_classifier.py

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,77 @@
1212

1313
# Define the prompt template
1414
COMMAND_STATE_CLASSIFIER_PROMPT = """
15-
As a system operations analyst, your role is to analyze command outputs and report the results.
16-
Follow these specific steps:
15+
As a security operations analyst, your task is to determine if a command output indicates successful
16+
initial access to a target system.
17+
18+
# PRIORITY ORDER FOR CLASSIFICATION:
19+
20+
1. FIRST: Check for Initial Access Success
21+
- If ANY initial access indicators are found, output "SUCCESS_INITIAL_ACCESS" regardless of exit_code
22+
- This takes absolute precedence over all other classifications
23+
24+
2. SECOND: Check for Normal Success
25+
- Only if NO initial access indicators were found AND exit_code is "0", output "SUCCESS"
26+
- Even if exit_code is 0, do not output "SUCCESS" if there are initial access indicators
27+
(use "SUCCESS_INITIAL_ACCESS" instead)
28+
29+
3. THIRD: Check for Specific Error Types
30+
- Only if neither of the above conditions are met
31+
32+
# MOST IMPORTANT RULE: Check for Initial Access Success REGARDLESS of exit_code
33+
34+
Even if the command timed out (exit_code 124) or had any other error, FIRST check if there are ANY signs
35+
of successful initial access in the output.
36+
37+
# FIRST PRIORITY: Check for Initial Access Success
38+
39+
Before any other analysis, check if the command output indicates successful initial access to the target system.
40+
Output "SUCCESS_INITIAL_ACCESS" if ANY of the following indicators are present:
41+
42+
## 1. Meterpreter or shell session establishment (HIGHEST PRIORITY)
43+
- ANY line containing "Meterpreter session" AND "opened" (This is the strongest indicator)
44+
- ANY line containing "Session" AND "created"
45+
- ANY line containing "Command shell session" AND "opened"
46+
- ANY line containing "WIN" surrounded by special characters (like =-=-=WIN=-=-=)
47+
- "Successful connection established"
48+
- "Successfully opened reverse shell"
49+
50+
## 2. Successful remote command execution proving access
51+
- Evidence of successful `whoami` execution on target
52+
- Evidence of successful `id` execution on target
53+
- Evidence of successful `hostname` execution on target
54+
- Evidence of successful `ipconfig`/`ifconfig` execution on target
55+
- Evidence of successful `ls`/`dir` execution on target
56+
57+
## 3. Explicit access confirmation
58+
- "Access gained to target system"
59+
- "Successfully compromised target"
60+
- "Initial foothold established"
61+
- "Initial access achieved"
62+
- "Successfully exploited vulnerability"
63+
64+
# IMPORTANT: The exit_code does NOT override initial access indicators
65+
If ANY of the above indicators are found, output "SUCCESS_INITIAL_ACCESS" regardless of the exit_code.
66+
This includes cases where the command timed out (exit_code 124) but still managed to establish a session.
67+
68+
# SECOND PRIORITY: Standard Command State Analysis
69+
70+
Only if NONE of the above initial access indicators are found, proceed with standard command state analysis:
1771
1872
1. If the `exit_code` is "0", output "SUCCESS" and end.
73+
- This includes successful port scans that found open ports
74+
- This includes successful reconnaissance commands
75+
- This includes ANY command that completed normally with exit_code 0
76+
1977
2. Otherwise, check the command output from `stdout` and `stderr`. Then choose the most appropriate
20-
error code from the following:
78+
code from the following:
2179
- TIMEOUT: When command execution times out or when the output indicates a timeout occurred.
2280
Look for indicators such as:
2381
* Messages containing phrases like "timeout", "timed out", "Read timeout expired"
2482
* Messages containing "connection timeout" or similar connection-related timeout phrases
2583
* Log entries indicating that a command was terminated due to exceeding time limits
2684
* Warning messages about waiting too long for command completion
27-
* `exit_code` is "-1" (reserved for timeout)
85+
* `exit_code` is "124" or "-1" (reserved for timeout)
2886
- COMMAND_NOT_FOUND: When the command is not found on the local machine
2987
- FILE_NOT_FOUND: When a local file referenced in the command is not found (excluding remote files like smb)
3088
- REMOTE_OPERATION_FAILED: When an operation on a remote machine (e.g., file reference, command execution) fails
@@ -33,8 +91,11 @@
3391
3492
3. Output the selected error code and end.
3593
36-
Note that OTHERS should only be used when the error does not fit any of the above categories
37-
and there are no success indicators in the output.
94+
# NOTE
95+
96+
- SUCCESS_INITIAL_ACCESS takes precedence over all other states, including SUCCESS and TIMEOUT.
97+
OTHERS is the last resort.
98+
- Output only the classification string, without any extra characters.
3899
39100
# command
40101
{command}
@@ -99,7 +160,9 @@ def classify_command_state(state: GraphState, settings_obj: Settings) -> GraphSt
99160
).strip()
100161

101162
# Convert the classification string to CommandState
102-
if classification_str == "SUCCESS":
163+
if classification_str == "SUCCESS_INITIAL_ACCESS":
164+
command_state = CommandState.SUCCESS_INITIAL_ACCESS
165+
elif classification_str == "SUCCESS":
103166
command_state = CommandState.SUCCESS
104167
elif classification_str == "COMMAND_NOT_FOUND":
105168
command_state = CommandState.COMMAND_NOT_FOUND
@@ -111,8 +174,10 @@ def classify_command_state(state: GraphState, settings_obj: Settings) -> GraphSt
111174
command_state = CommandState.TIMEOUT
112175
elif classification_str == "NETWORK_ERROR":
113176
command_state = CommandState.NETWORK_ERROR
114-
else:
177+
elif classification_str == "OTHERS":
115178
command_state = CommandState.OTHERS
179+
else:
180+
raise ValueError(f"Unknown command state classification: {classification_str}")
116181

117182
# Set the command state in the new state
118183
new_state.command_state = command_state

wish-models/src/wish_models/command_result/command_state.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ class CommandState(str, Enum):
77
DOING = "DOING"
88
"""The command is being executed."""
99

10+
SUCCESS_INITIAL_ACCESS = "SUCCESS_INITIAL_ACCESS"
11+
"""The command succeeded with initial access to the target system.
12+
13+
Examples include establishing a Meterpreter session or getting a shell."""
14+
1015
SUCCESS = "SUCCESS"
1116
"""The command succeeded, with meaningful insights."""
1217

0 commit comments

Comments
 (0)