Created
July 19, 2018 18:36
-
-
Save jackson5sec/39a823899bf8bca5408654b3b72c6166 to your computer and use it in GitHub Desktop.
A make-shift SMB2 replacement for Metasploit's auxiliary/scanner/smb_version
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
''' | |
This is a make-shift replacement for metasploit's auxiliary/scanner/smb_version for clients that have disabled/removed | |
SMBv1. This grabs the hostname, domain name, and Windows version from the NTLMv2 challenge response | |
@Quickbreach | |
''' | |
import argparse | |
import struct | |
from binascii import hexlify, unhexlify | |
import socket | |
import random | |
import string | |
from netaddr import IPNetwork | |
from threading import Thread | |
from multiprocessing import Queue | |
from impacket.spnego import SPNEGO_NegTokenResp | |
from impacket.ntlm import NTLMAuthChallenge, AV_PAIRS, NTLMSSP_AV_HOSTNAME | |
from impacket.smb3structs import SMB2Packet, SMB2Negotiate, \ | |
SMB2SessionSetup_Response, SMB2_DIALECT_002, SMB2_DIALECT_21, \ | |
SMB2_DIALECT_30, SMB2_DIALECT_302 | |
import logging | |
from impacket.examples import logger | |
logger.init() | |
logging.getLogger().setLevel(logging.INFO) | |
class VChecker(Thread): | |
def __init__(self, IPQueue, Timeout = 3): | |
Thread.__init__(self) | |
self.daemon = True | |
self.IPQueue = IPQueue | |
self.Timeout = 3 | |
self.suicide = False | |
self.start() | |
def join(self, timeout): | |
if(timeout == -1): | |
return | |
else: | |
self.suicide = True | |
super(VChecker, self).join(timeout) | |
def run(self): | |
while True: | |
if self.suicide: return | |
nextIP = None # need this declared outside of the try/catch | |
try: | |
if not self.IPQueue.empty(): | |
nextIP = self.IPQueue.get() | |
else: | |
self.suicide = True | |
return | |
except Exception, e: | |
return | |
if nextIP == None: return | |
s = None | |
try: | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
s.settimeout(self.Timeout) | |
s.connect((nextIP, 445)) | |
except Exception, e: | |
continue | |
if(s == None): | |
continue | |
try: | |
# Negotiate | |
negProto = SMB2Negotiate(unhexlify("24000500010000007f000000cb78cd146438e7119168000c291232a370000000020000000202100200030203110300000100260000000000010020000100c8c31f28d43563c829b9070423e96a98701ac3ec788a3ac01573ee03d07d942600000200060000000000020002000100")) | |
negProto['Dialects'] = [SMB2_DIALECT_002, SMB2_DIALECT_21, SMB2_DIALECT_30, SMB2_DIALECT_302, 0, 0] | |
negProto['ClientGuid'] = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8)) | |
rawData = str(SMB2Packet()) + str(negProto) | |
netbios = struct.pack('>i', len(str(rawData))) | |
rpkt = str(netbios) + str(rawData) | |
s.sendall(rpkt) | |
data = s.recv(4096) | |
negResp = SMB2Packet(data[4:]) | |
# NTLMSSP Negotiate | |
sessionSetup = unhexlify("000000a2fe534d42400001000000000001001f0000000000000000000200000000000000fffe00000000000000000000000000000000000000000000000000000000000019000001010000000000000058004a000000000000000000604806062b0601050502a03e303ca00e300c060a2b06010401823702020aa22a04284e544c4d5353500001000000978208e2000000000000000000000000000000000601b11d0000000f") | |
test = SMB2Packet(sessionSetup[4:]) | |
test['Reserved'] = 0 | |
test['MessageID'] = 1 | |
netbios = str(struct.pack('>i', len(str(test)))) | |
s.sendall(netbios + str(test)) | |
# Get NTLMSSP challenge response | |
data = s.recv(4096) | |
s.close() | |
packet = SMB2Packet(data[4:]) | |
resp = SMB2SessionSetup_Response(packet['Data']) | |
securityBlob = SPNEGO_NegTokenResp(resp['Buffer']) | |
authData = NTLMAuthChallenge(securityBlob['ResponseToken']) | |
serverInfo = AV_PAIRS(authData['TargetInfoFields']) | |
majorVersion = int(hexlify(struct.unpack('<c', str(authData['Version'])[0])[0]), 16) | |
minorVersion = int(hexlify(struct.unpack('<c', str(authData['Version'])[1])[0]), 16) | |
buildVersion = struct.unpack('<h', str(authData['Version'])[2:4])[0] | |
hostname = serverInfo[NTLMSSP_AV_HOSTNAME][1].decode("utf-16-le").encode("utf-8") | |
domain = authData['domain_name'].decode("utf-16-le").encode("utf-8") | |
except Exception, e: | |
logging.error("Failed to get data from " + nextIP + " (Does it support NTLM?)") | |
logging.error(e) | |
continue | |
OS = "(Unknown OS version)" | |
if majorVersion == 5: | |
# Major 5, minor 1: Windows XP SP2 | |
if minorVersion == 1: OS = "Windows XP SP2" | |
# Major 5, minor 2: Windows server 2003 | |
if minorVersion == 2: OS = "Windows Server 2003" | |
if majorVersion == 6: | |
if minorVersion == 0: OS = "Windows Vista or Server 2008" | |
if minorVersion == 1: OS = "Windows 7 or Server 2008 R2" | |
if minorVersion == 2: OS = "Windows 8 or Server 2012" | |
if minorVersion == 3: OS = "Windows 8.1 or Server 2012 R2" | |
if majorVersion == 10: | |
if minorVersion == 0: OS = "Windows 10 or Server 2016" | |
logging.info(nextIP + ":445\t" + OS + " (build:" + str(buildVersion) + ") (name:" + hostname + ") (Domain:" + domain + ")") | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser() | |
parser._optionals.title = "Standard arguments" | |
parser.add_argument('-t', type=str, help='Target IP or CIDR', required=True) | |
parser.add_argument('--threads', default=1, type=int, help='Maximum number of concurrent threads (default: 1)', required=False) | |
parser.add_argument('--timeout', default=1, type=int, help='Connection timeout in seconds (default: 1)', required=False) | |
args = parser.parse_args() | |
targetList = Queue() | |
workers = [] | |
for ip in IPNetwork(args.t): | |
targetList.put(str(ip)) | |
for x in range(0, args.threads): | |
workers.append(VChecker(targetList, args.timeout)) | |
try: | |
for worker in workers: | |
while worker.isAlive(): | |
worker.join(-1) | |
except KeyboardInterrupt: | |
logging.error("Recieved interrupt - cleaning up...") | |
for worker in workers: | |
worker.join(0) | |
exit(0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment