Skip to content

Instantly share code, notes, and snippets.

@ahappyforest
Created February 2, 2013 18:59
Show Gist options
  • Save ahappyforest/4698806 to your computer and use it in GitHub Desktop.
Save ahappyforest/4698806 to your computer and use it in GitHub Desktop.
#!/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