PageRenderTime 47ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/mongol.py

https://bitbucket.org/yatwql/mongol
Python | 195 lines | 190 code | 3 blank | 2 comment | 1 complexity | c2fc477eb096d15c060d76eea67f05f1 MD5 | raw file
  1. #!/usr/bin/env python
  2. import socket
  3. import logging
  4. import sys, getopt, time
  5. logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
  6. from scapy.all import *
  7. # a few silly globals
  8. debug = True
  9. MESSAGE = "GET %s HTTP/1.1" + "\x0d\x0a" + "Host: %s" + "\x0d\x0a\x0d\x0a"
  10. port = 80
  11. inputfile = ""
  12. outputfile = "output.txt"
  13. Keyword = "tibetalk"
  14. def usage():
  15. print "Mongol.py: A tool for pin pointing the ip addresses of the great firewall"
  16. print " of China, keyword filtering devcies/mirror routers"
  17. print ""
  18. print "usage (as root): python mongol.py -i hostslist.txt -o outputfilename.txt [-k KEYWORD]"
  19. print "\t-i hostlist.txt: required newline seperated list of hosts to scan"
  20. print "\t-o outputfile.txt: File to write data out too"
  21. print "\t-h: Show this message"
  22. print "\t-k KEYWORD: Overwrite the default keyword of 'tibet@lk'"
  23. # Basically a slightly modified traceroute
  24. def ackattack(host):
  25. port = RandNum(1024,65535)
  26. # build a simple ACK packet, using a range (1,255) for the ttl creates 255 packets
  27. # TODO: fix so that it can be operated behind a NAT, attempted with seq=0 and ack=0
  28. ack = IP(dst=host, ttl=(1,255))/TCP(sport=port, dport=80, flags="A", seq=0, ack=0)
  29. # send packets and collect answers
  30. ans,unans = sr(ack, timeout=4, verbose=1)
  31. iplist = []
  32. retdata = ""
  33. for snd,rcv in ans:
  34. #print rcv.summary()
  35. endpoint = isinstance(rcv.payload, TCP)
  36. #retdata += "%s %s %s\n" % (snd.ttl,rcv.src,endpoint)
  37. retdata += "%s\n" % (rcv.src)
  38. iplist.append(rcv.src)
  39. if endpoint:
  40. break
  41. return retdata, iplist
  42. # parse arguments
  43. try:
  44. opts, args = getopt.getopt(sys.argv[1:],"hi:o:k:")
  45. except getopt.GetoptError:
  46. usage()
  47. sys.exit(1)
  48. for opt, arg in opts:
  49. if opt == "-h":
  50. usage()
  51. sys.exit(0)
  52. elif opt == "-i":
  53. inputfile = arg
  54. elif opt == "-o":
  55. outputfile = arg
  56. elif opt == "-k":
  57. Keyword = arg
  58. # read the hostnames in from the inputfile
  59. if not inputfile:
  60. usage()
  61. print "ERROR: Please select an input file of hostnames, one hostname per line"
  62. sys.exit(1)
  63. hostnames = []
  64. fd = open(inputfile, "r")
  65. hosts = fd.readlines()
  66. for addr in hosts:
  67. hostnames.append(addr.rstrip("\n"))
  68. # empty list of found firewalls
  69. firewalls = []
  70. fdout = open(outputfile, "w")
  71. for host in hostnames:
  72. # first we create a real handshake and send the censored term
  73. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  74. # why 5 seconds? idk you got a better idea?
  75. s.settimeout(5)
  76. # make sure we can resolve the host
  77. try:
  78. ipaddr = socket.gethostbyname(host)
  79. except socket.gaierror:
  80. print "Could not resolve " + host
  81. continue
  82. # make sure the host is up
  83. try:
  84. s.connect((ipaddr, port))
  85. except socket.timeout:
  86. print "connection to " + host + " has timed out moving on"
  87. continue
  88. except socket.error:
  89. print "connection failed, moving on"
  90. continue
  91. s.send(MESSAGE % ("/", host))
  92. try:
  93. response = s.recv(1024)
  94. except socket.timeout:
  95. print "connection to " + host + " has timedout moving on, Possibly not a webserver"
  96. continue
  97. except socket.error:
  98. print "RST: Possibly already blocked"
  99. continue
  100. s.close()
  101. # TODO: implement other valid response codes, this is a hack.
  102. if response.find("200 OK") != -1 or response.find("302 Redirect") != -1 or response.find("401 Unauthorized") != -1:
  103. # get a non firewalled ACK trace.
  104. noFWprint, noFWlist = ackattack(ipaddr)
  105. # http://en.wikipedia.org/wiki/List_of_blacklisted_keywords_in_the_People%27s_Republic_of_China
  106. print "Sending stimulus"
  107. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  108. s.settimeout(5)
  109. try:
  110. s.connect((ipaddr, port))
  111. except socket.timeout:
  112. print "connection to " + host + " has timedout moving on"
  113. continue
  114. except socket.error:
  115. print "connection to " + host + " has timedout moving on"
  116. continue
  117. s.send(MESSAGE % ("/"+Keyword, host) )
  118. # possibly a delay from the IDS to reaction time
  119. time.sleep(3)
  120. try:
  121. response = s.recv(1024)
  122. except socket.error:
  123. print "Found a filter\n\n"
  124. # get a firewalled trace
  125. FWprint, FWlist = ackattack(ipaddr)
  126. if debug:
  127. print "\n\nIPADDR: " + ipaddr
  128. print "Without FW:"
  129. print noFWprint
  130. print "\n\nWith FW:"
  131. print FWprint
  132. filterIP = FWlist[-2]
  133. # we only check the first 3 octecs because of variation in the routers depending on
  134. # firewall status
  135. # fuck regex's
  136. shortip = filterIP.split(".")
  137. shortip = "%s.%s.%s." % (shortip[0], shortip[1], shortip[2])
  138. print "shortip: " + shortip
  139. # add the firewall's IP to the list to be written out if it does not already exist
  140. if filterIP not in firewalls:
  141. firewalls.append(filterIP)
  142. fdout.write(filterIP + "\n")
  143. fdout.flush()
  144. if shortip in noFWlist:
  145. hopsdiff = noFWlist.index(filterIP) - FWlist.index(filterIP)
  146. print "Guess: " + filterIP
  147. print "IP block: " + shortip
  148. print "Hops diff: " + str(hopsdiff)
  149. else:
  150. print "Guess: " + filterIP
  151. else:
  152. print "Appears not to be blocking"
  153. else:
  154. print "Bad response code from " + host
  155. #print response
  156. continue
  157. s.close()
  158. fdout.close()