Merge pull request #1900 from guardicore/1763-fix-windows-exe-removal

This commit is contained in:
Mike Salvatore 2022-04-20 15:04:59 -04:00
commit d1ac07b7a4
3 changed files with 73 additions and 34 deletions

View File

@ -79,7 +79,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
script proxy execution PBA was disabled. #1864 script proxy execution PBA was disabled. #1864
- Unnecessary collection of kerberos credentials. #1771 - Unnecessary collection of kerberos credentials. #1771
- A bug where bogus users were collected by Mimikatz and added to the config. #1860 - A bug where bogus users were collected by Mimikatz and added to the config. #1860
- A bug where windows executable was not self deleting. #1763
### Security ### Security
- Change SSH exploiter so that it does not set the permissions of the agent - Change SSH exploiter so that it does not set the permissions of the agent

View File

@ -28,10 +28,6 @@ MONKEY_CMDLINE_DETACHED_WINDOWS = "%s start cmd /c %%(monkey_path)s %s" % (
CMD_PREFIX, CMD_PREFIX,
MONKEY_ARG, MONKEY_ARG,
) )
DELAY_DELETE_CMD = (
"cmd /c (for /l %%i in (1,0,2) do (ping -n 60 127.0.0.1 & del /f /q %(file_path)s & "
"if not exist %(file_path)s exit)) > NUL 2>&1 "
)
# Commands used for downloading monkeys # Commands used for downloading monkeys
POWERSHELL_HTTP_UPLOAD = ( POWERSHELL_HTTP_UPLOAD = (

View File

@ -3,6 +3,7 @@ import logging
import os import os
import subprocess import subprocess
import sys import sys
from pathlib import Path
from typing import List from typing import List
import infection_monkey.tunnel as tunnel import infection_monkey.tunnel as tunnel
@ -28,7 +29,7 @@ from infection_monkey.exploit.zerologon import ZerologonExploiter
from infection_monkey.i_puppet import IPuppet, PluginType from infection_monkey.i_puppet import IPuppet, PluginType
from infection_monkey.master import AutomatedMaster from infection_monkey.master import AutomatedMaster
from infection_monkey.master.control_channel import ControlChannel from infection_monkey.master.control_channel import ControlChannel
from infection_monkey.model import DELAY_DELETE_CMD, VictimHostFactory from infection_monkey.model import VictimHostFactory
from infection_monkey.network import NetworkInterface from infection_monkey.network import NetworkInterface
from infection_monkey.network.firewall import app as firewall from infection_monkey.network.firewall import app as firewall
from infection_monkey.network.info import get_local_network_interfaces from infection_monkey.network.info import get_local_network_interfaces
@ -401,35 +402,77 @@ class InfectionMonkey:
@staticmethod @staticmethod
def _self_delete() -> bool: def _self_delete() -> bool:
InfectionMonkey._remove_monkey_dir()
if "python" in Path(sys.executable).name:
return False
try:
if "win32" == sys.platform:
InfectionMonkey._self_delete_windows()
else:
InfectionMonkey._self_delete_linux()
T1107Telem(ScanStatus.USED, sys.executable).send()
return True
except Exception as exc:
logger.error("Exception in self delete: %s", exc)
T1107Telem(ScanStatus.SCANNED, sys.executable).send()
return False
@staticmethod
def _remove_monkey_dir():
status = ScanStatus.USED if remove_monkey_dir() else ScanStatus.SCANNED status = ScanStatus.USED if remove_monkey_dir() else ScanStatus.SCANNED
T1107Telem(status, get_monkey_dir_path()).send() T1107Telem(status, get_monkey_dir_path()).send()
deleted = False
if -1 == sys.executable.find("python"): @staticmethod
try: def _self_delete_windows():
status = None delay_delete_cmd = InfectionMonkey._build_windows_delete_command()
if "win32" == sys.platform: startupinfo = InfectionMonkey._get_startup_info()
from subprocess import CREATE_NEW_CONSOLE, STARTF_USESHOWWINDOW, SW_HIDE
startupinfo = subprocess.STARTUPINFO() subprocess.Popen(
startupinfo.dwFlags = CREATE_NEW_CONSOLE | STARTF_USESHOWWINDOW delay_delete_cmd,
startupinfo.wShowWindow = SW_HIDE stdin=None,
subprocess.Popen( stdout=None,
DELAY_DELETE_CMD % {"file_path": sys.executable}, stderr=None,
stdin=None, close_fds=True,
stdout=None, startupinfo=startupinfo,
stderr=None, )
close_fds=True,
startupinfo=startupinfo, @staticmethod
) def _build_windows_delete_command() -> str:
deleted = True agent_pid = os.getpid()
else: agent_file_path = sys.executable
os.remove(sys.executable)
status = ScanStatus.USED # Returns 1 if the process is running and 0 otherwise
deleted = True check_running_agent_cmd = f'tasklist /fi "PID eq {agent_pid}" ^| find /C "{agent_pid}"'
except Exception as exc:
logger.error("Exception in self delete: %s", exc) sleep_seconds = 5
status = ScanStatus.SCANNED delete_file_and_exit_cmd = f"del /f /q {agent_file_path} & exit"
if status:
T1107Telem(status, sys.executable).send() # Checks if the agent process is still running.
return deleted # If the agent is still running, it sleeps for 'sleep_seconds' before checking again.
# If the agent is not running, it deletes the executable and exits the loop.
# The check runs up to 20 times to give the agent ample time to shutdown.
delete_agent_cmd = (
f'cmd /c (for /l %i in (1,1,20) do (for /F "delims=" %j IN '
f'(\'{check_running_agent_cmd}\') DO if "%j"=="1" (timeout {sleep_seconds}) else '
f"({delete_file_and_exit_cmd})) ) > NUL 2>&1"
)
return delete_agent_cmd
@staticmethod
def _get_startup_info():
from subprocess import CREATE_NEW_CONSOLE, STARTF_USESHOWWINDOW, SW_HIDE
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags = CREATE_NEW_CONSOLE | STARTF_USESHOWWINDOW
startupinfo.wShowWindow = SW_HIDE
return startupinfo
@staticmethod
def _self_delete_linux():
os.remove(sys.executable)