home *** CD-ROM | disk | FTP | other *** search
/ DEFCON 14 / DEFCON_14_CD-ROM_2006.iso / DC-14-Presentations / DC-14-Ruks / martyn_ruks_dlsw_query-1.0_defcon14.py < prev   
Text File  |  2006-07-11  |  34KB  |  910 lines

  1. #! /usr/bin/env python
  2. # DLSw Query Tool
  3. # Public Release 1.0 (Defcon 14)
  4. # Written by: Martyn Ruks, MWR InfoSecurity, Copyright 2006
  5. #
  6. # This tool is released for educational purposes only and the author is not responsible for any damage it causes.
  7. # Greetz to B-r00t, m1nx, haggis, marshal-l, mark@vulndev.org
  8. #
  9. # Thanks to Phillipe Biondi <phil@secdev.org> for Scapy
  10. #
  11. # For usage: ./dlsw_query-1.0.py --help
  12. #
  13.  
  14. # Add various required functions
  15. import time
  16. import binascii
  17. import socket
  18. import optparse
  19.  
  20. # Set log level to benefit from Scapy warnings
  21. import logging
  22. logging.getLogger("scapy").setLevel(1)
  23.  
  24. from BitVector import *
  25. from scapy import *
  26. from optparse import OptionParser
  27.  
  28. #
  29. # Extend optparse to make target options required
  30. #
  31.  
  32. class OptionParser (optparse.OptionParser):
  33.  
  34.     def check_required (self, opt):
  35.         option = self.get_option(opt)
  36.  
  37.         if getattr(self.values, option.dest) is None:
  38.             self.error("%s option not supplied" % option)
  39.  
  40. #
  41. # Packet Arrays
  42. #
  43.  
  44. # Public version contains static arrays
  45. # future versions will include Packet Class Definitions for use with Scapy
  46.  
  47. dlsw_response = '\x31\x48\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x42\x01\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\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\x00\x00\x00\x00\x04\x15\x21' 
  48.  
  49. dlsw_request_v1 = '\x31\x48\x00\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x42\x01\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x81\x1d\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\x00\x38\x15\x20\x05\x81\x00\x00\x0c\x04\x82\x01\x00\x04\x83\x00\x14\x12\x86\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x07\x84\x43\x69\x73\x63\x6f\x03\x87\x01\x03\x85\x00\x03\x88\x00\x05\x8b\x00\x00\x0c'
  50.  
  51. dlsw_request_v2 = '\x31\x48\x00\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x42\x01\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x81\x1d\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\x00\x38\x15\x20\x05\x81\x00\x00\x0c\x04\x82\x02\x00\x04\x83\x00\x14\x12\x86\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x07\x84\x43\x69\x73\x63\x6f\x03\x87\x01\x03\x85\x00\x03\x88\x00\x05\x8b\x00\x00\x0c'
  52.  
  53. #
  54. # Packet Handling Functions
  55. #
  56.  
  57. # Reads a DLSw packet from a socket
  58. def packet_read(channel1,fileHandle,filewrite):
  59.     response = channel1.recv (4)
  60.  
  61.     # Now get the packet information
  62.     dlsw_version = get_length(response,0,1)
  63.     header_length_bytes = get_length(response,1,2)
  64.     message_length_bytes = get_length(response,2,4)
  65.     header_length_hex = get_hex_length(response,1,2)
  66.     message_length_hex = get_hex_length(response,2,4)
  67.     print ''
  68.  
  69.     # Check the DLSw version
  70.     if dlsw_version != 49:
  71.         text = '*** WARNING *** Does not look like a DLSw packet'
  72.         print text
  73.         if filewrite == 1:
  74.             fileHandle.write ( text+'\n' )
  75.  
  76.     text = 'Header length 0x'+header_length_hex+' or '+str(header_length_bytes)+' bytes'
  77.     print text
  78.     if filewrite == 1:
  79.             fileHandle.write ( text+'\n' )
  80.  
  81.     text = 'Message length 0x'+message_length_hex+' or '+str(message_length_bytes)+' bytes'
  82.     print text
  83.     if filewrite == 1:
  84.             fileHandle.write ( text+'\n' )
  85.  
  86.     # Calculate first packet size
  87.     response_size = message_length_bytes + header_length_bytes
  88.     text = 'Packet is '+str(response_size)+' bytes'
  89.     print text
  90.     if filewrite == 1:
  91.             fileHandle.write ( text+'\n' )
  92.  
  93.     # Check whether we have read enough data from the socket
  94.     if response_size > 4:
  95.         response2 = channel1.recv (response_size-4)
  96.     
  97.     # Join all the bits together
  98.     response = response+response2
  99.  
  100.     # Return the packet itself
  101.     return response
  102.  
  103. # Returns a decimal integer between two specified positions in a string
  104. def get_length(response,start,end):
  105.     header_length = response[start:end]
  106.     header_length_hex = binascii.hexlify(header_length)
  107.     header_length_bytes = string.atoi(str(header_length_hex),16)
  108.     return header_length_bytes
  109.  
  110. # Returns a hex value as an integer between two specified positions in a string
  111. def get_hex_length(response,start,end):
  112.     header_length = response[start:end]
  113.     header_length_hex = binascii.hexlify(header_length)
  114.     return header_length_hex
  115.  
  116. #
  117. # Functions to parse response data
  118. #
  119.  
  120. # Check packet type
  121. def check_cap_packet_type(response,fileHandle,filewrite):
  122.     query_type = response[14:15]
  123.     query_type = binascii.hexlify(query_type)
  124.     if query_type != '20':
  125.         text = '*** WARNING *** Not a Capabilities Exchange Packet'
  126.         print text
  127.         if filewrite == 1:
  128.             fileHandle.write ( text+'\n' )
  129.     query_direction = response[38:39]
  130.     query_direction = binascii.hexlify(query_direction)
  131.     header_length = get_length(response,1,2)
  132.     gds_value = response[header_length+2:header_length+4]
  133.     gds_value = binascii.hexlify(gds_value)
  134.     if query_direction == '01':
  135.         if gds_value == '1520':
  136.             text = '*** NOTE *** Packet passed the tests for a Request'
  137.             print text
  138.             if filewrite == 1:
  139.                 fileHandle.write ( text+'\n\n' )
  140.         else:
  141.             text = '*** WARNING *** Not a valid Request Packet'
  142.             print text
  143.             if filewrite == 1:
  144.                 fileHandle.write ( text+'\n\n' )
  145.     elif query_direction == '02':
  146.         if gds_value == '1521':
  147.             text = '*** NOTE *** Packet passed the tests for a Response'
  148.             print text
  149.             if filewrite == 1:
  150.                 fileHandle.write ( text+'\n\n' )
  151.         elif gds_value == '1522':
  152.             text = '*** NOTE *** Target refused our Capabilities'
  153.             print text
  154.             if filewrite == 1:
  155.                 fileHandle.write ( text+'\n\n' )
  156.             # ADD REASON DISSECTION HERE
  157.         else:
  158.             text = '*** WARNING *** Not a valid Response Packet'
  159.             print text
  160.             if filewrite == 1:
  161.                 fileHandle.write ( text+'\n\n' )
  162.  
  163. # Get the advertised DLSw version
  164. def get_dlsw_version(response,header_length,fileHandle,filewrite):
  165.  
  166.     # Search for the version string
  167.     dlsw_version = re.search('\x82',response)
  168.  
  169.     if dlsw_version:
  170.         # Check the data is in the message not the header
  171.         version_length_pos = dlsw_version.start()
  172.  
  173.         if version_length_pos > header_length+4:
  174.             # Get the length of the string in the right format
  175.             version_length = response[version_length_pos-1:version_length_pos]
  176.             version_length_hex = binascii.hexlify(version_length)
  177.             version_length_bytes = string.atoi(str(version_length_hex),16)
  178.  
  179.             if version_length_bytes == 4:
  180.                 # Get the string itself
  181.                 dlsw_string1 = response[version_length_pos+1:version_length_pos+2]
  182.                 dlsw_string2 = response[version_length_pos+2:version_length_pos+3]
  183.  
  184.                 dlsw_string1 = binascii.hexlify(dlsw_string1)
  185.                 dlsw_string2 = binascii.hexlify(dlsw_string2)
  186.  
  187.                 dlsw_string1 = string.atoi(str(dlsw_string1),10)
  188.                 text = 'DLSw Version: '+str(dlsw_string1)+'.'+str(dlsw_string2)
  189.                 print text
  190.                 if filewrite == 1:
  191.                     fileHandle.write ( text+'\n' )
  192.             else:
  193.                 text = '*** WARNING *** The version string is not in the correct format'
  194.                 print text
  195.                 if filewrite == 1:
  196.                     fileHandle.write ( text+'\n' )
  197.  
  198.         else:
  199.             text = '*** WARNING *** The DLSw version was not in the correct place'
  200.             print text
  201.             if filewrite == 1:
  202.                 fileHandle.write ( text+'\n' )
  203.     else:
  204.         text = '*** WARNING *** The DLSw version data was not present'
  205.         print text
  206.         if filewrite == 1:
  207.             fileHandle.write ( text+'\n' )
  208.  
  209. # Get the TCP connections number
  210. def get_tcp_connections(response,header_length,fileHandle,filewrite):
  211.  
  212.     # Search for the number of supported TCP connections
  213.     tcp_connections = re.search('\x87',response)
  214.  
  215.     if tcp_connections:
  216.         # Check the data is in the message not the header
  217.         version_length_pos = tcp_connections.start()
  218.  
  219.         if version_length_pos > header_length+4:
  220.             # Get the length of the string in the right format
  221.             version_length = response[version_length_pos-1:version_length_pos]
  222.             version_length_hex = binascii.hexlify(version_length)
  223.             version_length_bytes = string.atoi(str(version_length_hex),16)
  224.  
  225.             if version_length_bytes == 3:
  226.                 # Get the string itself
  227.                 tcp_connections = response[version_length_pos+1:version_length_pos+2]
  228.  
  229.                 tcp_connections = binascii.hexlify(tcp_connections)
  230.  
  231.                 tcp_connections = string.atoi(str(tcp_connections),10)
  232.                 text = 'TCP Connections: '+str(tcp_connections)
  233.                 print text
  234.                 if filewrite == 1:
  235.                     fileHandle.write ( text+'\n' )
  236.             else:
  237.                 text = '*** WARNING *** The TCP connections data is not in the correct format'
  238.                 print text
  239.                 if filewrite == 1:
  240.                     fileHandle.write ( text+'\n' )
  241.  
  242.         else:
  243.             text = '*** WARNING *** The TCP connections data was not in the correct place'
  244.             print text
  245.             if filewrite == 1:
  246.                 fileHandle.write ( text+'\n' )
  247.     else:
  248.         text = '*** WARNING *** The TCP connections data was not present'
  249.         print text
  250.         if filewrite == 1:
  251.             fileHandle.write ( text+'\n' )
  252.  
  253. # Get the vendor OUI
  254. def get_vendor_oui(response,header_length,fileHandle,filewrite):
  255.  
  256.     # Search for the Vendor OUI value
  257.     vendor_oui = re.search('\x8b',response)
  258.  
  259.     if vendor_oui:
  260.         # Check the data is in the message not the header
  261.         version_length_pos = vendor_oui.start()
  262.  
  263.         if version_length_pos > header_length+4:
  264.             # Get the length of the string in the right format
  265.             version_length = response[version_length_pos-1:version_length_pos]
  266.             version_length_hex = binascii.hexlify(version_length)
  267.             version_length_bytes = string.atoi(str(version_length_hex),16)
  268.  
  269.             if version_length_bytes == 5:
  270.                 # Get the string itself
  271.                 vendor_oui = response[version_length_pos+1:version_length_pos+4]
  272.  
  273.                 vendor_oui = binascii.hexlify(vendor_oui)
  274.                 if vendor_oui == '00000c':
  275.                     vendor_name = "Cisco"
  276.                 else:
  277.                     vendor_name = "Unknown"
  278.  
  279.                 text = 'Vendor OUI: 0x'+str(vendor_oui)+' '+vendor_name
  280.                 print text
  281.                 if filewrite == 1:
  282.                     fileHandle.write ( text+'\n' )
  283.             else:
  284.             
  285.                 text = '*** WARNING *** The vendor OUI data is not in the correct format'
  286.                 print text
  287.                 if filewrite == 1:
  288.                     fileHandle.write ( text+'\n' ) 
  289.  
  290.         else:
  291.             text = '*** WARNING *** The vendor OUI data was not in the correct place'
  292.             print text
  293.             if filewrite == 1:
  294.                 fileHandle.write ( text+'\n' )
  295.     else:
  296.         text = '*** WARNING *** The vendor OUI string was not present'
  297.         print text
  298.         if filewrite == 1:
  299.             fileHandle.write ( text+'\n' )
  300.  
  301. # Get Multicast support
  302. def get_multicast(response,header_length,fileHandle,filewrite):
  303.  
  304.     # Search for the MAC exclusivity value
  305.     multicast = re.search('\x8c',response)
  306.  
  307.     if multicast:
  308.         # Check the data is in the message not the header
  309.         version_length_pos = multicast.start()
  310.  
  311.         if version_length_pos > header_length+4:
  312.             # Get the length of the string in the right format
  313.             version_length = response[version_length_pos-1:version_length_pos]
  314.             version_length_hex = binascii.hexlify(version_length)
  315.             version_length_bytes = string.atoi(str(version_length_hex),16)
  316.  
  317.             if version_length_bytes == 3:
  318.                 # Get the string itself
  319.                 multicast = response[version_length_pos+1:version_length_pos+2]
  320.  
  321.                 multicast = binascii.hexlify(multicast)
  322.                 if multicast == '00':
  323.                     multicast = "No"
  324.                 elif multicast == '01':
  325.                     multicast = "Yes"
  326.                 else:
  327.                     multicast = "Unknown"
  328.  
  329.                 text = 'Multicast: '+str(multicast)
  330.                 print text
  331.                 if filewrite == 1:
  332.                     fileHandle.write ( text+'\n' )
  333.             else:
  334.                 text = '*** WARNING *** The Multicast support data is not in the correct format'
  335.                 print text
  336.                 if filewrite == 1:
  337.                     fileHandle.write ( text+'\n' )
  338.  
  339.         else:
  340.             text = '*** WARNING *** The Multicast support data was not in the correct place'
  341.             print text
  342.             if filewrite == 1:
  343.                 fileHandle.write ( text+'\n' )
  344.     else:
  345.         text = '*** WARNING *** The Multicast support data was not present'
  346.         print text
  347.         if filewrite == 1:
  348.             fileHandle.write ( text+'\n' )
  349.  
  350. # Get Initial Pacing
  351. def get_pacing(response,header_length,fileHandle,filewrite):
  352.  
  353.     # Search for the Initial Pacing value
  354.     pacing = re.search('\x83',response)
  355.  
  356.     if pacing:
  357.         # Check the data is in the message not the header
  358.         version_length_pos = pacing.start()
  359.  
  360.         if version_length_pos > header_length+4:
  361.             # Get the length of the string in the right format
  362.             version_length = response[version_length_pos-1:version_length_pos]
  363.             version_length_hex = binascii.hexlify(version_length)
  364.             version_length_bytes = string.atoi(str(version_length_hex),16)
  365.  
  366.             if version_length_bytes == 4:
  367.                 # Get the string itself
  368.                 pacing = response[version_length_pos+1:version_length_pos+3]
  369.  
  370.                 pacing = binascii.hexlify(pacing)
  371.                 pacing = string.atoi(str(pacing),16)
  372.  
  373.                 text = 'Initial Pacing: '+str(pacing)
  374.                 print text
  375.                 print ''
  376.                 if filewrite == 1:
  377.                     fileHandle.write ( text+'\n' )
  378.             else:
  379.                 text = '*** WARNING *** The initial pacing data is not in the correct format'
  380.                 print text
  381.                 print ''
  382.                 if filewrite == 1:
  383.                     fileHandle.write ( text+'\n' )
  384.  
  385.         else:
  386.             text = '*** WARNING *** The initial pacing data was not in the correct place'
  387.             print text
  388.             print ''
  389.             if filewrite == 1:
  390.                 fileHandle.write ( text+'\n' )
  391.     else:
  392.         text = '*** WARNING *** The initial pacing data was not present'
  393.         print text
  394.         print ''
  395.         if filewrite == 1:
  396.             fileHandle.write ( text+'\n' )
  397.  
  398. # Get the version string information
  399. def get_version_string(response,header_length,fileHandle,filewrite):
  400.  
  401.     # Search for the version string
  402.     version_string = re.search('\x84',response)
  403.  
  404.     if version_string:
  405.         # Check the data is in the message not the header
  406.         version_length_pos = version_string.start()
  407.  
  408.         if version_length_pos > header_length+4:
  409.  
  410.             # Get the length of the string in the right format
  411.             version_length = response[version_length_pos-1:version_length_pos]
  412.             version_length_hex = binascii.hexlify(version_length)
  413.             version_length_bytes = string.atoi(str(version_length_hex),16)
  414.  
  415.             # Get the string itself
  416.             version_string = response[version_length_pos+1:version_length_bytes+version_length_pos-1]
  417.             text = 'Version String:'
  418.             print ''
  419.             print text
  420.             print version_string
  421.             print ''
  422.             if filewrite == 1:
  423.                 fileHandle.write ( '\n'+text+'\n'+version_string+'\n' )
  424.  
  425.         else:
  426.             text = '*** WARNING *** The version string was not in the correct place'
  427.             print text
  428.             print ''
  429.             if filewrite == 1:
  430.                 fileHandle.write ( text+'\n' )
  431.     else:
  432.         text = '*** WARNING *** The version string was not present'
  433.         print text
  434.         print ''
  435.         if filewrite == 1:
  436.             fileHandle.write ( text+'\n' )
  437.  
  438. # Get the MAC address exclusivity
  439. def get_mac_exclusivity(response,header_length,fileHandle,filewrite):
  440.  
  441.     # Search for the MAC exclusivity value
  442.     mac_exclusive = re.search('\x85',response)
  443.  
  444.     if mac_exclusive:
  445.         # Check the data is in the message not the header
  446.         version_length_pos = mac_exclusive.start()
  447.  
  448.         if version_length_pos > header_length+4:
  449.             # Get the length of the string in the right format
  450.             version_length = response[version_length_pos-1:version_length_pos]
  451.             version_length_hex = binascii.hexlify(version_length)
  452.             version_length_bytes = string.atoi(str(version_length_hex),16)
  453.  
  454.             if version_length_bytes == 3:
  455.                 # Get the string itself
  456.                 mac_exclusive = response[version_length_pos+1:version_length_pos+2]
  457.  
  458.                 mac_exclusive = binascii.hexlify(mac_exclusive)
  459.                 if mac_exclusive == '00':
  460.                     mac_exclusive = "No"
  461.                 elif mac_exclusive == '01':
  462.                     mac_exclusive = "Yes"
  463.                 else:
  464.                     vendor_name = "Unknown"
  465.  
  466.                 text = 'Mac Address Info:'
  467.                 print text
  468.                 if filewrite == 1:
  469.                     fileHandle.write ( '\n'+text+'\n' )
  470.                 text = 'Exclusivity: '+str(mac_exclusive)
  471.                 print text
  472.                 if filewrite == 1:
  473.                     fileHandle.write ( text+'\n' )
  474.             else:
  475.                 text = '*** WARNING *** The Mac address exclusivity data is not in the correct format'
  476.                 print text
  477.                 print ''
  478.                 if filewrite == 1:
  479.                     fileHandle.write ( text+'\n' )
  480.  
  481.         else:
  482.             text = '*** WARNING *** The Mac address exclusivity data was not in the correct place'
  483.             print text
  484.             if filewrite == 1:
  485.                 fileHandle.write ( text+'\n' )
  486.     else:
  487.         text = '*** WARNING *** The Mac address exclusivity data was not present'
  488.         print text
  489.         print ''
  490.         if filewrite == 1:
  491.             fileHandle.write ( text+'\n' )
  492.  
  493. # Get the MAC address information
  494. def get_mac_addresses(response,header_length,fileHandle,filewrite):
  495.  
  496.     # Set counters and get working data
  497.     message_length = get_length(response,2,4)
  498.     mac_count = 0
  499.     current_length = message_length
  500.     working_response = response[header_length:header_length+message_length]
  501.  
  502.     # Work throught the data
  503.     while current_length > 0:
  504.  
  505.         # Search for the MAC Address information
  506.         mac_address = re.search('\x89',working_response)
  507.         if mac_address != None:
  508.             mac_length_pos = mac_address.start()
  509.  
  510.             # Get the length of the string in the right format
  511.             mac_length = working_response[mac_length_pos-1:mac_length_pos]
  512.             mac_length_hex = binascii.hexlify(mac_length)
  513.             mac_length_bytes = string.atoi(str(mac_length_hex),16)
  514.  
  515.             # Get the string itself
  516.             mac_addresses = working_response[mac_length_pos+1:mac_length_bytes+mac_length_pos-1]
  517.             mac_addresses = binascii.hexlify(mac_addresses)
  518.  
  519.             text = 'Address: '+mac_addresses[0:4]+'.'+mac_addresses[4:8]+'.'+mac_addresses[8:12]+' Mask: '+mac_addresses[12:16]+'.'+mac_addresses[16:20]+'.'+mac_addresses[20:24]
  520.             print text
  521.             if filewrite == 1:
  522.                 fileHandle.write ( text+'\n' ) 
  523.  
  524.             working_response = working_response[mac_length_pos+mac_length_bytes-1:current_length]
  525.             current_length = current_length-mac_length_bytes
  526.             mac_count = mac_count+1
  527.         else:
  528.             current_length = 0
  529.             if mac_count < 1:
  530.                 text = '*** NOTE *** No MAC address data was present'
  531.                 print text
  532.                 if filewrite == 1:
  533.                     fileHandle.write ( text+'\n' )
  534.  
  535. # Get the NetBIOS exclusivity
  536. def get_netbios_exclusivity(response,header_length,fileHandle,filewrite):
  537.  
  538.     # Search for the NetBIOS exclusivity
  539.     netbios_exclusive = re.search('\x88',response)
  540.  
  541.     if netbios_exclusive:
  542.         # Check the data is in the message not the header
  543.         version_length_pos = netbios_exclusive.start()
  544.  
  545.         if version_length_pos > header_length+4:
  546.             # Get the length of the string in the right format
  547.             version_length = response[version_length_pos-1:version_length_pos]
  548.             version_length_hex = binascii.hexlify(version_length)
  549.             version_length_bytes = string.atoi(str(version_length_hex),16)
  550.  
  551.             if version_length_bytes == 3:
  552.                 # Get the string itself
  553.                 netbios_exclusive = response[version_length_pos+1:version_length_pos+2]
  554.  
  555.                 netbios_exclusive = binascii.hexlify(netbios_exclusive)
  556.                 if netbios_exclusive == '00':
  557.                     netbios_exclusive = "No"
  558.                 elif netbios_exclusive == '01':
  559.                     netbios_exclusive = "Yes"
  560.                 else:
  561.                     vendor_name = "Unknown"
  562.  
  563.                 text = 'NetBIOS Name Info:'
  564.                 print ''
  565.                 print text
  566.                 if filewrite == 1:
  567.                     fileHandle.write ( '\n'+text+'\n' )
  568.                 text = 'Exclusivity: '+str(netbios_exclusive)
  569.                 print text
  570.                 if filewrite == 1:
  571.                     fileHandle.write ( text+'\n' )
  572.             else:
  573.                 text = '*** WARNING *** The NetBIOS exclusivity data is not in the correct format'
  574.                 print text
  575.                 if filewrite == 1:
  576.                     fileHandle.write ( text+'\n' )
  577.  
  578.         else:
  579.             text = '*** WARNING *** The NetBIOS exclusivity data was not in the correct place'
  580.             print text
  581.             if filewrite == 1:
  582.                 fileHandle.write ( text+'\n' )
  583.     else:
  584.         text = '*** WARNING *** The NetBIOS exclusivity data was not present'
  585.         print text
  586.         print ''
  587.         if filewrite == 1:
  588.             fileHandle.write ( text+'\n' )
  589.  
  590. # Get the NetBIOS names
  591. def get_netbios_names(response,header_length,fileHandle,filewrite):
  592.  
  593.     # Set counters and get working data
  594.     message_length = get_length(response,2,4)
  595.     netbios_count = 0
  596.     current_length = message_length
  597.     working_response = response[header_length:header_length+message_length]
  598.  
  599.     while current_length > 0:
  600.         # Search for the NetBIOS name information
  601.         netbios_name = re.search('\x8A',working_response)
  602.         if netbios_name != None:
  603.             netbios_length_pos = netbios_name.start()
  604.  
  605.             # Get the length of the string in the right format
  606.             netbios_length = working_response[netbios_length_pos-1:netbios_length_pos]
  607.             netbios_length_hex = binascii.hexlify(netbios_length)
  608.             netbios_length_bytes = string.atoi(str(netbios_length_hex),16)
  609.  
  610.             # Get the string itself
  611.             netbios_names = working_response[netbios_length_pos+1:netbios_length_bytes+netbios_length_pos-1]
  612.  
  613.             # Print the result out to screen
  614.             text = 'Name: '+str(netbios_names)
  615.             print text
  616.             if filewrite == 1:
  617.                 fileHandle.write ( text+'\n' )
  618.  
  619.             working_response = working_response[netbios_length_pos+netbios_length_bytes-1:current_length]
  620.             current_length = current_length-netbios_length_bytes
  621.             netbios_count = netbios_count+1
  622.         else:
  623.             current_length = 0
  624.             if netbios_count < 1:
  625.                 text = '*** NOTE *** No NetBIOS name data was present'
  626.                 print text
  627.                 if filewrite == 1:
  628.                     fileHandle.write ( text+'\n' )
  629.  
  630. # Get the supported SAP values
  631. def get_sap_support(response,header_length,fileHandle,filewrite):
  632.  
  633.     # Search for the SAP support
  634.     sap_support = re.search('\x86',response)
  635.  
  636.     # Check the data is in the message not the header
  637.     version_length_pos = sap_support.start()
  638.  
  639.     if version_length_pos > header_length+4:
  640.         # Get the length of the string in the right format
  641.         version_length = response[version_length_pos-1:version_length_pos]
  642.         version_length_hex = binascii.hexlify(version_length)
  643.         version_length_bytes = string.atoi(str(version_length_hex),16)
  644.  
  645.         if version_length_bytes == 18:
  646.             print ''
  647.             text = 'SAP Support:'
  648.             print text
  649.             if filewrite == 1:
  650.                 fileHandle.write ( '\n'+text+'\n' )
  651.             # Get the string itself
  652.             sap_support = response[version_length_pos+1:version_length_pos+17]
  653.             sap_number = 0
  654.             counter = 0
  655.             total = 0
  656.             while counter < 16:
  657.                 sap_supported = sap_support[counter:counter+1]
  658.                 sap_supported = binascii.hexlify(sap_supported)
  659.                 sap_supported = string.atoi(str(sap_supported),16)
  660.                 total = (sap_supported+1)/32 + total
  661.                 saparray = BitVector( intVal = sap_supported )
  662.                 counter2 = 0
  663.                 outputstring = ''
  664.                 while counter2 < 8:
  665.                     sapsupport = str(hex(sap_number))
  666.                     if saparray[counter2] == 0:
  667.                         sapvalue = "Off"
  668.                     else:
  669.                         sapvalue = "On"
  670.                     outputstring = outputstring+sapsupport+'='+sapvalue+' '
  671.                     if sap_number < 16:
  672.                         outputstring = outputstring+' '
  673.                     counter2 = counter2 + 1
  674.                     sap_number = sap_number + 2
  675.                 print outputstring
  676.                 if filewrite == 1:
  677.                     fileHandle.write ( outputstring+'\n' )
  678.                 counter = counter + 1
  679.  
  680.             text = 'Total SAPs allowed: '+str(total)+' / 128'
  681.             print text
  682.             if filewrite == 1:
  683.                 fileHandle.write ( text+'\n' )
  684.         else:
  685.             text = '*** WARNING *** The SAP support data is not in the correct format'
  686.             print text
  687.             print ''
  688.             fileHandle.write ( text+'\n\n' )
  689.  
  690.     else:
  691.         text = '*** WARNING *** The SAP support data was not in the correct place'
  692.         print text
  693.         print ''
  694.         fileHandle.write ( text+'\n\n' )
  695.  
  696.  
  697. #
  698. # Command Line Options
  699. #
  700.  
  701. parser = OptionParser()
  702. parser.add_option("-t", "--target", action="store", dest="target", metavar="TARGET", help="Target IP address or hostname (required)")
  703. parser.add_option("-o", "--outputfile", action="store", dest="outputfile", metavar="OUTPUTFILE", default="temp", help="Output file to write data to (defaults to dlsw_<target>.txt)")
  704. parser.add_option("-p", "--port", action="store", dest="port", type="int", default="2065", help="Port number to connect to and listen on (defaults to 2065)")
  705. parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Display more verbose informtaion")
  706. parser.add_option("-V", "--version", action="store", dest="version", default=1, type="choice", choices=["1","2"], help="Version to try 1 or 2 (defaults to version 2)")
  707. parser.add_option("-c", action="store_true", dest="complete", default=False, help="Attempt to complete the Capabilities Exchange (defaults to no)")
  708.  
  709. # Get the command line options
  710. (options, args) = parser.parse_args()
  711.  
  712. # Assign the rest of the inputs
  713. port = options.port
  714. version = options.version
  715. verbose = options.verbose
  716. complete = options.complete
  717.  
  718. # Mandate the use of a target
  719. parser.check_required("-t")
  720.  
  721. if options.target:
  722.     target = options.target
  723.     if verbose == True:
  724.         print 'TARGET:', target
  725. else:
  726.     sys.exit(0)
  727.  
  728. if port >= 0 and port < 65536:
  729.     pass
  730. else:
  731.     print 'Error, port number must be between 0 and 65535'
  732.     sys.exit(0)
  733.  
  734. # REVIEW THE USE OF THIS
  735. if options.outputfile != "temp":
  736.     outputfile = options.outputfile
  737.     filewrite = 1
  738. else:
  739.     outputfile = 'dlsw_'+target+'.txt'
  740.     filewrite = 0
  741.  
  742. # Open logfile for writing
  743. if filewrite == 1:
  744.     # SANITISE INPUT
  745.     # Open the log file for writing
  746.     try:
  747.         fileHandle = open ( outputfile, 'a' )
  748.         if verbose == True:
  749.             print 'Output will be written to logfile', outputfile
  750.     except Exception:
  751.         print 'Error opening output file', outputfile, 'for writing'
  752.         sys.exit(0)
  753. else:
  754.     fileHandle = 0
  755.  
  756. # Get the local time first
  757. datestring = time.ctime()
  758.  
  759. if filewrite == 1:
  760.     fileHandle.write ( '####################################################################\n' )
  761.     fileHandle.write ( 'TARGET: '+target+'\n' )
  762.     fileHandle.write ( 'PORT: '+str(port)+'\n' )
  763.     fileHandle.write ( 'DATE: '+datestring+'\n' )
  764.     fileHandle.write ( '####################################################################\n\n' )
  765.  
  766. # Set version to either 1 or 2
  767. #if version != 1:
  768. #    version = 2
  769.  
  770. # Add output for added verbosity
  771. if verbose == True:
  772.     print 'Verbose output selected'
  773.     if complete == True:
  774.         print 'DLSw handhsake will be completed'
  775.     else:
  776.         print 'DLSw handhsake will not be completed'
  777.  
  778.     print 'Version '+str(version)+' selected'
  779.     if filewrite == 1:
  780.         fileHandle.write ( 'Version '+str(version)+' selected' )
  781.  
  782. #
  783. # Socket definitions
  784. #
  785.  
  786. # Define socket for incoming data
  787. incoming = socket.socket ( socket.AF_INET,socket.SOCK_STREAM )
  788. try:
  789.     incoming.bind ( ( '', port ) )
  790.     incoming.listen ( 1 )
  791. except Exception:
  792.     print ''
  793.     print 'Error, cannot bind to local TCP port', port
  794.     if verbose == True:
  795.         print 'May need to wait for kernel to release socket'
  796.     print ''
  797.     sys.exit(0)
  798. else:
  799.     if verbose == True:
  800.         print 'Successfully bound to local TCP port', port
  801.         if filewrite == 1:
  802.             fileHandle.write ( 'Successfully bound to local TCP port '+str(port)+'\n' )
  803.  
  804. # Define socket for outgoing data
  805. outgoing = socket.socket ( socket.AF_INET,socket.SOCK_STREAM )
  806. try:
  807.     outgoing.connect ( ( target, port ) )
  808. except Exception:
  809.     print 'Error, cannot connect to host', target, 'on port', port
  810.     sys.exit(0)
  811. else:
  812.     if verbose == True:
  813.         print 'Connection suceeded to target host', target, 'on port', port
  814.         if filewrite == 1:
  815.             fileHandle.write ( 'Connection suceeded to target host '+target+' on port '+str(port)+'\n' )
  816.  
  817. #
  818. # Main program starts here
  819. #
  820.  
  821. # Get ready to receive response
  822. channel1, details = incoming.accept()
  823.  
  824. # Send Request to start the transaction
  825. if version == "1":
  826.     outgoing.send ( str(dlsw_request_v1) )
  827. else:
  828.     outgoing.send ( str(dlsw_request_v2) )
  829.  
  830. # Get ready to receive response
  831. #channel1, details = incoming.accept()
  832.  
  833. # Get the incoming Request from the target
  834. print 'Capabilities Exchange Request has been sent'
  835.  
  836.  
  837. if complete == True:
  838.  
  839.     # Send Response to peer down the incoming connection
  840.     channel1.send ( str(dlsw_response) )
  841.     print 'Capabilities Exchange Response has been sent'
  842.     if filewrite == 1:
  843.         fileHandle.write ( 'Full exchange was attempted\n\n' )
  844. else:
  845.     print 'Capabilities Exchange Response not sent'
  846.     if filewrite == 1:
  847.         fileHandle.write ( 'Full exchange was not attempted\n\n' )
  848.  
  849. # Close socket depending on version
  850. if version == "1":
  851.     pass
  852. #    channel1.close()
  853. elif version == "2":
  854.     outgoing.close()
  855. else:
  856.     channel1.close()
  857.     outgoing.close()
  858.     print 'Invalid version selected!'
  859.     sys.exit(1)
  860.  
  861. # Read in the Response packet
  862. response = packet_read(channel1,fileHandle,filewrite)
  863.  
  864. header_length = get_length(response,1,2)
  865.  
  866. # Check the packet is a Capabilities Exchange Response
  867. check_cap_packet_type(response,fileHandle,filewrite)
  868.  
  869. # Read in the Request packet
  870. response = packet_read(channel1,fileHandle,filewrite)
  871.  
  872. header_length = get_length(response,1,2)
  873.  
  874. # Check the packet is a Capabilities Exchange Request
  875. check_cap_packet_type(response,fileHandle,filewrite)
  876. print ''
  877.  
  878. # Parse and output all the data from the target
  879. get_dlsw_version(response,header_length,fileHandle,filewrite)
  880. get_tcp_connections(response,header_length,fileHandle,filewrite)
  881. get_vendor_oui(response,header_length,fileHandle,filewrite)
  882. get_multicast(response,header_length,fileHandle,filewrite)
  883. get_pacing(response,header_length,fileHandle,filewrite)
  884. get_mac_exclusivity(response,header_length,fileHandle,filewrite)
  885. get_mac_addresses(response,header_length,fileHandle,filewrite)
  886. get_netbios_exclusivity(response,header_length,fileHandle,filewrite)
  887. get_netbios_names(response,header_length,fileHandle,filewrite)
  888. get_sap_support(response,header_length,fileHandle,filewrite)
  889.  
  890. if filewrite == 1:
  891.     # Close the log file
  892.     fileHandle.close()
  893.  
  894. # Close socket depending on version
  895. if version == "1":
  896.      pass
  897. #    outgoing.close()
  898. elif version == "2":
  899.     channel1.close()
  900. else:
  901.     outgoing.close()
  902.     channel1.close()
  903.     sys.exit(1)
  904.  
  905. # Explicit exit call
  906. sys.exit(0)
  907.  
  908.