Advertisement
Guest User

Untitled

a guest
Mar 31st, 2020
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.91 KB | None | 0 0
  1. import asyncio
  2. import json
  3. import logging
  4. import socket
  5. from geoip2.database import Reader
  6. import geoip2
  7. import aioredis
  8. from tanner.dorks_manager import DorksManager
  9. from tanner.config import TannerConfig
  10.  
  11.  
  12. class SessionAnalyzer:
  13.     def __init__(self, loop=None):
  14.         self._loop = loop if loop is not None else asyncio.get_event_loop()
  15.         self.queue = asyncio.Queue(loop=self._loop)
  16.         self.logger = logging.getLogger('tanner.session_analyzer.SessionAnalyzer')
  17.         self.attacks = ['sqli', 'rfi', 'lfi', 'xss', 'php_code_injection', 'cmd_exec', 'crlf']
  18. #        f = open('penis.txt','w')
  19.  #       f.write(str("DEBI:"))
  20.   #      f.close()
  21.  
  22.     async def analyze(self, session_key, redis_client):
  23.         session = None
  24.         await asyncio.sleep(1, loop=self._loop)
  25.         try:
  26.             session = await redis_client.get(session_key, encoding='utf-8')
  27.             session = json.loads(session)
  28.         except (aioredis.ProtocolError, TypeError, ValueError) as error:
  29.             self.logger.exception('Can\'t get session for analyze: %s', error)
  30.         else:
  31.             result = await self.create_stats(session, redis_client)
  32.             await self.queue.put(result)
  33.             await self.save_session(redis_client)
  34.  
  35.     async def save_session(self, redis_client):
  36.         while not self.queue.empty():
  37.             session = await self.queue.get()
  38.             s_key = session['snare_uuid']
  39.             del_key = session['sess_uuid']
  40.             try:
  41.                 await redis_client.zadd(s_key, session['start_time'], json.dumps(session))
  42.                 await redis_client.delete(*[del_key])
  43.             except aioredis.ProtocolError as redis_error:
  44.                 self.logger.exception('Error with redis. Session will be returned to the queue: %s', redis_error)
  45.                 self.queue.put(session)
  46.  
  47.  
  48.     def save_dict_to_file(dic):
  49.          f = open('dict.txt','w')
  50.          f.write(str(dic))
  51.          f.close()
  52.  
  53.     async def create_stats(self, session, redis_client):
  54.         sess_duration = session['end_time'] - session['start_time']
  55.         referer = None
  56.         if sess_duration != 0:
  57.             rps = session['count'] / sess_duration
  58.         else:
  59.             rps = 0
  60.         location_info = await self._loop.run_in_executor(
  61.             None, self.find_location, session['peer']['ip']
  62.         )
  63.         tbr, errors, hidden_links, attack_types = await self.analyze_paths(session['paths'],
  64.                                                                            redis_client)
  65.         attack_count = self.set_attack_count(attack_types)
  66.  
  67.         stats = dict(
  68.             sess_uuid=session['sess_uuid'],
  69.             peer_ip=session['peer']['ip'],
  70.             peer_port=session['peer']['port'],
  71.             location=location_info,
  72.             user_agent=session['user_agent'],
  73.             snare_uuid=session['snare_uuid'],
  74.             start_time=session['start_time'],
  75.             end_time=session['end_time'],
  76.             requests_in_second=rps,
  77.             approx_time_between_requests=tbr,
  78.             accepted_paths=session['count'],
  79.             errors=errors,
  80.             hidden_links=hidden_links,
  81.             attack_types=attack_types,
  82.             attack_count=attack_count,
  83.             paths=session['paths'],
  84.             cookies=session['cookies'],
  85.             referer=session['referer']
  86.         )
  87.  
  88.         owner = await self.choose_possible_owner(stats)
  89.         stats.update(owner)
  90.         save_dict_to_file(stats)
  91.     return stats
  92.  
  93.     @staticmethod
  94.     async def analyze_paths(paths, redis_client):
  95.         tbr = []
  96.         attack_types = []
  97.         current_path = paths[0]
  98.         dorks = await redis_client.smembers(DorksManager.dorks_key)
  99.  
  100.         for _, path in enumerate(paths, start=1):
  101.             tbr.append(path['timestamp'] - current_path['timestamp'])
  102.             current_path = path
  103.         tbr_average = sum(tbr) / float(len(tbr))
  104.  
  105.         errors = 0
  106.         hidden_links = 0
  107.         for path in paths:
  108.             if path['response_status'] != 200:
  109.                 errors += 1
  110.             if path['path'] in dorks:
  111.                 hidden_links += 1
  112.             if 'attack_type' in path:
  113.                 attack_types.append(path['attack_type'])
  114.         return tbr_average, errors, hidden_links, attack_types
  115.  
  116.     def set_attack_count(self, attack_types):
  117.         attacks = self.attacks.copy()
  118.         attacks.append('index')
  119.         attack_count = {k: 0 for k in attacks}
  120.         for attack in attacks:
  121.             attack_count[attack] = attack_types.count(attack)
  122.         count = {k: v for k, v in attack_count.items() if v != 0}
  123.         return count
  124.  
  125.     async def choose_possible_owner(self, stats):
  126.         owner_names = ['user', 'tool', 'crawler', 'attacker', 'admin']
  127.         possible_owners = {k: 0.0 for k in owner_names}
  128.         if stats['peer_ip'] == '127.0.0.1' or stats['peer_ip'] == '::1':
  129.             possible_owners['admin'] = 1.0
  130.         with open(TannerConfig.get('DATA', 'crawler_stats')) as f:
  131.             bots_owner = await self._loop.run_in_executor(None, f.read)
  132.         crawler_hosts = ['googlebot.com', 'baiduspider', 'search.msn.com', 'spider.yandex.com', 'crawl.sogou.com']
  133.         possible_owners['crawler'], possible_owners['tool'] = await self.detect_crawler(
  134.             stats, bots_owner, crawler_hosts
  135.         )
  136.         possible_owners['attacker'] = await self.detect_attacker(
  137.             stats, bots_owner, crawler_hosts
  138.         )
  139.         maxcf = max([possible_owners['crawler'], possible_owners['attacker'], possible_owners['tool']])
  140.  
  141.         possible_owners['user'] = round(1 - maxcf, 2)
  142.  
  143.         owners = {k: v for k, v in possible_owners.items() if v != 0}
  144.         return {'possible_owners': owners}
  145.  
  146.     @staticmethod
  147.     def find_location(ip):
  148.         reader = Reader(TannerConfig.get('DATA', 'geo_db'))
  149.         try:
  150.             location = reader.city(ip)
  151.             info = dict(
  152.                 country=location.country.name,
  153.                 country_code=location.country.iso_code,
  154.                 city=location.city.name,
  155.                 zip_code=location.postal.code,
  156.             )
  157.         except geoip2.errors.AddressNotFoundError:
  158.             info = "NA"  # When IP doesn't exist in the db, set info as "NA - Not Available"
  159.         return info
  160.  
  161.     async def detect_crawler(self, stats, bots_owner, crawler_hosts):
  162.         for path in stats['paths']:
  163.             if path['path'] == '/robots.txt':
  164.                 return (1.0, 0.0)
  165.         if stats['requests_in_second'] > 10:
  166.             if stats['referer'] is not None:
  167.                 return (0.0, 0.5)
  168.             if stats['user_agent'] is not None and stats['user_agent'] in bots_owner:
  169.                 return (0.85, 0.15)
  170.             return (0.5, 0.85)
  171.         if stats['user_agent'] is not None and stats['user_agent'] in bots_owner:
  172.             hostname, _, _ = await self._loop.run_in_executor(
  173.                 None, socket.gethostbyaddr, stats['peer_ip']
  174.             )
  175.             if hostname is not None:
  176.                 for crawler_host in crawler_hosts:
  177.                     if crawler_host in hostname:
  178.                         return (0.75, 0.15)
  179.             return (0.25, 0.15)
  180.         return (0.0, 0.0)
  181.  
  182.     async def detect_attacker(self, stats, bots_owner, crawler_hosts):
  183.         if set(stats['attack_types']).intersection(self.attacks):
  184.             return 1.0
  185.         if stats['requests_in_second'] > 10:
  186.             return 0.0
  187.         if stats['user_agent'] is not None and stats['user_agent'] in bots_owner:
  188.             hostname, _, _ = await self._loop.run_in_executor(
  189.                 None, socket.gethostbyaddr, stats['peer_ip']
  190.             )
  191.             if hostname is not None:
  192.                 for crawler_host in crawler_hosts:
  193.                     if crawler_host in hostname:
  194.                         return 0.25
  195.             return 0.75
  196.         if stats['hidden_links'] > 0:
  197.             return 0.5
  198.         return 0.0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement