# (c) 2009-(to the end of time) Adam Pridgen adam.pridgen@thecoverofnight.com # GPL v3 # 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 . # # ==================== greetz ============================== # # Riley Porter wrote getips function for the Net Bios Collector Script # Special thanks to Philippe Biondi and the Scapy authors. # import sys from scapy.all import * from optparse import OptionParser from random import randint # Turn down the verbosity of scapy conf.verb = 0 def getips(IP_RANGE): ''' Original Author of this function is Riley Porter getips(IPRange) example usage: IP_RANGE = '192.168.1.1-50' x = getips(IP_RANGE) for ip in x: print x ''' List = [] IP_LIST = [] IP_RANGE = IP_RANGE.rsplit(".",2) # breaks up IP into a list with the Following Values ['192.168','1','1-50'] print IP_RANGE[1] if len(IP_RANGE[1].split("-",1)) ==2: #Checks if where range identifiers are located "-" for i in range(int(IP_RANGE[1].split("-",1)[0]),int(IP_RANGE[1].split("-",1)[1])+1,1): List.append(IP_RANGE[0]+"."+str(i)+".") for ip in List: for i in range(int(IP_RANGE[2].split("-",1)[0]),int(IP_RANGE[2].split("-",1)[1])+1,1): IP_LIST.append(ip+str(i)) return IP_LIST if len(IP_RANGE[1].split("-",1)) ==1: for i in range(int(IP_RANGE[2].split("-",1)[0]),int(IP_RANGE[2].split("-",1)[1])+1,1): IP_LIST.append(IP_RANGE[0]+"."+str(IP_RANGE[1].split("-",1)[0])+"."+str(i)) return IP_LIST def expand_host_range_file(host_range_file): hr = [] host_ranges = open(host_range_file).readlines() for i in host_ranges: hr.append(i.strip()) print hr ips_to_scan = [] f = [] for i in hr: f += getips(i) # uniquify ips = set() new_ip_list = [] for i in f: if not i in ips: ips.add(i) new_ip_list.append(i) g = open("expanded_"+host_range_file, 'w') g.write("\n".join(new_ip_list)) return new_ip_list def rtcp_ping_hosts(hosts, filename, ports=[80,53,3389], ppayload=None, to=1): results = {} progress_file = open(filename, "a") scanned_file = open(filenamei+"_scanned.txt", "a") while len(hosts) > 0: i = randint(0, len(hosts)-1) port = ports[randint(0, len(ports)-1)] a, up_host, hIPS, pOpen = tcp_ping_host(hosts[i], port, ppayload, to) p = "Closed" h = "" if pOpen: p = "Open" if hIPS: h = "FW?" if up_host: progress_file.write("%s %s %s\n"%(hosts[i], h, p)) results[hosts[i]] = [a , up_host, hIPS, pOpen] scanned_file.write("%s\n"%hosts[i]) print "Scanned Host: ","%s %s %s\n"%(hosts[i], h, p) i = hosts.pop(i) return results def tcp_ping_hosts(hosts, filename, ports=[80,53,3389], ppayload=None, to=1): results = {} print "Using the %s to get hosts"%(filename) print "Using the %s to get hosts"%(filename+"_scanned.txt") progress_file = open(filename, "a") scanned_file = open(filename+"_scanned.txt", "a") for i in hosts: port = ports[randint(0, len(ports)-1)] a, up_host, hIPS, pOpen = tcp_ping_host(i, port, ppayload, to) p = "Closed" h = "" if pOpen: p = "Open" if hIPS: h = "FW?" if up_host: progress_file.write("%s %s %s\n"%(i, p, h)) results[i] = [a , up_host, hIPS, pOpen] scanned_file.write("%s\n"%i) uphost = "UP" if not up_host: uphost = "DN" print "Scanned Host: ","%s %s %s %s\n"%(i, uphost, h, p) return results def get_hosts_to_scan(hosts_file,noscan_file=None): hosts = "".join(open(hosts_file).readlines()).split() if not noscan_file: return hosts noscan = "".join(open(noscan_file).readlines()).split() h = set(hosts) n = set(noscan) for i in noscan: if i in h: h.remove(i) hosts = [i for i in h] return hosts #p.haslayer(ICMP) and p.getlayer(ICMP).type == 3 def tcp_ping_host(host, port=80, ppayload=None, to=1): # host is the ip-address string # sport is the dst-port to scan from # seq number is current seq number of the packet # if we want to mix it up and add arbtrary payloads # simply make ppayload into a string, or a RandString(size, chars) p = IP(dst=host)/TCP(dport=port, sport=RandShort(), seq=RandShort()) if ppayload: p.payload = str(ppayload) pOpen = False hIPS = False # send a single packet and wait for to*1 Seconds for a response a = sr1(p, timeout=to) #p.show2() # if the answer,a, is None, the host did not respond # if a is a response, and it is ICMP and type == 1 # then the host is unreachable, port unreachable indicates # there may be a host there (UDP) type scan # a.haslayer(ICMP) checks if the packet has an ICMP layer # a.getlayer(ICMP) gets the instance of the layer and then # the fields for that layer can be referenced, e.g. # a.getlayer(ICMP).type lets us access the type field if a is None: return a, False, False, False elif a.haslayer(ICMP) and a.getlayer(ICMP).code != 3\ and a.getlayer(ICMP).type != 3: return a, False, False, False # 0x12 are the Syn-Ack in the flag fields of the TCP Segment pOpen = a.haslayer(TCP) and (a.getlayer(TCP).flags == 0x12) # try with a bad-sum # some IPS/IDS/Firewalls respond to all packets, so lets mix # it up and shoot a random/bad checksum at them # to do this we will take p and modify the chksum to be a random # short value and send it along (Idea was grabbed from nmap docs) t = p.getlayer(TCP) t.chksum = RandShort() b = sr1(p, timeout=to) # if we get a reply, its safe to say the host is FAIL # or its a security device. if not b is None: hIPS = True # fini. hope it was as fun for you as it was for mw. # Spent all day in the coffee shop on this one, yay! return a, True, hIPS, pOpen def set_parse_options(): parser = OptionParser() parser.add_option("-o", "--out", dest="base_outfile", help="output file where scan results are written. default is 'outfile_'+scanfile", metavar="FILE") parser.add_option("-e", "--expand", dest="expand", help="input file with host ips to be expanded. writes a file 'expanded_'+ that is used for scanning", metavar="FILE") parser.add_option("-p", "--ports", dest="ports", help="csv list of ports to randomly while scanning" ) parser.add_option("-t", "--timeout", dest="timeout", help="timeout to apply to the packets") parser.add_option("-s", "--scan", dest="scanfile", help="original file to be scanned with host expanded and ready to be scanned", metavar="FILE") parser.add_option("-n", "--noscan", dest="noscanfile", help="hosts already scanned or not to be scanned with host expanded and ready to be scanned", metavar="FILE") parser.set_defaults(noscanfile = None, base_outfile = None, expand = None, scanfile = None, timeout = "1", ports = "80") return parser def clean_ports(ports): p = ports.split(",") ports = [] for i in p: if i != '': ports.append(int(i)) return ports if __name__ == "__main__": parser = set_parse_options() (option, args) = parser.parse_args() scanfile = '' hosts = None if option.expand: hosts = expand_host_range_file(option.expand) scanfile = "expanded_"+option.expand elif option.scanfile and option.noscanfile: hosts = get_hosts_to_scan (option.scanfile, option.noscanfile) scanfile = option.scanfile elif option.scanfile: hosts = get_hosts_to_scan(option.scanfile, option.noscanfile) scanfile = option.scanfile else: parser.print_help() parser.error("scanfile or file with host-ips to be expanded must be specified") timeout = 1 prts = [] try: if option.timeout: timeout = int(option.timeout) except: parser.print_help() parser.error("Timeouts must be an integer value in seconds") try: if option.ports: prts = clean_ports(option.ports) except: parser.print_help() parser.error("Ports must be specified as a comma delimited string e.g. 80,53,3389") base_outfile = "outfile_"+ scanfile if option.base_outfile: base_outfile = option.base_outfile results = tcp_ping_hosts(hosts, base_outfile, ports=prts, to=timeout) print "Found the following Hosts that are up:" for host in results: print host, "Port Open: %s"%results[host][3], "Guarded: %s"%results[host][2]