Skip to content

Commit

Permalink
Merge branch '3543-wmi-hanging' into develop
Browse files Browse the repository at this point in the history
Issue #3543
PR #3588
  • Loading branch information
mssalvatore committed Aug 16, 2023
2 parents 134d6ae + d889638 commit 6ef4b8d
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 23 deletions.
29 changes: 29 additions & 0 deletions envs/monkey_zoo/packer/setup_mimikatz_15.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
---
- name: Create a mimikatz-15 machine image
hosts: all
become_method: runas
vars:
ansible_remote_tmp: C:\Windows\Temp
ansible_become_password: pAJfG56JX><
tasks:
- name: Create user
win_user:
Expand Down Expand Up @@ -33,6 +35,33 @@
win_command:
cmd: netsh advfirewall firewall add rule name="Allow Port 445" dir=in action=allow protocol=TCP localport=445

- name: Allow port 135 DCOM
win_command:
cmd: netsh advfirewall firewall add rule name="Allow Port 135" dir=in action=allow protocol=TCP localport=135

- name: Allow DCOM Connection
win_firewall_rule:
name: Allow DCOM Connection
localport: any
direction: in
program: C:\Windows\System32\svchost.exe
action: allow
state: present
enabled: yes

- name: Disable Windows Defender using registry
win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender
name: DisableAntiSpyware
data: 1
type: dword
state: present

- name: Disable Windows Defender
win_shell: Set-MpPreference -DisableIntrusionPreventionSystem $true -DisableIOAVProtection $true -DisableRealtimeMonitoring $true -EnableNetworkProtection AuditMode -Force
become: yes
become_user: m0nk3y

- name: Change the hostname to mimikatz-15
ansible.windows.win_hostname:
name: mimikatz-15
Expand Down
79 changes: 57 additions & 22 deletions monkey/agent_plugins/exploiters/wmi/src/wmi_client.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
from typing import Optional

from impacket.dcerpc.v5.dcom import wmi
Expand All @@ -8,6 +9,8 @@
from common.credentials import Credentials, LMHash, NTHash, Password
from infection_monkey.i_puppet import TargetHost

logger = logging.getLogger(__name__)


def secret_of_type(credentials, type) -> Optional[SecretStr]:
if type is Password and isinstance(credentials.secret, Password):
Expand All @@ -30,6 +33,7 @@ class WMIClient:
def __init__(self):
self._wbem_services: Optional[wmi.IWbemServices] = None
self._connected = False
self._dcom: Optional[DCOMConnection] = None

def connected(self) -> bool:
return self._connected
Expand All @@ -42,34 +46,41 @@ def login(self, host: TargetHost, credentials: Credentials):
:param credentials: Credentials to use
:raises Exception: If login fails
"""
# Impacket has a hard-coded timeout of 30 seconds
dcom = DCOMConnection(
str(host.ip),
username=credentials.identity.username,
password=get_plaintext(secret_of_type(credentials, Password)),
domain=str(host.ip),
lmhash=get_plaintext(secret_of_type(credentials, LMHash)),
nthash=get_plaintext(secret_of_type(credentials, NTHash)),
oxidResolver=True,
)

# Impacket has a hard-coded timeout of 120 seconds
try:
self._wbem_services = self._wbem_login(dcom)
except Exception as err:
dcom.disconnect()
raise err

self._connected = True

def _wbem_login(self, dcom: DCOMConnection) -> wmi.IWbemServices:
iface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login)
iWbemLevel1Login = wmi.IWbemLevel1Login(iface)
self._dcom = DCOMConnection(
str(host.ip),
username=credentials.identity.username, # type: ignore[union-attr]
password=get_plaintext(secret_of_type(credentials, Password)),
domain=str(host.ip),
lmhash=get_plaintext(secret_of_type(credentials, LMHash)),
nthash=get_plaintext(secret_of_type(credentials, NTHash)),
oxidResolver=True,
)
iInterface = self._dcom.CoCreateInstanceEx(
wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login
)
except Exception:
try:
self._dcom.disconnect() # type: ignore[union-attr]
except KeyError:
logger.exception("Disconnecting the DCOMConnection failed")

raise

iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)

try:
return iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL)
self._wbem_services = iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL)
except Exception:
self._dcom.disconnect()

raise
finally:
iWbemLevel1Login.RemRelease()

self._connected = True

def execute_remote_process(self, command, path) -> bool:
"""
Execute a process on the remote host
Expand All @@ -86,3 +97,27 @@ def execute_remote_process(self, command, path) -> bool:
# not need to use the dropper at all.
result = win32_process.Create(command, path, None)
return (result.ProcessId != 0) and (result.ReturnValue == 0)

def __del__(self):
if self._wbem_services:
self._wbem_services.RemRelease()
self._wbem_services = None

if self._dcom:
self._dcom.disconnect()
self._dcom = None
WMIClient._dcom_cleanup()

@staticmethod
def _dcom_cleanup():
for port_map in list(DCOMConnection.PORTMAPS.keys()):
del DCOMConnection.PORTMAPS[port_map]
for oid_set in list(DCOMConnection.OID_SET.keys()):
del DCOMConnection.OID_SET[oid_set]

DCOMConnection.OID_SET = {}
DCOMConnection.PORTMAPS = {}
if DCOMConnection.PINGTIMER:
DCOMConnection.PINGTIMER.cancel()
DCOMConnection.PINGTIMER.join()
DCOMConnection.PINGTIMER = None
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ def login(self, credentials: Credentials, tags: Set[AgentEventTag]):
tags.update(LOGIN_TAGS)

try:
self._wmi_client.login(self._host, credentials)
self._smb_client.login(credentials, tags)
self._wmi_client.login(self._host, credentials)
except Exception as err:
raise RemoteAuthenticationError from err

Expand Down

0 comments on commit 6ef4b8d

Please sign in to comment.