Created
February 2, 2013 18:59
-
-
Save ahappyforest/4698806 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment