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
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
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 " )
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 ) :
self . logger = CMEAdapter ( extra = { ' protocol ' : ' WINRM ' ,
' host ' : self . host ,
' port ' : ' NONE ' ,
' hostname ' : ' NONE ' } )
def enum_host_info ( self ) :
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-04-29 10:28:47 +00:00
self . domain = smb_conn . getServerDomain ( )
self . hostname = smb_conn . getServerName ( )
2017-10-25 02:08:19 +00:00
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 ) :
self . logger . info ( self . endpoint )
def create_conn_obj ( self ) :
endpoints = [
' https:// {} :5986/wsman ' . format ( self . host ) ,
' http:// {} :5985/wsman ' . format ( self . host )
]
for url in endpoints :
try :
requests . get ( url , verify = False , timeout = 10 )
self . endpoint = url
if self . endpoint . startswith ( ' https:// ' ) :
self . port = 5986
else :
self . port = 5985
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 ' ,
username = username ,
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 ' ' ) ) )
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 :
2019-11-10 23:12:35 +00:00
self . logger . error ( u ' {} \\ {} : {} " {} " ' . format ( self . domain ,
username ,
password ,
2017-10-25 02:08:19 +00:00
e ) )
return False
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 ] )