######################################################################################################################
# Exploit Title: SMB12 information gathering
# SMB12 means it's capable of inspecting both SMB1 and SMB2 versions 
# the utility will extract varios attributes from SMB protocol of the remote server such as
# OS version (only supported by SMB1 as per protocol definition)
# DNS computername, DNS domainname, NEtBIOS computername and NetBIOS domain name (SMB1 and SMB2)
# boot time and current time on the remote server (SMB1 and SMB2)
# Server's GUID (SMB1 and SMB2)
# Additional : NEtBIOS probe against UDP 137 (netbios session) to determine server roles such as
#		-domain master browser
# 		-domain controller
#		-server service
# Date: 11-July-2020
# Exploit Author: Ivica Stipovic
# Vendor Homepage: www.microsoft.com
# Software Link: intergrated as part of Windows OS
# Version: SMB1 and SMB2 
# Tested on: Windows 7, Windows 10, Windows 2012 R2, Windows 2016, Windows 2019 
# Domain setup: Some OS-es were setup as WORKGROUP members and some as DOMAIN 
# Objective: enhance system info returned by SMB protocol in comparison to :
# nmap smb-system-info.nse and metasploit smb_version and smb2 modules
# Known Limitation: not designed for SAMBA implementations (Linux etc) - no reliable detection/exception possible
# Download link: https://github.com/adenosine-phosphatase/smb12info
###########################################################################################################

import socket
import sys
import time
from datetime import datetime, timedelta
from struct import *

TCP_PORT=445

netbios_check=(
		"\x91\xe2"		 					# Transaction ID
		"\x00\x00" 							# Flags
		"\x00\x01"							# Questions=1
		"\x00\x00"							# Answer RRs
		"\x00\x00"							# Authority RRs
		"\x00\x00"							# Additional RRs
		"\x20\x43\x4b\x41\x41\x41\x41\x41"	# Queries MSHOME/Type NB, Class IN
		"\x41\x41\x41\x41\x41\x41\x41\x41"
		"\x41\x41\x41\x41\x41\x41\x41\x41"
		"\x41\x41\x41\x41\x41\x41\x41\x41"
		"\x41\x00"
		"\x00\x21"							# NBSTAT (33)
		"\x00\x01")							# Class IN(1)

smb_helper_message=(
		"\x00" 								# NEtbios header - Message type 00
        "\x00\x00\x54" 						# Length
		"\xff\x53\x4d\x42" 					# SMB header-Server component
        "\x72" 								# SMB command - negotiate protocol
        "\x00" 								# NT Status - status_success
        "\x00" 								# NT Status
        "\x00\x00" 							# NT Status
        "\x18" 								# Flags: 0x18
        "\x01\x28" 							# Flags2
        "\x00\x00" 							# Process ID High
        "\x00\x00\x00\x00\x00\x00\x00\x00" 	# Signature
        "\x00\x00" 							# Reserved
        "\x00\x00" 							# Tree ID
        "\x2e\x6f" 							# Process ID
        "\x00\x00" 							# User ID
        "\x7f\xe6" 							# Multiplex ID
		"\x00" 								# Word Count
        "\x31\x00" 							# Byte count
        "\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00" # Requested Dialects
        "\x02\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00" # PC NETWORK PROGRAM 1.0
        "\x02\x4e\x54\x20\x4c\x41\x4e\x4d\x41\x4e\x20" # MICROSOFT NETWORKS 1.03
        "\x31\x2e\x30\x00" 				
        "\x02\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00")

smb_enahanced_helper_message=(
		"\x00"								# NetBIOS header - message type 
		"\x00\x00\x45" 						# Length
		"\xff\x53\x4d\x42" 					# Server Component -SMB2
		"\x72" 								# Header Length
		"\x00\x00\x00\x00" 					# NT STATUS - status success
		"\x18" 								# Flags
		"\x53\xc8" 							# Flags2
		"\x00\x00" 							# Process ID High
		"\x00\x00\x00\x00\x00\x00\x00\x00" 	# Signature=00000
		"\x00\x00" 							# Reserved=0000
		"\xff\xff" 							# Tree ID
		"\xff\xfe" 							# Process ID
		"\x00\x00" 							# User ID
		"\x00\x00" 							# Multiplex ID
		"\x00" 								# Word Count
		"\x22\x00" 							# Byte count
		"\x02\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00" # Requested dialects - this is
		"\x02\x53\x4d\x42\x20\x32\x2e\x30\x30\x32\x00"     # the main difference to initial SMB1
		"\x02\x53\x4d\x42\x20\x32\x2e\x3f\x3f\x3f\x00")    # request

smb2_helper_message=(
		"\x00" 								# NetBIOS message type
		"\x00\x00\xae" 						# Length
		"\xfe\x53\x4d\x42" 					# SMB2 -Protocol ID
		"\x40\x00" 							# Header Length
		"\x00\x00" 							# Credit Charge
		"\x00\x00" 							# Channel sequence
		"\x00\x00" 							# Reserved
		"\x00\x00" 							# Negotiate Protocol
		"\x00\x00" 							# Credits requested
		"\x00\x00\x00\x00" 					# Flags
		"\x00\x00\x00\x00" 					# Chain offset
		"\x01\x00\x00\x00\x00\x00\x00\x00" 	# Message ID - unknown=1
		"\xff\xfe\x00\x00" 					# PRocess ID
		"\x00\x00\x00\x00" 					# Tree ID
		"\x00\x00\x00\x00\x00\x00\x00\x00" 	# Session ID
		"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # Signature 
		"\x24\x00" 							# Structure size
		"\x05\x00" 							# Dialect count
		"\x01\x00" 							# Security mode / signing enabled
		"\x00\x00" 							# Reserved
		"\x7f\x00\x00\x00" 					# Capabilities
		"\x86\xcc\xaa\x67\xca\xb6\xea\x11\x91\xb1\xfd\x77\x48\xa7\x6a\x3c" # Client GUID 
		"\x70\x00\x00\x00" 					# NegotiateContextOffset	
		"\x02\x00" 							# NEgotiateContextCount
		"\x00\x00" 							# Reserved
		"\x02\x02" 							# Dialect 1
		"\x10\x02" 							# Dialect 2
		"\x00\x03" 							# Dialect 3
		"\x02\x03" 							# Dialect 4
		"\x11\x03" 							# Dialect 5
		"\x00\x00" 							# unknonw
		"\x01\x00" 							# DataType SMB_PREAUTH
		"\x26\x00" 							# Datalength
		"\x00\x00\x00\x00" 					# Reserved
		"\x01\x00" 							# Hash Algorithm
		"\x20\x00" 							# salt length
		"\x01\x00" 							# Hash algorithm SHA-512
		"\xd3\x2f\xfe\xad\x6b\xc5\x32\xbb" 	# Salt (32 bytes)
		"\x44\x29\x7d\x56\x33\x69\xcd\xe7" 
		"\x42\x1c\x20\x53\x85\x16\x97\xc5" 
		"\x01\xec\x80\x12\x6a\x9b\xbe\x2d" 
		"\x00\x00" 							# unknown
		"\x02\x00" 							# SMB2_encryption_capabilities
		"\x06\x00" 							# Datalength
		"\x00\x00\x00\x00" 					# Reserved
		"\x02\x00" 							# Cipher count
		"\x02\x00" 							# Cipher ID
		"\x01\x00") 						# Cipher ID
		
smb_helper_message_security_blob=(
		"\x00" 								# NetBIOS message type
		"\x00\x00\x8f" 						# Length
		"\xff\x53\x4d\x42" 					# SMB1 Server Component
		"\x73" 								# Session Setup AndX (0x73)
		"\x00" 								# Error class=success
		"\x00" 								# Reserved
		"\x00\x00" 							# Error Code=no error
		"\x18" 								# Flags
		"\x01\x28" 							# Flags2
		"\x00\x00" 							# Process ID High
		"\x00\x00\x00\x00\x00\x00\x00\x00" 	# Signature
		"\x00\x00" 							# Reserved
		"\x00\x00" 							# Tree ID
		"\x2e\x6f" 							# Process ID
		"\x00\x00" 							# User ID	
		"\x7f\xe6" 							# Multiplex ID
		"\x0c" 								# Word Count
		"\xff" 								# AndX Command=no further commands
		"\x00" 								# Reserved
		"\x00\x00" 							# AndXOffset=0
		"\xdf\xff" 							# Max Buffer
		"\x02\x00" 							# Max Mpx Count
		"\x01\x00" 							# VC Number
		"\x00\x00\x00\x00" 					# Session Key
		"\x31\x00" 							# Security Blob Length
		"\x00\x00\x00\x00" 					# Reserved
		"\xd4\x00\x00\x80" 					# Capabilities
		"\x54\x00"							# Byte Count
		"\x4e\x54\x4c\x4d\x53\x53\x50\x00"  # NTLMSSP identifier	
		"\x01\x00\x00\x00" 					# NTLM Message Type = NTLMSSP_NEGOTIATE
		"\x05\x02\x88\xa2" 					# Negotiate flags
		"\x01\x00\x01\x00\x20\x00\x00\x00\x10\x00\x10\x00\x21\x00\x00\x00"		#Calling Wkst domain 
		"\x2e" 									
		"\x32\x54\x64\x44\x36\x30\x77\x62\x4e\50\x36\47\x39\x61\x66\x76" 		# Calling wkst name
		"\x57\x69\x6e\x64\x6f\x77\x73\x20\x32" 									# Native OS Win2000
		"\x30\x30\x30\x20\x32\x31\x39\x35\x00" 									# Native LAN Manager
	        "\x57\x69\x6e\x64\x6f\x77\x73\x20\x32" 
		"\x30\x30\x30\x20\x35\x2e\x30\x00")

smb2_helper_ntlmssp_message= (
		"\x00"								# Netbios Message Type 		
		"\x00\x00\xa2" 						# Length
		"\xfe\x53\x4d\x42" 					# Server Component, ex: SMB2
		"\x40\x00" 							# Header Length
		"\x01\x00" 							# Credit Charge
		"\x00\x00" 							# Channel sequence
		"\x00\x00" 							# Reserved
		"\x01\x00" 							# Session Setup
		"\x21\x00" 							# Credits requested
		"\x10\x00\x00\x00" 					# Flags
		"\x00\x00\x00\x00" 					# Chain Offset
		"\x02\x00\x00\x00\x00\x00\x00\x00" 	# Message ID
		"\xff\xfe\x00\x00" 		 			# Process ID
		"\x00\x00\x00\x00" 		 			# Tree ID
		"\x00\x00\x00\x00\x00\x00\x00\x00" 	# Session ID
		"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # Signature
		"\x19\x00" 							# Structure size
		"\x00" 								# Flags
		"\x02" 								# Security mode
		"\x01\x00\x00\x00" 					# Capabilities
		"\x00\x00\x00\x00" 					# Channel
		"\x58\x00" 							# Previous session ID
		"\x4a\x00" 							# Blob length
		"\x00\x00\x00\x00\x00\x00\x00\x00" 	# Previos Session ID
		"\x60\x48\x06\x06\x2b\x06\x01\x05" 	# GSS-API Generic Security Service 
		"\x05\x02\xa0\x3e\x30\x3c\xa0\x0e" 	# Simple Protected NEgotiation
		"\x30\x0c\x06\x0a\x2b\x06\x01\x04" 	# mechtypes + NTLM Secure Service Provider
		"\x01\x82\x37\x02\x02\x0a\xa2\x2a" 
		"\x04\x28\x4e\x54\x4c\x4d\x53\x53" 
		"\x50\x00\x01\x00\x00\x00\x97\x82" 
		"\x08\xe2\x00\x00\x00\x00\x00\x00" 
		"\x00\x00\x00\x00\x00\x00\x00\x00" 
		"\x00\x00\x0a\x00\xee\x42\x00\x00" 
		"\x00\x0f")
			

def print_smb12_system_info (smb_type,data2):
	
	netbios_header=4

	if smb_type==1:
		smb_header=32
	else:
		smb_header=64
	
        blob_offset=netbios_header+smb_header
        offset=0
    	index=0
    	size=len (data2)
		    		
	pattern=0
    	security_blob="4e544c4d535350"
    	control=""

    	for t in data2[blob_offset:size-blob_offset]:
		
		for x in data2[blob_offset+offset:blob_offset+offset+7]:
			control=control+"{:02x}".format(ord(x),"x")  
			

               	if security_blob==control:

			index=blob_offset+offset
			index=index+12
				
			targetnamelen=int(ord(data2[index:index+1][::-1]))

			index=index+28
			index=index+16

				
			targetname=data2[index:index+targetnamelen]			
			targetinfoitemlen=int(ord(data2[index+targetnamelen+2]))
			
			netbiosname=data2[index+targetnamelen+4:index+targetnamelen+4+targetinfoitemlen]
				
			netbioscomputernamelen=int(ord(data2[index+targetnamelen+4+targetinfoitemlen+2]))
			index=index+targetnamelen+4+targetinfoitemlen+2

			netbioscomputername=data2[index+2:index+2+netbioscomputernamelen]
			
			dnsdomainnamelen=int(ord(data2[index+2+netbioscomputernamelen+2]))
		 	index=index+2+netbioscomputernamelen+2

			dnsdomainname=data2[index+2:index+2+dnsdomainnamelen]
			
			dnscomputernamelen=int(ord(data2[index+2+dnsdomainnamelen+2]))
			index=index+2+dnsdomainnamelen+2

			dnscomputername=data2[index+2:index+2+dnscomputernamelen]
			
			print "[+] Target Name:", targetname
			print "[+] Netbios Domainname:",netbiosname
			print "[+] Netbios Computername:", netbioscomputername
			print "[+] DNS Domain Name:", dnsdomainname
			print "[+] DNS Computer Name:", dnscomputername
					
			index=index+2+dnscomputernamelen
			
# Check for DNS tree info item type - must be 5, anything else means not a domain member
			
			if int(ord(data2[index]))==5:
				dnstreelen=int(ord(data2[index+2]))
							
				print "[+] DNS Tree Name:", data2[index+2:index+2+dnstreelen+1]
				index=index+2+dnstreelen+2

# Skip over 16 bytes (timestamp=12 bytes + end-of-list=4 bytes
							
			index=index+16
			
			if size-index>0:
			
				print "[+] OS info:",data2[index-2:size]
	
		offset+=1
		control=""

def netbios_fingerprint():

	sockUDP=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
	try:	
		sockUDP.sendto(netbios_check,(TCP_IP,137))
		sockUDP.settimeout(3)		
		dataUDP,addrUDP=sockUDP.recvfrom(1024)
		
		number_of_names=int(ord(dataUDP[56]))
		
		delta=0
		names_offset=57
		role=0
		
		for x in range(number_of_names):
			
			role=int(ord(dataUDP[names_offset+(x+1)*16-1+delta]))						
			if role==0:
				print ("[+] NetBIOS Role: Workstation/Redirector")
			elif role==32:
				print ("[+] NetBIOS Role: Server Service")
			elif role==28:
				print ("[+] NetBIOS Role: Domain Controller")
			elif role==27:
				print ("[+] NetBIOS Role: Domain Master Browser") 
			delta+=2
	
	except socket.timeout:
		print "[-] No response from NetBIOS"
		sockUDP.close()
	
def send_smb_request(message_type,sock_type):

	sock_type.sendall(message_type)
	resp,addr=sock_type.recvfrom(1024)
	return resp

def print_smb1_guid(smb1_guid_data):

	 guidA_id=""
	 guidB_id=""
	 guidC_id=""
	 guidD_id=""
	 guidE_id=""
	 for x in temp_data[73:77]:	
		guidA_id=guidA_id+"{:02x}".format(ord(x),"x")
      
    	 for x in temp_data[77:79]:
		guidB_id=guidB_id+"{:02x}".format(ord(x),"x")

    	 for x in temp_data[79:81]:
		guidC_id=guidC_id+"{:02x}".format(ord(x),"x")

    	 for x in temp_data[81:83]:
		guidD_id=guidD_id+"{:02x}".format(ord(x),"x")

    	 for x in temp_data[83:89]:
        	guidE_id=guidE_id+"{:02x}".format(ord(x),"x")
    
    	 print "[+] Server GUID:" ,guidA_id+'-'+guidB_id+'-'+guidC_id+'-'+guidD_id+'-'+guidE_id

def print_system_time(start_time,end_time,time_type):

# time_type=0 then boot time
# time_type=1 then current time

	dx=""
	for y in temp_data[start_time:end_time][::-1]:
		dx=dx+"{:02x}".format(ord(y),"x")

    	if dx!="0000000000000000":
    		us=int(dx,16) / 10.
		if time_type==0:
       			print "[+] Boot time:",datetime(1601,1,1) + timedelta(microseconds=us)    
		else:
			print "[+] Current time:", datetime(1601,1,1) + timedelta(microseconds=us)
    	else:
		if time_type==0:		
			print "[-] Boot time not specified"
		else:
			print "[+] Current time not specified"
    	dx=""


if len(sys.argv)!=2:
    print ("usage: python smbinject.py <ip address>")
    sys.exit()
else:
    TCP_IP=sys.argv[1]

#====================================
# Negotiate Protocol Request sequence
#=====================================

print ("[+] Trying NetBIOS fingerprint...")

netbios_fingerprint()

sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((TCP_IP,TCP_PORT))

try:
    print ("[+] Starting SMB1 check")
    temp_data=send_smb_request(smb_helper_message,sock)	
    smb_dialect=temp_data[72:74]
  
    current_time_start=60
    current_time_stop=68

    print_system_time(current_time_start,current_time_stop,1)
    print_smb1_guid(temp_data)

    print ("[+] SMB1 dialect detected")
    time.sleep(1) 

    data=send_smb_request(smb_helper_message_security_blob,sock)
    print ("[+] SMB response")
    
    smb=1
    print_smb12_system_info (smb,data)

except socket.error,ex:
    print ("[-] Server reset SMB1 negotiation. Trying SMB2 ...")
    sock2=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock2.connect((TCP_IP,TCP_PORT))
  
    temp_data=send_smb_request(smb_enahanced_helper_message,sock2)
 
    guid1_id=""
    guid2_id=""
    guid3_id=""
    guid4_id=""
    guid5_id=""

    for x in temp_data[76:80][::-1]:	
	guid1_id=guid1_id+"{:02x}".format(ord(x),"x")
      
    for x in temp_data[80:82][::-1]:
	guid2_id=guid2_id+"{:02x}".format(ord(x),"x")

    for x in temp_data[82:84][::-1]:
	guid3_id=guid3_id+"{:02x}".format(ord(x),"x")

    for x in temp_data[84:86]:
	guid4_id=guid4_id+"{:02x}".format(ord(x),"x")

    for x in temp_data[86:92]:
        guid5_id=guid5_id+"{:02x}".format(ord(x),"x")
    
    print "[+] Server GUID:" ,guid1_id+'-'+guid2_id+'-'+guid3_id+'-'+guid4_id+'-'+guid5_id
    
    dt=""

    current_time_start=108
    current_time_stop=116
    boot_time_start=116
    boot_time_stop=124

    print_system_time(current_time_start,current_time_stop,1)
    print_system_time(boot_time_start,boot_time_stop,0)

    time.sleep(2) 	
 
    send_smb_request(smb2_helper_message,sock2)
    time.sleep(1)
  
    data2=send_smb_request(smb2_helper_ntlmssp_message,sock2)   

    smb=2
    print_smb12_system_info (smb,data2)

    sock2.close()

sock.close()