# (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]