Skip to content

Commit 5a363b1

Browse files
committed
feat(feat): some wizzards and some suggester \n\n Version: release/0.2.116 \n\n with love \n\n LazyOwn on HackTheBox: https://app.hackthebox.com/teams/overview/6429 \n\n LazyOwn/ https://grisuno.github.io/LazyOwn/ \n\n \n\n Fecha: jue 14 may 2026 21:48:55 -04 \n\n Hora: 1778809735
1 parent 901c973 commit 5a363b1

11 files changed

Lines changed: 2857 additions & 2126 deletions

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
# Changelog
33

44

5+
### Nuevas características
6+
7+
### Otros
8+
9+
* * feat(feat): some wizzards and some suggester \n\n Version: release/0.2.116 \n\n with love \n\n LazyOwn on HackTheBox: https://app.hackthebox.com/teams/overview/6429 \n\n LazyOwn/ https://grisuno.github.io/LazyOwn/ \n\n \n\n Fecha: jue 14 may 2026 21:48:55 -04 \n\n Hora: 1778809735
10+
11+
512
### Nuevas características
613

714
### Otros

COMMANDS.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,14 @@ Example:
200200
Fall through to the payload-aware completer for unhandled commands.
201201

202202
## preloop
203-
Print a session-start pro tip after the banner, once per session.
203+
Print a session-start pro tip and handle first-run setup.
204+
205+
If ``sessions/theone`` does not exist this is the operator's first
206+
launch. The shell will:
207+
1. Run ``config_banner`` so the operator can customise the prompt.
208+
2. Run ``wizard`` to populate the essential payload keys.
209+
3. Print first-step suggestions (ping → lazynmap).
210+
4. Create ``sessions/theone`` so subsequent launches skip setup.
204211

205212
## postloop
206213
Handle operations to perform after exiting the command loop.

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3083,7 +3083,14 @@ Example:
30833083
Fall through to the payload-aware completer for unhandled commands.
30843084

30853085
## preloop
3086-
Print a session-start pro tip after the banner, once per session.
3086+
Print a session-start pro tip and handle first-run setup.
3087+
3088+
If ``sessions/theone`` does not exist this is the operator's first
3089+
launch. The shell will:
3090+
1. Run ``config_banner`` so the operator can customise the prompt.
3091+
2. Run ``wizard`` to populate the essential payload keys.
3092+
3. Print first-step suggestions (ping → lazynmap).
3093+
4. Create ``sessions/theone`` so subsequent launches skip setup.
30873094

30883095
## postloop
30893096
Handle operations to perform after exiting the command loop.
@@ -12807,6 +12814,13 @@ No description available.
1280712814
# Changelog
1280812815

1280912816

12817+
### Nuevas características
12818+
12819+
### Otros
12820+
12821+
* * feat(feat): recomended commands and some love \n\n Version: release/0.2.115 \n\n \n\n LazyOwn on HackTheBox: https://app.hackthebox.com/teams/overview/6429 \n\n LazyOwn/ https://grisuno.github.io/LazyOwn/ \n\n \n\n Fecha: jue 14 may 2026 01:26:16 -04 \n\n Hora: 1778736376
12822+
12823+
1281012824
### Nuevas características
1281112825

1281212826
### Otros

cli/reactive_hints.py

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,45 @@
4646
}
4747
)
4848

49+
# Ordered kill-chain: after running X, suggest Y (phase-agnostic sensible defaults)
50+
_KILL_CHAIN_NEXT: dict[str, list[str]] = {
51+
"ping": ["lazynmap", "arpscan", "hosts_discovery"],
52+
"lazynmap": ["gobuster", "ffuf", "enum4linux", "searchsploit"],
53+
"rustscan": ["gobuster", "ffuf", "enum4linux", "searchsploit"],
54+
"nmap": ["gobuster", "ffuf", "enum4linux", "searchsploit"],
55+
"gobuster": ["ffuf", "nikto", "whatweb", "feroxbuster"],
56+
"ffuf": ["nikto", "whatweb", "burpsuite", "sqlmap"],
57+
"enum4linux": ["crackmapexec", "secretsdump", "kerbrute"],
58+
"crackmapexec": ["secretsdump", "evil-winrm", "psexec"],
59+
"secretsdump": ["evil-winrm", "psexec", "hashcat"],
60+
"linpeas": ["pspy64", "find_suid", "sudo_privesc"],
61+
"winpeas": ["printspoofer", "juicypotato", "whoami_priv"],
62+
"searchsploit": ["lazynmap", "gobuster", "exploit_db"],
63+
"kerbrute": ["GetNPUsers", "GetUserSPNs", "crackmapexec"],
64+
"nikto": ["sqlmap", "burpsuite", "ffuf"],
65+
"whatweb": ["gobuster", "nikto", "burpsuite"],
66+
"feroxbuster": ["ffuf", "nikto", "whatweb"],
67+
"sqlmap": ["burpsuite", "ffuf", "wfuzz"],
68+
"hashcat": ["evil-winrm", "ssh", "crackmapexec"],
69+
"john": ["evil-winrm", "ssh", "crackmapexec"],
70+
"evil-winrm": ["winpeas", "secretsdump", "mimikatz"],
71+
"ssh": ["linpeas", "pspy64", "sudo_privesc"],
72+
"ftp": ["gobuster", "enum4linux", "searchsploit"],
73+
"smb": ["enum4linux", "crackmapexec", "secretsdump"],
74+
"responder": ["crackmapexec", "hashcat", "secretsdump"],
75+
}
76+
77+
_PHASE_PRIORITY: dict[str, list[str]] = {
78+
"recon": ["ping", "lazynmap", "rustscan", "arpscan", "whois"],
79+
"enum": ["gobuster", "ffuf", "enum4linux", "nikto", "whatweb", "feroxbuster", "kerbrute"],
80+
"exploit": ["searchsploit", "crackmapexec", "sqlmap", "burpsuite", "evil-winrm"],
81+
"privesc": ["linpeas", "winpeas", "pspy64", "sudo_privesc", "printspoofer"],
82+
"lateral": ["crackmapexec", "evil-winrm", "chisel", "secretsdump", "psexec"],
83+
"cred": ["hashcat", "john", "responder", "kerbrute", "secretsdump"],
84+
"postexp": ["linpeas", "winpeas", "mimikatz", "secretsdump", "whoami_priv"],
85+
"exfil": ["download_c2", "nc", "curl", "scp", "rsync"],
86+
}
87+
4988
_MAX_LABEL_LEN: int = 24
5089
_HINT_CONSOLE: Console = Console(stderr=False, highlight=False, soft_wrap=True)
5190

@@ -118,4 +157,78 @@ def _render(labels: list[str]) -> None:
118157
_HINT_CONSOLE.print(hint)
119158

120159

121-
__all__ = ["SKIP_COMMANDS", "render_inline_hints"]
160+
def _read_run_commands(sessions_dir: str = "sessions") -> set[str]:
161+
"""Return the set of command names already executed this session."""
162+
import csv
163+
from pathlib import Path
164+
165+
path = Path(sessions_dir) / "LazyOwn_session_report.csv"
166+
seen: set[str] = set()
167+
if not path.exists():
168+
return seen
169+
try:
170+
with path.open("r", encoding="utf-8", errors="ignore") as fh:
171+
reader = csv.DictReader(fh)
172+
for row in reader:
173+
for col in ("tool", "command", "name"):
174+
val = (row.get(col) or "").strip().split()[0]
175+
if val:
176+
seen.add(val)
177+
break
178+
except Exception:
179+
pass
180+
return seen
181+
182+
183+
def render_command_hints(
184+
last_command: str,
185+
phase: str = "",
186+
sessions_dir: str = "sessions",
187+
limit: int = 3,
188+
enabled: bool = True,
189+
) -> None:
190+
"""Print phase-aware, history-filtered command hints after each step.
191+
192+
Uses kill-chain adjacency (``_KILL_CHAIN_NEXT``) first, then falls back
193+
to phase priority (``_PHASE_PRIORITY``). Commands already in the session
194+
CSV are skipped so the hint is always forward-looking.
195+
196+
Args:
197+
last_command: The command that just ran (first token used).
198+
phase: Current engagement phase (from payload.json / world_model).
199+
sessions_dir: Path to sessions/ directory.
200+
limit: Maximum labels to display.
201+
enabled: When False this is a no-op.
202+
203+
Returns:
204+
None — prints at most one dim line.
205+
"""
206+
if not enabled:
207+
return
208+
cmd = _first_token(last_command)
209+
if not cmd or cmd in SKIP_COMMANDS:
210+
return
211+
212+
already_run = _read_run_commands(sessions_dir)
213+
214+
# 1. Kill-chain adjacency: known follow-up for this specific command
215+
candidates: list[str] = [
216+
c for c in _KILL_CHAIN_NEXT.get(cmd, [])
217+
if c not in already_run
218+
]
219+
220+
# 2. Phase priority fallback
221+
if len(candidates) < limit:
222+
phase_key = phase.lower() if phase else "recon"
223+
for c in _PHASE_PRIORITY.get(phase_key, _PHASE_PRIORITY.get("recon", [])):
224+
if c not in already_run and c not in candidates and c != cmd:
225+
candidates.append(c)
226+
if len(candidates) >= limit * 2:
227+
break
228+
229+
labels = [_truncate(c, _MAX_LABEL_LEN) for c in candidates[:limit]]
230+
if labels:
231+
_render(labels)
232+
233+
234+
__all__ = ["SKIP_COMMANDS", "render_inline_hints", "render_command_hints"]

0 commit comments

Comments
 (0)