Merge pull request #1841 from guardicore/1650-shell-startup-modification

Agent: Add timeouts in shell startup modification PBA's
This commit is contained in:
Mike Salvatore 2022-04-01 07:22:28 -04:00 committed by GitHub
commit 649404d50f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 30 deletions

View File

@ -2,6 +2,7 @@ import subprocess
from typing import Dict from typing import Dict
from common.common_consts.post_breach_consts import POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION from common.common_consts.post_breach_consts import POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
from infection_monkey.i_puppet.i_puppet import PostBreachData from infection_monkey.i_puppet.i_puppet import PostBreachData
from infection_monkey.post_breach.pba import PBA from infection_monkey.post_breach.pba import PBA
from infection_monkey.post_breach.shell_startup_files.shell_startup_files_modification import ( from infection_monkey.post_breach.shell_startup_files.shell_startup_files_modification import (
@ -21,7 +22,7 @@ class ModifyShellStartupFiles(PBA):
super().__init__(telemetry_messenger, name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION) super().__init__(telemetry_messenger, name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION)
def run(self, options: Dict): def run(self, options: Dict):
results = [pba.run() for pba in self.modify_shell_startup_PBA_list()] results = [pba.run(options) for pba in self.modify_shell_startup_PBA_list()]
if not results: if not results:
results = [ results = [
( (
@ -70,14 +71,19 @@ class ModifyShellStartupFiles(PBA):
windows_cmd=windows_cmds, windows_cmd=windows_cmds,
) )
def run(self): def run(self, options):
if self.command: if self.command:
try: try:
output = subprocess.check_output( # noqa: DUO116 output = subprocess.check_output( # noqa: DUO116
self.command, stderr=subprocess.STDOUT, shell=True self.command,
stderr=subprocess.STDOUT,
shell=True,
timeout=LONG_REQUEST_TIMEOUT,
).decode() ).decode()
return output, True return output, True
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as err:
# Return error output of the command # Return error output of the command
return e.output.decode(), False return str(err), False
except subprocess.TimeoutExpired as err:
return str(err), False

View File

@ -1,26 +1,37 @@
import logging
import subprocess import subprocess
from common.common_consts.timeouts import MEDIUM_REQUEST_TIMEOUT
from infection_monkey.utils.environment import is_windows_os from infection_monkey.utils.environment import is_windows_os
logger = logging.getLogger(__name__)
def get_linux_commands_to_modify_shell_startup_files(): def get_linux_commands_to_modify_shell_startup_files():
if is_windows_os(): if is_windows_os():
return "", [], [] return "", [], []
HOME_DIR = "/home/" home_dir = "/home/"
command = "cut -d: -f1,3 /etc/passwd | egrep ':[0-9]{4}$' | cut -d: -f1"
# get list of usernames # get list of usernames
USERS = ( try:
users = (
subprocess.check_output( # noqa: DUO116 subprocess.check_output( # noqa: DUO116
"cut -d: -f1,3 /etc/passwd | egrep ':[0-9]{4}$' | cut -d: -f1", shell=True command,
shell=True,
timeout=MEDIUM_REQUEST_TIMEOUT,
) )
.decode() .decode()
.split("\n")[:-1] .split("\n")[:-1]
) )
except subprocess.TimeoutExpired:
logger.error(f"Command {command} timed out")
return "", [], []
# get list of paths of different shell startup files with place for username # get list of paths of different shell startup files with place for username
STARTUP_FILES = [ startup_files = [
file_path.format(HOME_DIR) file_path.format(home_dir)
for file_path in [ for file_path in [
"{0}{{0}}/.profile", # bash, dash, ksh, sh "{0}{{0}}/.profile", # bash, dash, ksh, sh
"{0}{{0}}/.bashrc", # bash "{0}{{0}}/.bashrc", # bash
@ -42,6 +53,6 @@ def get_linux_commands_to_modify_shell_startup_files():
"tee -a {0} &&", # append to file "tee -a {0} &&", # append to file
"sed -i '$d' {0}", # remove last line of file (undo changes) "sed -i '$d' {0}", # remove last line of file (undo changes)
], ],
STARTUP_FILES, startup_files,
USERS, users,
) )

View File

@ -1,36 +1,47 @@
import logging
import subprocess import subprocess
from pathlib import Path from pathlib import Path
from common.common_consts.timeouts import MEDIUM_REQUEST_TIMEOUT
from infection_monkey.utils.environment import is_windows_os from infection_monkey.utils.environment import is_windows_os
MODIFY_POWERSHELL_STARTUP_SCRIPT = Path(__file__).parent / "modify_powershell_startup_file.ps1" MODIFY_POWERSHELL_STARTUP_SCRIPT = Path(__file__).parent / "modify_powershell_startup_file.ps1"
logger = logging.getLogger(__name__)
def get_windows_commands_to_modify_shell_startup_files(): def get_windows_commands_to_modify_shell_startup_files():
if not is_windows_os(): if not is_windows_os():
return "", [] return "", []
# get powershell startup file path # get powershell startup file path
SHELL_STARTUP_FILE = subprocess.check_output("powershell $Profile").decode().split("\r\n")[0] shell_startup_file = subprocess.check_output("powershell $Profile").decode().split("\r\n")[0]
SHELL_STARTUP_FILE_PATH_COMPONENTS = SHELL_STARTUP_FILE.split("\\") shell_startup_file_path_components = shell_startup_file.split("\\")
# get list of usernames # get list of usernames
USERS = ( command = "dir C:\\Users /b"
subprocess.check_output("dir C:\\Users /b", shell=True) # noqa: DUO116 try:
users = (
subprocess.check_output( # noqa: DUO116
command, shell=True, timeout=MEDIUM_REQUEST_TIMEOUT
)
.decode() .decode()
.split("\r\n")[:-1] .split("\r\n")[:-1]
) )
USERS.remove("Public") users.remove("Public")
except subprocess.TimeoutExpired:
logger.error(f"Command {command} timed out")
return "", []
STARTUP_FILES_PER_USER = [ startup_files_per_user = [
"\\".join( "\\".join(
SHELL_STARTUP_FILE_PATH_COMPONENTS[:2] + [user] + SHELL_STARTUP_FILE_PATH_COMPONENTS[3:] shell_startup_file_path_components[:2] + [user] + shell_startup_file_path_components[3:]
) )
for user in USERS for user in users
] ]
return [ return [
"powershell.exe", "powershell.exe",
str(MODIFY_POWERSHELL_STARTUP_SCRIPT), str(MODIFY_POWERSHELL_STARTUP_SCRIPT),
"-startup_file_path {0}", "-startup_file_path {0}",
], STARTUP_FILES_PER_USER ], startup_files_per_user