11import os
2+ import base64
23import requests
34import urllib3
4- import contextlib
55import logging
66import xml .etree .ElementTree as ET
77
1010from pypsrp .wsman import NAMESPACES
1111from pypsrp .client import Client
1212
13- from impacket .smbconnection import SMBConnection
1413from impacket .examples .secretsdump import LocalOperations , LSASecrets , SAMHashes
1514
1615from nxc .config import process_secret
1716from nxc .connection import connection
1817from nxc .helpers .bloodhound import add_user_bh
1918from nxc .helpers .misc import gen_random_string
19+ from nxc .helpers .ntlm_parser import parse_challenge
2020from nxc .logger import NXCAdapter
2121
2222
@@ -33,58 +33,33 @@ def __init__(self, args, db, host):
3333 self .lmhash = ""
3434 self .nthash = ""
3535 self .ssl = False
36- self .auth_type = None
36+ self .challenge_header = None
3737
3838 connection .__init__ (self , args , db , host )
3939
4040 def proto_logger (self ):
41- # Reason why default is SMB/445, because default is enumerate over SMB.
42- # For more details, please check the function "print_host_info"
41+ # For more details, please check the function "print_host_info"
4342 logging .getLogger ("pypsrp" ).disabled = True
4443 logging .getLogger ("pypsrp.wsman" ).disabled = True
4544 self .logger = NXCAdapter (
4645 extra = {
47- "protocol" : "SMB " ,
46+ "protocol" : "WINRM " ,
4847 "host" : self .host ,
49- "port" : "445 " ,
48+ "port" : "5985 " ,
5049 "hostname" : self .hostname ,
5150 }
5251 )
5352
5453 def enum_host_info (self ):
55- # smb no open, specify the domain
56- if self .args .no_smb :
57- self .domain = self .args .domain
58- else :
59- try :
60- smb_conn = SMBConnection (self .host , self .host , None , timeout = 5 )
61- no_ntlm = False
62- except Exception as e :
63- self .logger .fail (f"Error retrieving host domain: { e } specify one manually with the '-d' flag" )
64- else :
65- try :
66- smb_conn .login ("" , "" )
67- except BrokenPipeError :
68- self .logger .fail ("Broken Pipe Error while attempting to login" )
69- except Exception as e :
70- if "STATUS_NOT_SUPPORTED" in str (e ):
71- # no ntlm supported
72- no_ntlm = True
73-
74- self .domain = smb_conn .getServerDNSDomainName () if not no_ntlm else self .args .domain
75- self .hostname = smb_conn .getServerName () if not no_ntlm else self .host
76- self .server_os = smb_conn .getServerOS ()
77- if isinstance (self .server_os .lower (), bytes ):
78- self .server_os = self .server_os .decode ("utf-8" )
54+ ntlm_info = parse_challenge (base64 .b64decode (self .challenge_header .split (" " )[1 ].replace ("," , "" )))
55+ self .domain = ntlm_info ["target_info" ]["MsvAvDnsDomainName" ]
56+ self .hostname = ntlm_info ["target_info" ]["MsvAvNbComputerName" ]
57+ self .server_os = ntlm_info ["version" ]
58+ self .logger .extra ["hostname" ] = self .hostname
7959
80- self .logger . extra [ "hostname" ] = self .hostname
60+ self .output_filename = os . path . expanduser ( f"~/.nxc/logs/ { self .hostname } _ { self . host } _ { datetime . now (). strftime ( '%Y-%m-%d_%H%M%S' ) } " )
8161
82- self .output_filename = os .path .expanduser (f"~/.nxc/logs/{ self .hostname } _{ self .host } _{ datetime .now ().strftime ('%Y-%m-%d_%H%M%S' )} " )
83-
84- with contextlib .suppress (Exception ):
85- smb_conn .logoff ()
86-
87- self .db .add_host (self .host , self .port , self .hostname , self .domain , self .server_os )
62+ self .db .add_host (self .host , self .port , self .hostname , self .domain , self .server_os )
8863
8964 if self .args .domain :
9065 self .domain = self .args .domain
@@ -98,16 +73,10 @@ def enum_host_info(self):
9873 self .output_filename = os .path .expanduser (f"~/.nxc/logs/{ self .hostname } _{ self .host } _{ datetime .now ().strftime ('%Y-%m-%d_%H%M%S' )} " .replace (":" , "-" ))
9974
10075 def print_host_info (self ):
101- if self .args .no_smb :
102- self .logger .extra ["protocol" ] = "WINRM-SSL" if self .ssl else "WINRM"
103- self .logger .extra ["port" ] = self .port
104- self .logger .display (f"{ self .server_os } (name:{ self .hostname } ) (domain:{ self .domain } )" )
105- else :
106- self .logger .display (f"{ self .server_os } (name:{ self .hostname } ) (domain:{ self .domain } )" )
107- self .logger .extra ["protocol" ] = "WINRM-SSL" if self .ssl else "WINRM"
108- self .logger .extra ["port" ] = self .port
109-
110- self .logger .info (f"Connection information: { self .endpoint } (auth type:{ self .auth_type } ) (domain:{ self .domain if self .args .domain else '' } )" )
76+ self .logger .extra ["protocol" ] = "WINRM-SSL" if self .ssl else "WINRM"
77+ self .logger .extra ["port" ] = self .port
78+ self .logger .display (f"{ self .server_os } (name:{ self .hostname } ) (domain:{ self .domain } )" )
79+
11180 return True
11281
11382 def create_conn_obj (self ):
@@ -117,6 +86,14 @@ def create_conn_obj(self):
11786
11887 endpoints = {}
11988
89+ headers = {
90+ "Content-Length" : "0" ,
91+ "Keep-Alive" : "true" ,
92+ "Content-Type" : "application/soap+xml;charset=UTF-8" ,
93+ "User-Agent" : "Microsoft WinRM Client" ,
94+ "Authorization" : "Negotiate TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw=="
95+ }
96+
12097 for protocol in self .args .check_proto :
12198 endpoints [protocol ] = {}
12299 endpoints [protocol ]["port" ] = self .port [self .args .check_proto .index (protocol )] if len (self .port ) == 2 else self .port [0 ]
@@ -131,9 +108,12 @@ def create_conn_obj(self):
131108 self .port = endpoints [protocol ]["port" ]
132109 try :
133110 self .logger .debug (f"Requesting URL: { endpoints [protocol ]['url' ]} " )
134- res = requests .post (endpoints [protocol ]["url" ], verify = False , timeout = self .args .http_timeout )
111+ res = requests .post (endpoints [protocol ]["url" ], headers = headers , verify = False , timeout = self .args .http_timeout )
135112 self .logger .debug (f"Received response code: { res .status_code } " )
136- self .auth_type = res .headers ["WWW-Authenticate" ] if "WWW-Authenticate" in res .headers else "NOAUTH"
113+ self .challenge_header = res .headers ["WWW-Authenticate" ]
114+ if (not self .challenge_header ) or ("Negotiate" not in self .challenge_header ):
115+ self .logger .info ('Failed to get NTLM challenge from target "/wsman" endpoint, maybe isn\' t winrm service.' )
116+ return False
137117 self .endpoint = endpoints [protocol ]["url" ]
138118 self .ssl = endpoints [protocol ]["ssl" ]
139119 return True
0 commit comments