2020-04-28 19:30:18 +00:00
2017-10-25 02:08:19 +00:00
import requests
import logging
2020-04-28 19:30:18 +00:00
import configparser
2017-10-25 02:08:19 +00:00
from impacket . smbconnection import SMBConnection , SessionError
from cme . connection import *
from cme . helpers . logger import highlight
2021-11-20 21:37:14 +00:00
from cme . helpers . bloodhound import add_user_bh
2017-10-25 02:08:19 +00:00
from cme . logger import CMEAdapter
2020-04-28 19:30:18 +00:00
from io import StringIO
from pypsrp . client import Client
2017-10-25 02:08:19 +00:00
# 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 )
2020-04-28 11:24:01 +00:00
class SuppressFilter ( logging . Filter ) :
# remove warning https://github.com/diyan/pywinrm/issues/269
def filter ( self , record ) :
return ' wsman ' not in record . getMessage ( )
2017-10-25 02:08:19 +00:00
class winrm ( connection ) :
def __init__ ( self , args , db , host ) :
self . domain = None
2020-07-28 14:16:06 +00:00
self . server_os = None
2017-10-25 02:08:19 +00:00
connection . __init__ ( self , args , db , host )
@staticmethod
def proto_args ( parser , std_parser , module_parser ) :
winrm_parser = parser . add_parser ( ' winrm ' , help = " own stuff using WINRM " , parents = [ std_parser , module_parser ] )
2019-08-16 13:58:26 +00:00
winrm_parser . add_argument ( " -H " , ' --hash ' , metavar = " HASH " , dest = ' hash ' , nargs = ' + ' , default = [ ] , help = ' NTLM hash(es) or file(s) containing NTLM hashes ' )
2020-04-30 14:06:57 +00:00
winrm_parser . add_argument ( " --no-bruteforce " , action = ' store_true ' , help = ' No spray when using file for username and password (user1 => password1, user2 => password2 ' )
winrm_parser . add_argument ( " --continue-on-success " , action = ' store_true ' , help = " continues authentication attempts even after successes " )
2021-05-30 20:49:12 +00:00
winrm_parser . add_argument ( " --port " , type = int , default = 0 , help = " Custom WinRM port " )
2017-10-25 02:08:19 +00:00
dgroup = winrm_parser . add_mutually_exclusive_group ( )
dgroup . add_argument ( " -d " , metavar = " DOMAIN " , dest = ' domain ' , type = str , default = None , help = " domain to authenticate to " )
dgroup . add_argument ( " --local-auth " , action = ' store_true ' , help = ' authenticate locally to each target ' )
2020-04-30 14:06:57 +00:00
2017-10-25 02:08:19 +00:00
cgroup = winrm_parser . add_argument_group ( " Command Execution " , " Options for executing commands " )
cgroup . add_argument ( ' --no-output ' , action = ' store_true ' , help = ' do not retrieve command output ' )
cgroup . add_argument ( " -x " , metavar = " COMMAND " , dest = ' execute ' , help = " execute the specified command " )
cgroup . add_argument ( " -X " , metavar = " PS_COMMAND " , dest = ' ps_execute ' , help = ' execute the specified PowerShell command ' )
return parser
def proto_flow ( self ) :
self . proto_logger ( )
if self . create_conn_obj ( ) :
self . enum_host_info ( )
self . print_host_info ( )
if self . login ( ) :
if hasattr ( self . args , ' module ' ) and self . args . module :
self . call_modules ( )
else :
self . call_cmd_args ( )
def proto_logger ( self ) :
2021-10-16 19:37:06 +00:00
self . logger = CMEAdapter ( extra = { ' protocol ' : ' SMB ' ,
2017-10-25 02:08:19 +00:00
' host ' : self . host ,
' port ' : ' NONE ' ,
' hostname ' : ' NONE ' } )
def enum_host_info ( self ) :
2020-06-20 10:20:53 +00:00
# smb no open, specify the domain
2020-04-29 10:28:47 +00:00
if self . args . domain :
self . domain = self . args . domain
self . logger . extra [ ' hostname ' ] = self . hostname
else :
2017-10-25 02:08:19 +00:00
try :
2020-04-29 10:28:47 +00:00
smb_conn = SMBConnection ( self . host , self . host , None )
try :
smb_conn . login ( ' ' , ' ' )
except SessionError as e :
if " STATUS_ACCESS_DENIED " in e . message :
pass
2017-10-25 02:08:19 +00:00
2020-09-06 13:21:38 +00:00
self . domain = smb_conn . getServerDNSDomainName ( )
2020-04-29 10:28:47 +00:00
self . hostname = smb_conn . getServerName ( )
2020-06-20 10:20:53 +00:00
self . server_os = smb_conn . getServerOS ( )
2020-04-29 10:28:47 +00:00
self . logger . extra [ ' hostname ' ] = self . hostname
2017-10-25 02:08:19 +00:00
2020-04-29 10:28:47 +00:00
try :
smb_conn . logoff ( )
except :
pass
2017-10-25 02:08:19 +00:00
2020-04-29 10:28:47 +00:00
except Exception as e :
logging . debug ( " Error retrieving host domain: {} specify one manually with the ' -d ' flag " . format ( e ) )
2017-10-25 02:08:19 +00:00
2020-04-29 10:28:47 +00:00
if self . args . domain :
self . domain = self . args . domain
2017-10-25 02:08:19 +00:00
2020-04-29 10:28:47 +00:00
if self . args . local_auth :
self . domain = self . hostname
2017-10-25 02:08:19 +00:00
def print_host_info ( self ) :
2020-06-20 10:20:53 +00:00
if self . args . domain :
2021-10-16 19:37:06 +00:00
self . logger . extra [ ' protocol ' ] = " HTTP "
2020-06-20 10:20:53 +00:00
self . logger . info ( self . endpoint )
2021-10-16 19:37:06 +00:00
else :
self . logger . extra [ ' protocol ' ] = " SMB "
2020-06-20 10:20:53 +00:00
self . logger . info ( u " {} (name: {} ) (domain: {} ) " . format ( self . server_os ,
self . hostname ,
self . domain ) )
2021-10-16 19:37:06 +00:00
self . logger . extra [ ' protocol ' ] = " HTTP "
2020-06-20 10:20:53 +00:00
self . logger . info ( self . endpoint )
2021-10-16 19:37:06 +00:00
self . logger . extra [ ' protocol ' ] = " WINRM "
2020-06-20 10:20:53 +00:00
2017-10-25 02:08:19 +00:00
def create_conn_obj ( self ) :
2021-05-30 20:49:12 +00:00
2017-10-25 02:08:19 +00:00
endpoints = [
2021-05-30 20:49:12 +00:00
' 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 )
2017-10-25 02:08:19 +00:00
]
for url in endpoints :
try :
2020-07-30 13:14:31 +00:00
requests . get ( url , verify = False , timeout = 3 )
2017-10-25 02:08:19 +00:00
self . endpoint = url
if self . endpoint . startswith ( ' https:// ' ) :
2021-05-30 20:49:12 +00:00
self . port = self . args . port if self . args . port else 5986
2017-10-25 02:08:19 +00:00
else :
2021-05-30 20:49:12 +00:00
self . port = self . args . port if self . args . port else 5985
2017-10-25 02:08:19 +00:00
self . logger . extra [ ' port ' ] = self . port
return True
except Exception as e :
if ' Max retries exceeded with url ' not in str ( e ) :
logging . debug ( ' Error in WinRM create_conn_obj: ' + str ( e ) )
return False
def plaintext_login ( self , domain , username , password ) :
try :
2020-04-28 11:24:01 +00:00
from urllib3 . connectionpool import log
log . addFilter ( SuppressFilter ( ) )
2020-04-28 19:30:18 +00:00
self . conn = Client ( self . host ,
auth = ' ntlm ' ,
2021-11-09 12:19:06 +00:00
username = u ' {} \\ {} ' . format ( domain , username ) ,
2020-04-28 19:30:18 +00:00
password = password ,
ssl = False )
2017-10-25 02:08:19 +00:00
# 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)
2020-04-28 19:30:18 +00:00
self . conn . execute_ps ( " hostname " )
2017-10-25 02:08:19 +00:00
self . admin_privs = True
2019-11-10 23:12:35 +00:00
self . logger . success ( u ' {} \\ {} : {} {} ' . format ( self . domain ,
username ,
password ,
2018-03-01 19:36:17 +00:00
highlight ( ' ( {} ) ' . format ( self . config . get ( ' CME ' , ' pwn3d_label ' ) ) if self . admin_privs else ' ' ) ) )
2021-11-20 21:37:14 +00:00
add_user_bh ( self . username , self . domain , self . logger , self . config )
2020-04-30 14:06:57 +00:00
if not self . args . continue_on_success :
return True
2017-10-25 02:08:19 +00:00
except Exception as e :
2020-06-20 10:26:32 +00:00
if " with ntlm " in str ( e ) :
self . logger . error ( u ' {} \\ {} : {} ' . format ( self . domain ,
username ,
password ) )
else :
self . logger . error ( u ' {} \\ {} : {} " {} " ' . format ( self . domain ,
username ,
password ,
e ) )
2017-10-25 02:08:19 +00:00
return False
2020-06-22 10:25:00 +00:00
def hash_login ( self , domain , username , ntlm_hash ) :
try :
from urllib3 . connectionpool import log
log . addFilter ( SuppressFilter ( ) )
lmhash = ' 00000000000000000000000000000000: '
nthash = ' '
#This checks to see if we didn't provide the LM Hash
if ntlm_hash . find ( ' : ' ) != - 1 :
lmhash , nthash = ntlm_hash . split ( ' : ' )
else :
nthash = ntlm_hash
ntlm_hash = lmhash + nthash
self . hash = nthash
if lmhash : self . lmhash = lmhash
if nthash : self . nthash = nthash
self . conn = Client ( self . host ,
auth = ' ntlm ' ,
2021-11-09 12:19:06 +00:00
username = u ' {} \\ {} ' . format ( domain , username ) ,
2020-06-22 10:25:00 +00:00
password = ntlm_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 ,
username ,
self . hash ,
highlight ( ' ( {} ) ' . format ( self . config . get ( ' CME ' , ' pwn3d_label ' ) ) if self . admin_privs else ' ' ) ) )
2021-11-20 21:37:14 +00:00
add_user_bh ( self . username , self . domain , self . logger , self . config )
2020-06-22 10:25:00 +00:00
if not self . args . continue_on_success :
return True
except Exception as e :
if " with ntlm " in str ( e ) :
self . logger . error ( u ' {} \\ {} : {} ' . format ( self . domain ,
username ,
self . hash ) )
else :
self . logger . error ( u ' {} \\ {} : {} " {} " ' . format ( self . domain ,
username ,
self . hash ,
e ) )
return False
2017-10-25 02:08:19 +00:00
def execute ( self , payload = None , get_output = False ) :
2020-04-28 19:30:18 +00:00
try :
r = self . conn . execute_cmd ( self . args . execute )
except :
self . logger . debug ( ' Cannot execute cmd command, probably because user is not local admin, but powershell command should be ok ! ' )
r = self . conn . execute_ps ( self . args . execute )
2017-10-25 02:08:19 +00:00
self . logger . success ( ' Executed command ' )
2020-04-28 19:30:18 +00:00
self . logger . highlight ( r [ 0 ] )
2017-10-25 02:08:19 +00:00
def ps_execute ( self , payload = None , get_output = False ) :
2020-04-28 19:30:18 +00:00
r = self . conn . execute_ps ( self . args . ps_execute )
2017-10-25 02:08:19 +00:00
self . logger . success ( ' Executed command ' )
2020-04-28 19:30:18 +00:00
self . logger . highlight ( r [ 0 ] )