Taras, List,

    I was reading through the whole rewritten-urls branch patch before
I merged into the trunk and realized that there are still a couple of
pending things and questions and we need to think about. Please read
the lines that start with "#APR" in the attached patch file. Thanks
and sorry to review this for the third time and still find new things
:(

Regards,
-- 
Andrés Riancho
Director of Web Security at Rapid7 LLC
Founder at Bonsai Information Security
Project Leader at w3af
Index: scripts/script-fuzzURLParts.w3af
===================================================================
--- scripts/script-fuzzURLParts.w3af    (revision 0)
+++ scripts/script-fuzzURLParts.w3af    (revision 4587)
@@ -0,0 +1,23 @@
+# This is a test for fuzzing URL parts!
+
+misc-settings
+set fuzzURLParts True
+back
+plugins
+output console,textFile
+output
+output config textFile
+set fileName output-w3af.txt
+set verbose True
+back
+output config console
+set verbose False
+back
+audit xss
+back
+target
+set target http://moth/w3af/core/fuzzURLParts/article/1
+back
+start
+assert len( kb.kb.getData('xss', 'xss') ) > 0
+exit
Index: core/controllers/miscSettings.py
===================================================================
--- core/controllers/miscSettings.py    (revision 4506)
+++ core/controllers/miscSettings.py    (working copy)
@@ -55,6 +55,7 @@
             cf.cf.save('fuzzableCookie', False )
             cf.cf.save('fuzzFileContent', True )
             cf.cf.save('fuzzFileName', False )
+            cf.cf.save('fuzzURLParts', False )
             cf.cf.save('fuzzFCExt', 'txt' )
             cf.cf.save('fuzzFormComboValues', 'tmb')
             cf.cf.save('autoDependencies', True )
@@ -104,6 +105,13 @@
         o3 = option('fuzzFileName', cf.cf.getData('fuzzFileName'), d3, 
'boolean', help=h3, 
                             tabid='Fuzzer parameters')
         
+        d16 = 'Indicates if w3af plugins will send fuzzed URL parts in order 
to find vulnerabilities'
+        h16 = 'For example, if the discovered URL is http://test/foo/bar/123, 
and fuzzURLParts'
+        h16 += ' is enabled, w3af will request among other things: '
+        h16 += 'http://test/foo/bar/<script>alert(document.cookie)</script> in 
order to find XSS.'
+        o16 = option('fuzzURLParts', cf.cf.getData('fuzzURLParts'), d16, 
'boolean', help=h16, 
+                            tabid='Fuzzer parameters')
+
         d4 = 'Indicates the extension to use when fuzzing file content'
         o4 = option('fuzzFCExt', cf.cf.getData('fuzzFCExt'), d4, 'string', 
tabid='Fuzzer parameters')
 
@@ -178,6 +186,7 @@
         ol.add(o13)
         ol.add(o14)
         ol.add(o15)
+        ol.add(o16)
         return ol
     
     def getDesc( self ):
@@ -194,6 +203,7 @@
         cf.cf.save('fuzzableCookie', optionsMap['fuzzCookie'].getValue() )
         cf.cf.save('fuzzFileContent', optionsMap['fuzzFileContent'].getValue() 
)
         cf.cf.save('fuzzFileName', optionsMap['fuzzFileName'].getValue() )
+        cf.cf.save('fuzzURLParts', optionsMap['fuzzURLParts'].getValue() )
         cf.cf.save('fuzzFCExt', optionsMap['fuzzFCExt'].getValue() )
         cf.cf.save('fuzzFormComboValues', 
optionsMap['fuzzFormComboValues'].getValue() )
         cf.cf.save('autoDependencies', 
optionsMap['autoDependencies'].getValue() )
Index: core/data/fuzzer/mutantUrlParts.py
===================================================================
--- core/data/fuzzer/mutantUrlParts.py  (revision 0)
+++ core/data/fuzzer/mutantUrlParts.py  (revision 4587)
@@ -0,0 +1,114 @@
+'''
+mutantUrlParts.py
+
+Copyright 2006 Andres Riancho
+
+This file is part of w3af, w3af.sourceforge.net .
+
+w3af is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation version 2 of the License.
+
+w3af is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with w3af; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+'''
+
+from core.data.fuzzer.mutant import mutant
+from core.controllers.w3afException import w3afException
+import urllib
+
+class mutantUrlParts(mutant):
+    '''

#APR: change to urlparts

+    This class is a urlpars mutant.
+    '''
+    def __init__( self, freq ):
+        mutant.__init__(self, freq)
+        
+        self._doubleEncoding = False
+        self._safeEncodeChars = ''
+        self._mutant_dc = {}
+
+    def getMutantType( self ):
+        return 'urlpars'
+
+    def setDoubleEncoding( self, trueFalse ):
+        self._doubleEncoding = trueFalse
+    
+    def setSafeEncodeChars( self, safeChars ):
+        '''
+        @parameter safeChars: A string with characters we don't want to URL 
encode in the urlpars. Example:
+            - '/&!'
+            - '/'
+        '''
+        self._safeEncodeChars = safeChars
+    
+    def getURL( self ):
+        '''
+        @return: The URL, as modified by "setModValue()"

#APR: I would like to see more doctests that represent the real use of this 
class. By that I mean that we should use
setModValue() in the doctest instead of "m._mutant_dc = divided_path". The 
ideal would be to use it just like in fuzzer.py

+        >>> from core.data.parsers.urlParser import url_object
+        >>> from core.data.request.fuzzableRequest import fuzzableRequest
+        >>> from core.data.dc.dataContainer import dataContainer as dc
+        >>> divided_path = dc()
+        >>> divided_path['start'] = ''
+        >>> divided_path['fuzzedUrlParts'] = 'ping!'
+        >>> divided_path['end'] = 'def'
+        
+        >>> fr = fuzzableRequest(url_object('http://www.w3af.com/abc/def'))    
    
+        >>> m = mutantUrlParts( fr )
+        >>> m._mutant_dc = divided_path
+        >>> m.setVar( 'fuzzedUrlParts' )
+        >>> m.getURL().url_string
+        u'http://www.w3af.com/ping%21/def'
+        '''
+        domain_path = self._freq.getURL().getDomainPath()
+        
+        # Please note that this double encoding is needed if we want to work 
with mod_rewrite
+        encoded = urllib.quote_plus( self._mutant_dc['fuzzedUrlParts'], 
self._safeEncodeChars )
+        if self._doubleEncoding:
+            encoded = urllib.quote_plus( encoded, safe=self._safeEncodeChars )
+        domain_path.setPath( self._mutant_dc['start'] + encoded + 
self._mutant_dc['end'] )
+        return domain_path

#APR: Are we sure about this? Shouldn't we have a real getURI that returns the 
URI and a real getURL that only returns the URL?

+    getURI = getURL
+    
+    def getData( self ):
+        return None
+    
+    def printModValue( self ):
+        res = 'The sent '+ self.getMutantType() +' is: "' + 
self._mutant_dc['start']
+        res += self._mutant_dc['fuzzedUrlParts'] + self._mutant_dc['end'] + '" 
.'
+        return res
+        
+    def setModValue( self, val ):
+        self._mutant_dc['fuzzedUrlParts'] = val
+        
+    def getModValue(self):
+        return self._mutant_dc['fuzzedUrlParts']
+    
+    def setURL( self, u ):
+        raise w3afException('You can\'t change the value of the URL in a 
mutantUrlParts instance.')

#APR: Do we use this? How?

+    def dynamicURL( self ):
+        '''
+        The URL will change, don't try to use it to avoid reporting something 
more than once.
+        '''
+        return True
+
+    def foundAt(self):
+        '''
+        @return: A string representing WHAT was fuzzed. This string is used 
like this:
+                - v.setDesc( 'SQL injection in a '+ v['db'] +' was found at: ' 
+ mutant.foundAt() )
+        '''
+        res = ''
+        res += '"' + self.getURL() + '", using HTTP method '
+        res += self.getMethod() + '. The fuzzed parameter was the target URL, 
with value: "'
+        res += self.getModValue() + '".'
+        return res
Index: core/data/fuzzer/fuzzer.py
===================================================================
--- core/data/fuzzer/fuzzer.py  (revision 4506)
+++ core/data/fuzzer/fuzzer.py  (working copy)
@@ -46,6 +46,7 @@
 from core.data.fuzzer.mutantQs import mutantQs
 from core.data.fuzzer.mutantPostData import mutantPostData
 from core.data.fuzzer.mutantFileName import mutantFileName
+from core.data.fuzzer.mutantUrlParts import mutantUrlParts
 from core.data.fuzzer.mutantHeaders import mutantHeaders
 from core.data.fuzzer.mutantJSON import mutantJSON
 from core.data.fuzzer.mutantCookie import mutantCookie
@@ -95,6 +96,12 @@
             om.out.debug('Fuzzing file name')
             result.extend(_createFileNameMutants(freq, mutantFileName, 
                                  mutant_str_list, fuzzableParamList, append))
+
+        if 'fuzzURLParts' in _fuzzable:
+            om.out.debug('Fuzzing URL parts')

#APR: Do we want to call _createUrlPartsMutants for all freq? Does it make 
sense to fuzz the URL when
there are query string parameters? Hmmm... we should think about this.

+            result.extend(_createUrlPartsMutants(freq, mutantUrlParts, 
+                                 mutant_str_list, fuzzableParamList, append))
+ 
     # POST-data parameters
     if isinstance(freq, httpPostDataRequest):
         # If this is a POST request, it could be a JSON request, and I want
@@ -488,6 +495,40 @@
 
     return result
     
+def _createUrlPartsMutants(freq, mutantClass, mutant_str_list, 
fuzzableParamList, append):
+    '''
+    @parameter freq: A fuzzable request with a dataContainer inside.
+    @parameter mutantClass: The class to use to create the mutants
+    @parameter fuzzableParamList: What parameters should be fuzzed
+    @parameter append: True/False, if we should append the value or replace it.
+    @parameter mutant_str_list: a list with mutant strings to use

#APR: doctest missing (sorry to ask for this now, but I did not identify the 
lack of it before)

+    @return: Mutants that have the filename URL changed with the strings at 
mutant_str_list
+    '''
+    res = []
+    path_sep = '/'
+    path = freq.getURL().getPath()
+    path_chunks = path.split(path_sep)
+    for idx, p_chunk in enumerate(path_chunks):
+        if not p_chunk:
+            continue
+        for mutant_str in mutant_str_list:
+            divided_path = dc()
+            divided_path['start'] = path_sep.join(path_chunks[:idx] + [''])
+            divided_path['end'] = path_sep.join([''] + path_chunks[idx+1:])
+            divided_path['fuzzedUrlParts'] = \
+                (p_chunk if append else '') + urllib.quote_plus(mutant_str)
+            freq_copy = freq.copy()
+            freq_copy.setURL(freq.getURL())
+            m = mutantClass(freq_copy) 
+            m.setOriginalValue(p_chunk)
+            m.setVar('fuzzedUrlParts')
+            m._mutant_dc = divided_path
+            m.setModValue(mutant_str)
+            m.setDoubleEncoding(True)
+            res.append(m)
+    return res
+ 
 def createRandAlpha(length=0):
     '''
     Create a random string ONLY with letters
@@ -588,6 +629,9 @@
         
     if cf.cf.getData('fuzzFileContent' ):
         _fuzzable['fuzzFileContent'] = None
+
+    if cf.cf.getData('fuzzURLParts'):
+        _fuzzable['fuzzURLParts'] = None
     
     return _fuzzable
 
------------------------------------------------------------------------------
Write once. Port to many.
Get the SDK and tools to simplify cross-platform app development. Create 
new or port existing apps to sell to consumers worldwide. Explore the 
Intel AppUpSM program developer opportunity. appdeveloper.intel.com/join
http://p.sf.net/sfu/intel-appdev
_______________________________________________
W3af-develop mailing list
W3af-develop@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/w3af-develop

Reply via email to