|
| 1 | +import re |
| 2 | +from dataclasses import dataclass |
| 3 | +from typing import Tuple |
| 4 | + |
| 5 | +from invoke import Responder |
| 6 | + |
| 7 | +from utils import SSHConnection |
| 8 | +from .capability import Capability |
| 9 | + |
| 10 | + |
| 11 | +GOT_ROOT_REXEXPs = [ |
| 12 | + re.compile("^# $"), |
| 13 | + re.compile("^bash-[0-9]+.[0-9]# $") |
| 14 | +] |
| 15 | + |
| 16 | + |
| 17 | +@dataclass |
| 18 | +class SSHRunCommand(Capability): |
| 19 | + conn: SSHConnection |
| 20 | + |
| 21 | + def describe(self, name: str = None) -> str: |
| 22 | + return f"give a command to be executed on the shell and I will respond with the terminal output when running this command on the linux server. The given command must not require user interaction. Only state the to be executed command. The command should be used for enumeration or privilege escalation." |
| 23 | + |
| 24 | + def __call__(self, command: str) -> Tuple[str, bool]: |
| 25 | + got_root = False |
| 26 | + sudo_pass = Responder( |
| 27 | + pattern=r'\[sudo\] password for ' + self.conn.username + ':', |
| 28 | + response=self.conn.password + '\n', |
| 29 | + ) |
| 30 | + |
| 31 | + try: |
| 32 | + stdout, stderr, rc = self.conn.run(command, pty=True, warn=True, watchers=[sudo_pass], timeout=10) |
| 33 | + except Exception as e: |
| 34 | + print("TIMEOUT! Could we have become root?") |
| 35 | + stdout, stderr, rc = "", "", -1 |
| 36 | + tmp = "" |
| 37 | + last_line = "" |
| 38 | + for line in stdout.splitlines(): |
| 39 | + if not line.startswith('[sudo] password for ' + self.conn.username + ':'): |
| 40 | + last_line = line |
| 41 | + tmp = tmp + line |
| 42 | + |
| 43 | + # remove ansi shell codes |
| 44 | + ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') |
| 45 | + last_line = ansi_escape.sub('', last_line) |
| 46 | + |
| 47 | + for i in GOT_ROOT_REXEXPs: |
| 48 | + if i.fullmatch(last_line): |
| 49 | + got_root = True |
| 50 | + if last_line.startswith(f'root@{self.conn.hostname}:'): |
| 51 | + got_root = True |
| 52 | + return tmp, got_root |
0 commit comments