#!/opt/local/bin/python # (c) Adam Pridgen adam.pridgen@thecoverofnight.com # GPL v3 i # # # This 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 version 2 of the License. # # This 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; if not, write to the Free Software Foundation, Inc., 51 # Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or jfgi from optparse import OptionParser from subprocess import * from scapy.all import * import sys, socket, random, time from time import sleep, time tcp_ports = [22,21,23,25, 79, 80, 110, 113, 119, 135, 137, 139, 143, 389, 443, 445, 1443, 3306, 1521, 8080] tcp_ports = [22] def sr_all(pkts,iface=None, timeout=-1): s=conf.L3socket(iface=iface) a,b,c=sndrcv(s,pkts,inter=4,timeout=timeout, verbose=0) s.close() return a,b def get_random_payload(): permute = "".join([chr(random.randint(0, 128)) for i in xrange(0, random.randint(1, 1300))]) return permute def get_random_item(list_): if len(list_) == 0: return None,list_ indx = randint.randint(0, len(list_)-1) item = list_[indx] list_.remove(item) return item, list_ def get_timestamp(): from datetime import datetime from time import mktime t = datetime.now() return mktime(t.timetuple())+1e-6*t.microsecond def build_packets(host, ports): pkts = [] ip = IP(id=RandShort(), flags=0x2, dst=host) tcp = TCP( sport=RandShort(), seq=RandInt())#, ack=RandInt()) ether = Ether() for i in ports: tcp.dport = i tcp.window = 65535 tcp.options = [('MSS', 1460), ('NOP', None), ('WScale', 3),('NOP', None),('NOP', None), ('SAckOK', ''), ] tcp.payload = get_random_payload()[0:1200] pkt = ether/ip/tcp pkts.append(pkt) return pkts def perform_scapy_scan(host, ports, iface, timeout=10 ): port_res = [] closed = [] opened = [] pkts = build_packets(host, ports) ans,unans = sr_all(pkts,timeout=timeout, iface=iface) if ans is None: return [] for s,r in ans: if r[TCP].flags & 0x04 or\ r[TCP].flags & 0x10: opened.append(r[TCP].sport) else: closed.append(r[TCP].sport) r.show() return opened,closed def read_progress(out): scanned_hosts = [] progress = out.readlines() for i in progress: if i == "": continue scanned_hosts(i.split()[0]) return set(scanned_hosts) def scan_hosts(hosts, ports, fname=None, iface=None, timeout=10): stringify = lambda l:", ".join(map(str, l)) progress = "scanned_hosts.txt" if fname: progress = fname out = file(progress, "wra") scanned_hosts = set() try: scanned_hosts = read_progress(out) except: pass while len(hosts) != 0: host, hosts = get_random_item(hosts) if host is None: break open, closed = perform_scapy_scan(host, ports, iface, timeout=timeout) if len(open) == 0 and len(closed) == 0: out.write("%s DOWN"%(host)) continue out.write("%s OPENED:%s CLOSED:%s"%(host, stringify(open), stringify(closed))) print "%s OPENED:%s CLOSED:%s"%(host, stringify(open), stringify(closed)) scanned_hosts.add(host) return scanned_hosts def is_link(host): return host.find("://") > -1 def get_host_from_link(host): host = host.split("://")[1] return host.split("/")[0] def run_cmd(cmd_str): x = Popen(cmd_str.split(), stdout=PIPE ) return x.stdout.read() def has_answer(dig_str): if len(dig_str.split("ANSWER: ")) != 2: return False ans = int(dig_str.split("ANSWER: ")[1].split(",")[0]) return ans > 0 def get_ipaddrs(dig_str): ips = [] if not has_answer(dig_str): return [] res = dig_str.split("ANSWER SECTION:\n")[1].split("\n\n")[0] for r in res.split("\n"): if r != '' and\ r.split()[-2] == "A": ips.append(r.split()[-1]) return ips def run_dig_ips(host_str): dig_str = run_cmd("dig %s"%host_str) return get_ipaddrs(dig_str) def get_dict_list(d,itm): if itm in d: return d[itm] return [] def batch_dig(host_list): ip_results = {} for i in host_list: if i.strip() == '': continue if is_link(i): i = get_host_from_link(i) ips = run_dig_ips(i) x = get_dict_list(ip_results, i) if len(ips) == 0: x.append(i) ip_results[i] = x continue ip_results[i] = x + ips return ip_results def write_dig_results(results, fname=None): if fname is None: fname = "dig_results.txt" print "Writing dig results to: %s" out = open(fname, "wa") for key in results: s = key + " " + ",".join(results[key]) out.write(s+"\n") def write_whois_results(results, fname=None): if fname is None: fname = "dig_results.txt" print "Writing dig results to: %s" out = open(fname, "wa") for key in results: s = key + " " + ",".join(results[key]) out.write(s+"\n") def run_whois(host_str): whois_str = run_cmd("whois %s"%host_str) return get_netnums(whois_str) def get_netnums(whois_str): if not whois_str.find("inetnum:") > 0: return "" return whois_str.split("inetnum:")[1].split("\n")[0].strip() def perform_dig_whois(hosts, xname=None, lname=None): results = {} if lname is None: lname = "iplist.txt" iplist = open(lname, "wa") if xname is None: xname = "dig_whois_results.txt" out = open(xname, "wa") for host in hosts: if host.strip() == "": continue if is_link(host): host = get_host_from_link(host) print "*****Performing dig for: %s"%host ips = run_dig_ips(host) if len(ips) == 0: ips = [host] print "***Performing whois for: %s"%", ".join(ips) netnums = batch_whois(ips) ip_l = convert_netnums(netnums) s = host+ " " + ",".join(ips) + " " + ",".join(ip_l) print "*Results: %s"%s out.write(s+"\n") iplist.write("\n".join(ip_l)+"\n") results[host] = ip_l return results def batch_whois(host_list): nn_results = [] for i in host_list: if i.strip() == '': continue net_num = run_whois(i) if net_num == "": continue nn_results.append(net_num) sleep(3) nn_set = set(nn_results) return [i for i in nn_set] def getnamebyaddr(ip): try: r = socket.gethostbyaddr(ip) return r[0] except socket.error: return None def perform_host(ip, timeout=3, nameserver="", hargs=""): host_str = "host %s %s %s"%(hargs, ip, nameserver) result = run_cmd(host_str) if result.find("not found") > -1: return None return get_host_names(result) def get_host_names(host_result): r = host_result.splitlines() n = set() for k in r: if k == "":continue name = k.split()[-1] name = ".".join(name.split('.')[:-1]) n.add(name) return ",".join(n) def batch_getnames(ips, filename=None): completed = set() results = {} out = None if filename: out = open(filename,"a+r") out.write("\n") out.seek(0) lines =out.readlines() out.seek(0, os.SEEK_END) completed = read_hosts_progress(lines) ips = [i for i in set(ips)] for ip in ips: if ip in completed: continue print "Executing host for: %s"%ip result = perform_host(ip) completed.add(ip) if result: print "****Got result: %s"%result results[ip] = result if out: out.write("%s %s\n"%(ip,result)) else: if out: out.write("%s NONE\n"%(ip)) print "****No Resolution" return results def read_hosts_progress(hosts_list): completed = set() for i in hosts_list: if i.strip() == "": continue completed.add(i.split()[0].strip()) return completed def batch_host(ips, filename=None, timeout=3): completed = set() results = {} out = None if filename: out = open(filename,"a+r") out.write("\n") out.seek(0) lines =out.readlines() out.seek(0, os.SEEK_END) completed = read_hosts_progress(lines) ips = [i for i in set(ips)] for ip in ips: if ip in completed: continue print "Executing host for: %s"%ip result = perform_host(ip, timeout) completed.add(ip) if result: print "****Got result: %s"%result results[ip] = result if out: out.write("%s %s\n"%(ip,result)) else: if out: out.write("%s NONE\n"%(ip)) print "****No Resolution" return results def write_ips_names(ip_dict, filename=None): if not filename: filename = "ips_names.txt" out = open(filename, "a") for ip in ip_dict: out.write("%s %s\n"%(ip,ip_dict[ip])) def get_ips(IP_RANGE): ''' getips(IPRange) example usage: IP_RANGE = '192.168.1.1-50' x = getips(IP_RANGE) for ip in x: print x ''' string_add = lambda l,i: l.append(socket.inet_ntoa(int_to_str(i))) # this check to make sure all the values are digits and not other # stuff. if not IP_RANGE.replace("-",".").replace(".","").isdigit(): return [IP_RANGE] def str_to_int(s): i = ord(s[0]) << 24 i += ord(s[1]) << 16 i += ord(s[2]) << 8 i += ord(s[3]) return i def int_to_str(i): s = [0,0,0,0] s[0]= chr((i&0xFF000000) >> 24) s[1]= chr((i&0x00FF0000) >> 16) s[2]= chr((i&0x0000FF00) >> 8 ) s[3]= chr((i&0x000000FF) ) return "".join(s) octets = IP_RANGE.split(".") print octets if len(octets) != 4: return [IP_RANGE] octet_strs = [] x = [] y = [] for i in octets: if i.find("-") > -1: y.append(i.split("-")[1]) x.append(i.split("-")[0]) else: y.append(i) x.append(i) x_int = str_to_int(socket.inet_aton(".".join(x))) y_int = str_to_int(socket.inet_aton(".".join(y))) while x_int <= y_int: string_add(octet_strs, x_int) x_int += 1 return octet_strs def fmt_netnum(inetnum): nn = [] x,y = split_split(inetnum) join = lambda x,yi,ind: x[ind]+"-"+y[ind] compare = lambda x,y,ind: x[ind] == y[ind] for i in xrange(0,4): if compare(x,y,i): nn.append(x[i]) else: nn.append(join(x,y,i)) return ".".join(nn) def split_split(inetnum): x,y = inetnum.split(" - ") return x.split("."), y.split(".") def convert_netnums(nn_list): nnn_list = [] for i in nn_list: if i.find(" - ") > 0: nnn_list.append(fmt_netnum(i)) else: nnn_list.append(i) nnn_set = set(nnn_list) return [i for i in nnn_set] usage = "usage: %prog [options] arg" parser = OptionParser(usage) parser.add_option("-p", "--write_iplist", dest="final_targets", help="file where final ip list will be written too", metavar="FILE") parser.add_option("-f", "--file", dest="hostfile", help="file containing host names to enumerate", metavar="FILE") parser.add_option("-e", "--iface", dest="iface", help="specify interface to use for scanning") parser.add_option("-s", "--scan", dest="perform_scan", action="store_true", help="perform a scan using scapy.") parser.add_option("-d", "--d", dest="dig_host", action="store_true", help="specify whether to dig the hosts in the file") parser.add_option("-w", "--whois", dest="whois_host", action="store_true", help="specify whether to enumerate the network IPs") parser.add_option("-r", "--resume", dest="resume_file", help="file used to maintain state of the quick scan", metavar="FILE") def write_final_targets(targets ,fname= None): if fname is None: fname = "iplist_scan.txt" f = open(fname, 'wa') f.write("\n".join(targets)+'\n') def run_dig_whois(fname): strip = lambda x: x.strip() targets = open(fname).readlines() targets = map(strip, targets) results = perform_dig_whois(targets) for host in results: targets += results[host] ft = [] for i in map(getips,targets): ft += i return ft def main(args): (options, args) = parser.parse_args() if not options.hostfile: parser.error("Must specify a file containing hostnames or ip addresses") strip = lambda x: x.strip() ips = [] targets = [] if options.dig_host and options.whois_host and options.hostfile: print "Using dig to enumerate the links then perform whois from: %s"%options.hostfile targets = open(options.hostfile).readlines() targets = map(strip, targets) results = perform_dig_whois(targets) for host in results: targets += results[host] ft = [] for i in map(getips,targets): ft += i write_final_targets(ft) elif options.dig_host and options.hostfile: print "Using dig to enumerate the links from : %s"%options.hostfile targets = batch_dig(open(options.hostfile).readlines()) ft = [] for i in map(getips,targets): ft += i write_final_targets(ft) elif options.hostfile and options.whois_host: print "Skipping the dig enumeration and reading IPs from: %s"%options.hostfile ips = open(options.hostfile).readlines() print "Using whois to enumerate more hosts and networks." ips = map(strip, ips) netnums = batch_whois(ips) targets = convert_netnums(ips) ft = [] for i in map(getips,targets): ft += i write_final_targets(ft) elif options.hostfile: targets = open(options.hostfile).readlines() else: parser.error("at least a list of ips or host names are required!") final_targets = [] for i in map(getips,targets): final_targets += i if options.perform_scan: print "Proceeding with the scan." scanned_hosts = scan_hosts(final_targets, tcp_ports, options.iface, options.resume_file) print "Scanned the following hosts:" for i in scanned_hosts: print i if __name__ == "__main__": main(sys.argv)