├── LICENSE ├── Main.py ├── MsfConsole.py ├── README.md ├── ReadInputThread.py ├── daemon-scripts ├── rc.local ├── runAtopwn.bash └── start-msfrcpd.bash └── resources └── autopwn.rc /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Luis Hebendanz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | 24 | -------------------------------------------------------------------------------- /Main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | try: 4 | import time 5 | import sys 6 | import threading 7 | from optparse import OptionParser 8 | from ReadInputThread import ReadInputThread 9 | except ImportError as msg: 10 | print "[-] Library not installed: " + str(msg) 11 | print "[*] Try installing it with: pip install " + str(msg.message) 12 | sys.exit() 13 | 14 | try: 15 | try: 16 | import readline 17 | except ImportError: 18 | import pyreadline as readline 19 | except ImportError: 20 | print "[-] Readline module is not installed!" 21 | print "[*] Install on Linux with: pip install readline" 22 | print "[*] Install on Windows with: pip install pyreadline" 23 | sys.exit() 24 | 25 | try: 26 | from MsfConsole import MsfConsole 27 | from metasploit.msfrpc import MsfRpcError 28 | except ImportError as msg: 29 | print "[-] Missing library pymetasploit" 30 | print "[*] Please clone from \"git clone https://github.com/allfro/pymetasploit.git pymetasploit\"" 31 | print "[*] \"cd pymetasploit && sudo python setup.py install\"" 32 | sys.exit() 33 | 34 | # 35 | class Main: 36 | # Hardcoded credentials 37 | username = "msf" 38 | password = "msf" 39 | port = 55553 40 | host = "127.0.0.1" 41 | ssl = True 42 | 43 | # Variables 44 | msfconsole = None 45 | 46 | def __init__(self): 47 | ### 48 | # Command line argument parser 49 | ### 50 | parser = OptionParser() 51 | parser.add_option("-r", "--resource", action="store", type="string", dest="resource", help="Path to resource file") 52 | parser.add_option("-u", "--user", action="store", type="string", dest="username", help="Username specified on msfrpcd") 53 | parser.add_option("-p", "--pass", action="store", type="string", dest="password", help="Password specified on msfrpcd") 54 | parser.add_option("-s", "--ssl", action="store_true", dest="ssl", help="Enable ssl") 55 | parser.add_option("-P", "--port", action="store", type="string", dest="port", help="Port to connect to") 56 | parser.add_option("-H", "--host", action="store", type="string", dest="host", help="Server ip") 57 | parser.add_option("-c", "--credentials", action="store_true", dest="credentials", help="Use hardcoded credentials") 58 | parser.add_option("-e", "--exit", action="store_true", dest="exit", help="Exit after executing resource script") 59 | (options, args) = parser.parse_args() 60 | 61 | if len(sys.argv) is not 1 and options.credentials is None: 62 | if options.username is not None: 63 | self.username = options.username 64 | else: 65 | print "[*] Use default: username => msf" 66 | self.username = "msf" 67 | 68 | if options.password is not None: 69 | self.password = options.password 70 | else: 71 | print "[*] Use default: password => msf" 72 | self.password = "msf" 73 | 74 | if options.ssl is True: 75 | self.ssl = True 76 | else: 77 | print "[*] Use default: ssl => False" 78 | self.ssl = False 79 | 80 | if options.port is not None: 81 | self.port = options.port 82 | else: 83 | print "[*] Use default: port => 55553" 84 | self.port = 55553 85 | 86 | if options.host is not None: 87 | self.host = options.host 88 | else: 89 | print "[*] Use default: host => 127.0.0.1" 90 | self.host = "127.0.0.1" 91 | else: 92 | if self.host and self.port and self.password and self.ssl and self.username is None: 93 | print "[-] You have to specify all hardcoded credentials" 94 | sys.exit() 95 | print "[*] Using hardcoded credentials!" 96 | 97 | # Objects 98 | self.msfconsole = MsfConsole(self.username, self.password, self.port, self.host, self.ssl) 99 | 100 | # Connect to msfrpcd 101 | if self.msfconsole.connect() is False: 102 | sys.exit() 103 | 104 | # If -r flag is given 105 | if options.resource is not None: 106 | self.msfconsole.load_resource(options.resource) 107 | time.sleep(3) 108 | 109 | if options.exit is True: 110 | self.msfconsole.disconnect() 111 | sys.exit() 112 | 113 | # Add directory auto completion 114 | readline.parse_and_bind("tab: complete") 115 | 116 | # Go to main menu 117 | self.exec_menu('main_menu') 118 | 119 | # Executes menu function 120 | def exec_menu(self, choice): 121 | # If empty input immediately go back to main menu 122 | if choice == '': 123 | self.menu_actions['main_menu'](self) 124 | else: 125 | # Execute selected function out of dictionary 126 | try: 127 | self.menu_actions[choice](self) 128 | # If given input isn't in dictionary 129 | except KeyError: 130 | print '[-] Invalid selection, please try again.' 131 | time.sleep(1) 132 | self.menu_actions['main_menu'](self) 133 | 134 | # Main Menu 135 | def main_menu(self): 136 | try: 137 | # Create read thread 138 | readThread = ReadInputThread(self.msfconsole.get_path()) 139 | readThread.start() 140 | 141 | try: 142 | while True: 143 | # Get command user types in 144 | command = readThread.get_command() 145 | 146 | # If command is not empty break out of loop 147 | if command: 148 | break 149 | 150 | # Run in background and read possible output from msfrpcd 151 | if self.msfconsole.read_output(): 152 | # Found data to read 153 | readThread.set_path(self.msfconsole.get_path()) 154 | except ValueError: 155 | pass 156 | 157 | if command == "quit": 158 | self.msfconsole.disconnect() 159 | sys.exit() 160 | # If command not empty send it to msfrpcd 161 | if command: 162 | self.msfconsole.exec_command(command) 163 | 164 | # Go to this menu again 165 | self.exec_menu('main_menu') 166 | 167 | # Connection is only valid for 5 minutes afterwards request another one 168 | except MsfRpcError: 169 | print "[*] API token expired requesting new one..." 170 | if self.msfconsole.connect() is False: 171 | sys.exit() 172 | self.exec_menu('main_menu') 173 | except KeyboardInterrupt: 174 | self.msfconsole.disconnect() 175 | sys.exit() 176 | 177 | # Dictionary of menu entries 178 | menu_actions = { 179 | 'main_menu': main_menu 180 | } 181 | 182 | # Execute main 183 | try: 184 | Main() 185 | except KeyboardInterrupt: 186 | print "[*] Interrpted execution" 187 | exit(0) 188 | 189 | except AttributeError: 190 | print "[-] You have to be connected to the server " + str(msg) 191 | exit(1) -------------------------------------------------------------------------------- /MsfConsole.py: -------------------------------------------------------------------------------- 1 | import time 2 | import socket 3 | import string 4 | from metasploit.msfrpc import MsfRpcClient 5 | from metasploit.msfrpc import MsfRpcError 6 | from ssl import SSLError 7 | 8 | # 9 | class MsfConsole: 10 | 11 | # Objects 12 | client = None 13 | console = None 14 | 15 | # Variables 16 | console_id = "" 17 | 18 | def __init__(self, username, password, port, host, ssl): 19 | self.username = username 20 | self.password = password 21 | self.port = port 22 | self.host = host 23 | self.ssl = ssl 24 | 25 | # Connect to the msfrpcd server 26 | def connect(self): 27 | print "[*] Connecting to server:\n Host => %s,\n Port => %s,\n User => %s,\n " \ 28 | "Pwd => %s,\n SSL => %s\n" % (self.host, self.port, self.username, '*' * len(self.password), self.ssl) 29 | # Login to msfrpcd server 30 | try: 31 | kwargs = {'username': self.username, 'port': self.port, 'server': self.host, 'ssl': self.ssl} 32 | self.client = MsfRpcClient(self.password, **kwargs) 33 | print "[+] Successfully connected" 34 | except SSLError, msg: 35 | print "[-] SSL error: " + str(msg) 36 | print "[-] You probably have installed the wrong pymetasploit version try installing it from here: https://github.com/allfro/pymetasploit.git" 37 | return False 38 | except socket.error, msg: 39 | print "[-] Couldn't connect to server: " + str(msg) 40 | return False 41 | except MsfRpcError: 42 | print "[-] Login failed. Wrong username or password" 43 | return False 44 | # Create console and id 45 | self.console = self.client.consoles.console() 46 | self.console_id = self.console.cid 47 | print "[*] Console id: " + self.console_id 48 | # Read msf banner 49 | self.read_output() 50 | return True 51 | 52 | # Read the output from msfconsole 53 | def read_output(self): 54 | try: 55 | timer = 0 56 | while timer <= 5: 57 | # Request information from msfrpcd 58 | resource = self.client.call('console.read', self.console_id) 59 | 60 | # Check for printable information 61 | if len(resource['data']) > 1: 62 | print resource['data'] 63 | break 64 | 65 | # If msf command still running try requesting again 66 | if resource['busy']: 67 | time.sleep(0.2) 68 | timer += 0.2 69 | continue 70 | 71 | # If resource is not busy quit reading 72 | else: 73 | break 74 | 75 | if timer >= 3: 76 | print "[-] Server response timed out" 77 | return False 78 | 79 | return True 80 | except KeyError: 81 | print "[-] Has the console been destroyed ? " 82 | print resource if 'resource' in locals() else "Couldn't print error" 83 | return False 84 | 85 | # Load resource file and execute every command 86 | def load_resource(self, path_to_resource): 87 | # Read resource file 88 | try: 89 | print "[*] Reading resource file..." 90 | infile = open(path_to_resource, 'r') 91 | commands = infile.readlines() 92 | infile.close() 93 | except IOError: 94 | print "[-] Path to resource file not found" 95 | return False 96 | 97 | # Loop through every command and execute it 98 | print "[*] Number of commands to execute: " + str(len(commands)) 99 | for line in commands: 100 | self.console.write(line) 101 | self.read_output() 102 | print "[+] Finished executing resource script" 103 | 104 | # List created jobs 105 | self.list_jobs() 106 | return True 107 | 108 | # List running jobs 109 | def list_jobs(self): 110 | # Request list of running jobs 111 | resource = self.client.jobs.list 112 | 113 | # If no error occurred 114 | if "error" not in resource: 115 | print "[+] Listing jobs..." 116 | print resource 117 | return True 118 | 119 | # If error occurred 120 | elif "error" in resource: 121 | print "[-] An error has occurred in listing jobs.\n" 122 | print resource 123 | return False 124 | 125 | 126 | # Execute command in msfconsole 127 | def exec_command(self, command): 128 | self.console.write(command) 129 | self.get_path() 130 | self.read_output() 131 | return True 132 | 133 | 134 | # Disconnect from msfconsole 135 | def disconnect(self): 136 | print "[*] Closing session..." 137 | self.console.destroy() 138 | self.client.client.close() 139 | 140 | 141 | # Get current msfconsole path 142 | def get_path(self): 143 | # Request data from server 144 | resource = self.client.call('console.list') 145 | 146 | # Filter the path out of it 147 | for console in resource['consoles']: 148 | if console['id'] == self.console_id: 149 | s = console['prompt'] 150 | extracted_path = ''.join(c for c in s if c in string.printable) 151 | return extracted_path 152 | 153 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Not mantained 2 | This tool won't be mantained by me anymore. There are better alternatives from Rapid7 themselves as descrived here: 3 | [How to run metasploit remotley](https://metasploit.help.rapid7.com/docs/running-metasploit-remotely#section-running-metasploit-as-a-daemon) 4 | 5 | Example: 6 | 7 | To make msf commands viable from elsewhere then the metasploit-framework directory set the GEM_HOME variable. 8 | To find the necessary path cd into the metasploit-framework directory and execute: 9 | ``` 10 | $ rvm gemdir 11 | /usr/local/rvm/gems/ruby-2.5.1@metasploit-framework 12 | $ rvm use 2.5.1@metasploit-framework 13 | ``` 14 | 15 | 16 | To start Metasploit as a daemon, you need to run the msfd utility, which opens on port 55554 by default. 17 | ``` 18 | $ ./msfd -a 127.0.0.1 19 | ``` 20 | 21 | To connect to the daemon, use netcat like the following example: 22 | ``` 23 | $ nc 127.0.0.1 5554 24 | ``` 25 | 26 | 27 | # Description 28 | A remote msfconsole written in Python 2.7 to connect to the msfrcpd server of metasploit. 29 | This tool gives you the ability to load modules permanently as daemon on your server like autopwn2. 30 | Although it gives you the ability to remotely use the msfrpcd server it is recommended to use it locally with a ssh or mosh shell because certificate validation is not enabled. 31 | 32 | ### Features 33 | - Optimized delivery & execution of commands. 34 | - Has all msf commands implemented even future ones. This is possible through the structure of the rpc api. 35 | - Browse through your command history with the up and down arrow key. 36 | - It feels like the normal msfconsole! 37 | 38 | 39 | # How does it looks like ? 40 | ``` 41 | [*] Connecting to server: 42 | Host => myDomain.com, 43 | Port => 55553, 44 | User => msf, 45 | Pwd => ***, 46 | SSL => True 47 | 48 | [+] Successfully connected 49 | [*] Console id: 19 50 | , , 51 | / \ 52 | ((__---,,,---__)) 53 | (_) O O (_)_________ 54 | \ _ / |\ 55 | o_o \ M S F | \ 56 | \ _____ | * 57 | ||| WW||| 58 | ||| ||| 59 | 60 | 61 | =[ metasploit v4.12.22-dev-52b81f3 ] 62 | + -- --=[ 1577 exploits - 906 auxiliary - 272 post ] 63 | + -- --=[ 455 payloads - 39 encoders - 8 nops ] 64 | + -- --=[ Free Metasploit Pro trial: http://r-7.co/trymsp ] 65 | 66 | 67 | msf > 68 | ``` 69 | 70 | # How do I use it ? 71 | Usage: Main.py [options] 72 | ``` 73 | Options: 74 | -h, --help show this help message and exit 75 | -r RESOURCE, --resource=RESOURCE 76 | Path to resource file 77 | -u USERNAME, --user=USERNAME 78 | Username specified on msfrpcd 79 | -p PASSWORD, --pass=PASSWORD 80 | Password specified on msfrpcd 81 | -s, --ssl Enable ssl 82 | -P PORT, --port=PORT Port to connect to 83 | -H HOST, --host=HOST Server ip 84 | -c, --credentials Use hardcoded credentials 85 | -e, --exit Exit after executing resource script 86 | ``` 87 | With the -c option you can use the credentials hardcoded into Main.py feel free to change them so that you don't have to use the credential parameters all the time. 88 | 89 | With the -r option you specify a resource script to load from your computer into the console. 90 | 91 | 92 | 93 | ### Example: 94 | This will load a resource script and use the hardcoded credentials: 95 | ``` 96 | python Main.py -c -r /root/resource/handler/allHandlers.rc 97 | ``` 98 | This will log in to the msfrpcd server through command line arguments: 99 | ``` 100 | python Main.py --ssl --port 55553 --host 127.0.0.1 --user msf --pass msf 101 | ``` 102 | 103 | 104 | # How do I install it ? 105 | First you must have metasploit installed. If you can't use the installer because you have no graphical environment or whatever use this guide from rapid7: [Nightly installers](https://github.com/rapid7/metasploit-framework/wiki/Nightly-Installers). 106 | This will install all needed dependencies: 107 | ``` 108 | curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall && \ 109 | chmod 755 msfinstall && \ 110 | ./msfinstall 111 | ``` 112 | 113 | 114 | ``` 115 | git clone https://github.com/allfro/pymetasploit.git pymetasploit 116 | cd pymetasploit && sudo python setup.py install 117 | ``` 118 | 119 | Also don't forget to start your msfrpcd server: 120 | ``` 121 | cd metasploit-framework/ 122 | ruby msfrpcd -U msf -P msf -p 55553 123 | ``` 124 | 125 | And it's probably a good idea to start and connect to the postgresql database: 126 | By the way change the password in the echo line. 127 | ``` 128 | sudo update-rc.d postgresql enable 129 | sudo service postgresql start 130 | echo "create database msf;create user msf with password 'password';grant all privileges on database msf to msf;" > createdb_sql.txt 131 | sudo -u postgres /usr/bin/psql < /home/postgres/createdb_sql.txt 132 | ``` 133 | In Metasploit: 134 | ``` 135 | db_connect msf:password@127.0.0.1/msf 136 | ``` 137 | 138 | 139 | -------------------------------------------------------------------------------- /ReadInputThread.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import time 3 | 4 | 5 | class ReadInputThread (threading.Thread): 6 | 7 | command = "" 8 | path = "" 9 | lock = None 10 | stop_thread = False 11 | 12 | def __init__(self, path): 13 | self.lock = threading.Lock() 14 | self.path = path 15 | threading.Thread.__init__(self) 16 | 17 | def run(self): 18 | # Wait for user input 19 | temp_command = raw_input(self.get_path()) 20 | 21 | # If command empty set to None and raise exception in get_command 22 | if not temp_command: 23 | self.set_command(None) 24 | 25 | else: # Else save user typed command 26 | self.set_command(temp_command) 27 | 28 | def get_command(self): 29 | self.lock.acquire() 30 | try: 31 | if self.command == None: 32 | raise ValueError() 33 | 34 | return self.command 35 | finally: 36 | self.lock.release() 37 | 38 | def set_command(self, command): 39 | self.lock.acquire() 40 | try: 41 | self.command = command 42 | finally: 43 | self.lock.release() 44 | 45 | def set_path(self, path): 46 | self.lock.acquire() 47 | try: 48 | self.path = path 49 | finally: 50 | self.lock.release() 51 | 52 | 53 | def get_path(self): 54 | self.lock.acquire() 55 | try: 56 | return self.path 57 | finally: 58 | self.lock.release() 59 | 60 | -------------------------------------------------------------------------------- /daemon-scripts/rc.local: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # 3 | # /etc/rc.local 4 | # 5 | # This script is executed at the end of each multiuser runlevel. 6 | # Make sure that the script will "exit 0" on success or any other 7 | # value on error. 8 | # 9 | # In order to enable or disable this script just change the execution 10 | # bits. 11 | # 12 | # By default this script does nothing. 13 | 14 | exec 2> /tmp/rc.local.log # send stderr from rc.local to a log file 15 | exec 1>&2 # send stdout to the same log file 16 | set -x # tell sh to display commands before execution 17 | 18 | export PATH=$PATH:/usr/local/rvm/rubies/ruby-2.3.1/bin 19 | export GEM_HOME=/usr/local/rvm/gems/ruby-2.3.1@metasploit-framework 20 | bash /root/msf-remote-console/daemon-scripts/start-msfrpcd.bash & 21 | bash /root/msf-remote-console/daemon-scripts/runAutopwn.bash & 22 | 23 | exit 0 24 | -------------------------------------------------------------------------------- /daemon-scripts/runAtopwn.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | pid=0 3 | id=0 4 | echo "Checking to see if msfrpcd is running ..." 5 | while [ "${pid:-0}" == 0 ]; do 6 | pid=$(netstat -tpln | grep 0\.0\.0\.0:55553 | awk '{print $7}' | sed 's#/.*##') 7 | if [ "${pid:-0}" -ne 0 ]; 8 | then 9 | printf "%s\n" "$pid" 10 | echo "The Service was identified in $i seconds." 11 | sleep 3 12 | python /root/msf-remote-console/Main.py -e -c -r /root/msf-remote-console/resources/autopwn.rc 13 | fi 14 | if [ "$i" == 120 ]; 15 | then 16 | echo "Cannot determine if service came up." 17 | break 18 | fi 19 | let i=i+1 20 | sleep 1 21 | done -------------------------------------------------------------------------------- /daemon-scripts/start-msfrcpd.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ruby /root/git/metasploit-framework/msfrpcd -U msf -P msf -p 55553 3 | -------------------------------------------------------------------------------- /resources/autopwn.rc: -------------------------------------------------------------------------------- 1 | use auxiliary/server/browser_autopwn2 2 | set ShowExploitList true 3 | set VERBOSE true 4 | run -j --------------------------------------------------------------------------------