/mongol.py
Python | 195 lines | 190 code | 3 blank | 2 comment | 1 complexity | c2fc477eb096d15c060d76eea67f05f1 MD5 | raw file
- #!/usr/bin/env python
- import socket
- import logging
- import sys, getopt, time
- logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
- from scapy.all import *
- # a few silly globals
- debug = True
- MESSAGE = "GET %s HTTP/1.1" + "\x0d\x0a" + "Host: %s" + "\x0d\x0a\x0d\x0a"
- port = 80
- inputfile = ""
- outputfile = "output.txt"
- Keyword = "tibetalk"
- def usage():
- print "Mongol.py: A tool for pin pointing the ip addresses of the great firewall"
- print " of China, keyword filtering devcies/mirror routers"
- print ""
- print "usage (as root): python mongol.py -i hostslist.txt -o outputfilename.txt [-k KEYWORD]"
- print "\t-i hostlist.txt: required newline seperated list of hosts to scan"
- print "\t-o outputfile.txt: File to write data out too"
- print "\t-h: Show this message"
- print "\t-k KEYWORD: Overwrite the default keyword of 'tibet@lk'"
- # Basically a slightly modified traceroute
- def ackattack(host):
- port = RandNum(1024,65535)
- # build a simple ACK packet, using a range (1,255) for the ttl creates 255 packets
- # TODO: fix so that it can be operated behind a NAT, attempted with seq=0 and ack=0
- ack = IP(dst=host, ttl=(1,255))/TCP(sport=port, dport=80, flags="A", seq=0, ack=0)
-
- # send packets and collect answers
- ans,unans = sr(ack, timeout=4, verbose=1)
- iplist = []
- retdata = ""
- for snd,rcv in ans:
- #print rcv.summary()
- endpoint = isinstance(rcv.payload, TCP)
- #retdata += "%s %s %s\n" % (snd.ttl,rcv.src,endpoint)
- retdata += "%s\n" % (rcv.src)
- iplist.append(rcv.src)
- if endpoint:
- break
-
- return retdata, iplist
- # parse arguments
- try:
- opts, args = getopt.getopt(sys.argv[1:],"hi:o:k:")
- except getopt.GetoptError:
- usage()
- sys.exit(1)
- for opt, arg in opts:
- if opt == "-h":
- usage()
- sys.exit(0)
- elif opt == "-i":
- inputfile = arg
- elif opt == "-o":
- outputfile = arg
- elif opt == "-k":
- Keyword = arg
- # read the hostnames in from the inputfile
- if not inputfile:
- usage()
- print "ERROR: Please select an input file of hostnames, one hostname per line"
- sys.exit(1)
- hostnames = []
- fd = open(inputfile, "r")
- hosts = fd.readlines()
- for addr in hosts:
- hostnames.append(addr.rstrip("\n"))
- # empty list of found firewalls
- firewalls = []
- fdout = open(outputfile, "w")
- for host in hostnames:
- # first we create a real handshake and send the censored term
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-
- # why 5 seconds? idk you got a better idea?
- s.settimeout(5)
- # make sure we can resolve the host
- try:
- ipaddr = socket.gethostbyname(host)
- except socket.gaierror:
- print "Could not resolve " + host
- continue
- # make sure the host is up
- try:
- s.connect((ipaddr, port))
- except socket.timeout:
- print "connection to " + host + " has timed out moving on"
- continue
- except socket.error:
- print "connection failed, moving on"
- continue
- s.send(MESSAGE % ("/", host))
-
- try:
- response = s.recv(1024)
- except socket.timeout:
- print "connection to " + host + " has timedout moving on, Possibly not a webserver"
- continue
- except socket.error:
- print "RST: Possibly already blocked"
- continue
- s.close()
- # TODO: implement other valid response codes, this is a hack.
- if response.find("200 OK") != -1 or response.find("302 Redirect") != -1 or response.find("401 Unauthorized") != -1:
- # get a non firewalled ACK trace.
- noFWprint, noFWlist = ackattack(ipaddr)
- # http://en.wikipedia.org/wiki/List_of_blacklisted_keywords_in_the_People%27s_Republic_of_China
- print "Sending stimulus"
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.settimeout(5)
- try:
- s.connect((ipaddr, port))
- except socket.timeout:
- print "connection to " + host + " has timedout moving on"
- continue
- except socket.error:
- print "connection to " + host + " has timedout moving on"
- continue
- s.send(MESSAGE % ("/"+Keyword, host) )
- # possibly a delay from the IDS to reaction time
- time.sleep(3)
- try:
- response = s.recv(1024)
- except socket.error:
- print "Found a filter\n\n"
- # get a firewalled trace
- FWprint, FWlist = ackattack(ipaddr)
- if debug:
- print "\n\nIPADDR: " + ipaddr
- print "Without FW:"
- print noFWprint
- print "\n\nWith FW:"
- print FWprint
-
- filterIP = FWlist[-2]
- # we only check the first 3 octecs because of variation in the routers depending on
- # firewall status
- # fuck regex's
- shortip = filterIP.split(".")
- shortip = "%s.%s.%s." % (shortip[0], shortip[1], shortip[2])
- print "shortip: " + shortip
- # add the firewall's IP to the list to be written out if it does not already exist
- if filterIP not in firewalls:
- firewalls.append(filterIP)
- fdout.write(filterIP + "\n")
- fdout.flush()
- if shortip in noFWlist:
- hopsdiff = noFWlist.index(filterIP) - FWlist.index(filterIP)
- print "Guess: " + filterIP
- print "IP block: " + shortip
- print "Hops diff: " + str(hopsdiff)
- else:
- print "Guess: " + filterIP
- else:
- print "Appears not to be blocking"
- else:
- print "Bad response code from " + host
- #print response
- continue
- s.close()
- fdout.close()