Andres:

With some delay, here is a(n almost fully) tested version. The only problem it 
already has is the last test, at line 125.

Carlos Pantelides

-----------------

http://seguridad-agile.blogspot.com/


--- On Tue, 7/19/11, Andres Riancho <[email protected]> wrote:

> From: Andres Riancho <[email protected]>
> Subject: Re: [W3af-users] symfony plugin
> To: "Carlos Pantelides" <[email protected]>
> Cc: [email protected], "w3af" <[email protected]>
> Date: Tuesday, July 19, 2011, 4:19 PM
> Carlos,
> 
> On Tue, Jul 19, 2011 at 11:28 AM, Carlos Pantelides
> <[email protected]>
> wrote:
> >> > How can I ask if a cookie is set?
> >>
> >> Not sure if there is a "clean" way of asking
> xUrllib
> >> if in the next request it will send a cookie or
> not
> >> (also, it depends on the request you make, since
> cookies
> >> might be restricted to a path).
> >
> >> What you could do, is to have two parts of the
> plugin,
> >> one to analyse all responses until you see a
> set-cookie
> >> and set an attribute like self._cookie_sent to
> True;
> >> and the second part (which will run only when
> >> _cookie_sent is True?!) that analyses forms.
> >
> > ok, in august I'll spend some time. I've attached a
> new version with cosmetic changes.
> 
> The code looks cleaner now, thanks.
> 
> >> >> Where can I test this plugin?
> >
> > These two sites are taken "from the manual", they both
> use a cookie with symfony=.... The first one has csrf
> activated, the other one no.
> >
> > http slash slash bkdjombang dot com
> >
> > http slash slash www dot katrinjuntke dot ch slash
> kontakt
> >
> > There are a lot of other sites that changed the
> cookie, like
> >
> > http slash slash level 7 systems dot co dot uk slash
> en slash contact-us
> >
> > https slash slash ssl7 dot net slash websitechat dot
> net slash login
> >
> > that have the csrf form protection disabled, but
> perhaps has moved it to a cookie. Anyway, they are
> undetectable as symfony. That narrows the utility of the
> plugin, thumbs up for symfony! (and the developers that
> change the defaults, but, we are not sure that they really
> run symfony...)
> >
> > I took the sites from http://www.appliedstacks.com/NewestFirst/Symfony
> 
> I'll wait until you've performed your testing before
> performing mine,
> so I get a more finished version. I'll bother you again in
> 15 days to
> see if you were able to test it in detail :)
> 
> >
> >> > Charli
> 
> 
> 
> -- 
> Andrés Riancho
> Director of Web Security at Rapid7 LLC
> Founder at Bonsai Information Security
> Project Leader at w3af
>
'''
symfony.py

Copyright 2011 Andres Riancho and Carlos Pantelides

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

'''

# options
from core.data.options.option import option
from core.data.options.optionList import optionList

from core.controllers.basePlugin.baseGrepPlugin import baseGrepPlugin

import core.data.kb.knowledgeBase as kb
import core.data.kb.info as info

from core.data.bloomfilter.bloomfilter import scalable_bloomfilter

import re

class symfony(baseGrepPlugin):
    '''
    Grep every page for traces of the Symfony framework.
      
    @author: Carlos Pantelides ([email protected] ) based upon work by Andres Riancho ( [email protected] ) and help from Pablo Mouzo ([email protected])
    '''
    
    def __init__(self):
        baseGrepPlugin.__init__(self)
        
        # Internal variables
        self._already_inspected = scalable_bloomfilter()
        
    def grep(self, request, response):
        '''
        Plugin entry point.
        
        @parameter request: The HTTP request object.
        @parameter response: The HTTP response object
        @return: None, all results are saved in the kb.
        
        Init
        >>> from core.data.url.httpResponse import httpResponse
        >>> from core.data.request.fuzzableRequest import fuzzableRequest
        >>> from core.controllers.misc.temp_dir import create_temp_dir
        >>> from core.data.parsers.urlParser import url_object
        >>> o = create_temp_dir()
        >>> emptyBody=''
        >>> unprotectedBody='<html><head></head><body><form action="login" method="post"><input type="text" name="signin" id="signin" /></form></body></html>'
        >>> protectedBody='<html><head></head><body><form action="login" method="post"><input type="text" name="signin" id="signin" /><input type="hidden" name="signin[_csrf_token]" value="069092edf6b67d5c25fd07642a54f6e3" id="signin__csrf_token" /></form></body></html>'
        >>> symfonyHeaders={'set-cookie': 'symfony=sfasfasfa'}
        >>> noSymfonyHeaders={}

        Symfony detection, positive
        >>> body = emptyBody
        >>> headers = symfonyHeaders
        >>> url = url_object('http://www.w3af.com/')
        >>> response = httpResponse(200, body , headers, url, url)
        >>> a = symfony()
        >>> assert a.symfonyDetected(response) == True
   
        Symfony detection, negative
        >>> body = emptyBody
        >>> headers = noSymfonyHeaders
        >>> url = url_object('http://www.w3af.com/')
        >>> response = httpResponse(200, body , headers, url, url)
        >>> a = symfony()
        >>> assert a.symfonyDetected(response) == False

        CSRF detection, positive
        >>> body = protectedBody
        >>> url = url_object('http://www.w3af.com/')
        >>> headers = symfonyHeaders
        >>> response = httpResponse(200, body , headers, url, url)
        >>> a = symfony()
        >>> assert a.csrfDetected(response.getDOM()) == True

        CSRF detection, negative
        >>> body = unprotectedBody
        >>> headers = symfonyHeaders
        >>> url = url_object('http://www.w3af.com/')
        >>> response = httpResponse(200, body , headers, url, url)
        >>> a = symfony()
        >>> assert a.csrfDetected(response.getDOM()) == False

        Symfonry plus CSRF detection, positive plus negative
        >>> kb.kb.save('symfony','symfony',[])
        >>> body = protectedBody
        >>> headers = symfonyHeaders        
        >>> url = url_object('http://www.w3af.com/')
        >>> response = httpResponse(200, body , headers, url, url)
        >>> request = fuzzableRequest()
        >>> request.setURL( url )
        >>> request.setMethod( 'GET' )
        >>> a = symfony()
        >>> a.grep(request, response)
        >>> assert len(kb.kb.getData('symfony', 'symfony')) == 0

        Symfonry plus CSRF detection, positive plus positive
        >>> kb.kb.save('symfony','symfony',[])
        >>> body = unprotectedBody
        >>> headers = symfonyHeaders
        >>> url = url_object('http://www.w3af.com/')
        >>> response = httpResponse(200, body , headers, url, url)
        >>> request = fuzzableRequest()
        >>> request.setURL( url )
        >>> request.setMethod( 'GET' )
        >>> a = symfony()
        >>> a.grep(request, response)
        >>> assert len(kb.kb.getData('symfony', 'symfony')) == 0 # should != 0, outside the tests it works fine!!!


        '''
        url = response.getURL()
        if response.is_text_or_html() and url not in self._already_inspected:
            
            # Don't repeat URLs
            self._already_inspected.add(url)

            if self.symfonyDetected(response):
                dom = response.getDOM()
                if dom is not None:
                    if not self.csrfDetected(dom):
                        i = info.info()
                        i.setPluginName(self.getName())
                        i.setName('Symfony Framework')
                        i.setURL(url)
                        i.setDesc('The URL: "%s" seems to be generated by the Symfony framework and contains a form that perhaps has csrf protection disabled.' % url)
                        i.setId(response.id)
                        kb.kb.append(self, 'symfony', i)

    def symfonyDetected(self, response):
        for header_name in response.getHeaders().keys():
            if header_name.lower() == 'set-cookie' or header_name.lower() == 'cookie':
                if re.match('^symfony=', response.getHeaders()[header_name]):
                    return True
        return False      
    
    def csrfDetected(self, dom):
        forms = dom.xpath('//form')
        if forms:
            csrf_protection_regex_string = '.*csrf_token'
            csrf_protection_regex_re = re.compile( csrf_protection_regex_string, re.IGNORECASE )
            for form in forms:
                inputs = form.xpath('//input[@id]')
                if inputs:
                    for input in inputs:
                        if csrf_protection_regex_re.search(input.attrib["id"]):
                            return True
        return False


    def setOptions( self, OptionList ):
        pass
    
    def getOptions( self ):
        '''
        @return: A list of option objects for this plugin.
        '''    
        ol = optionList()
        return ol
        
    def end(self):
        '''
        This method is called when the plugin wont be used anymore.
        '''
        self.printUniq( kb.kb.getData( 'symfony', 'symfony' ), 'URL' )

    def getPluginDeps( self ):
        '''
        @return: A list with the names of the plugins that should be runned before the
        current one.
        '''
        return []
    
    def getLongDesc( self ):
        '''
        @return: A DETAILED description of the plugin functions and features.
        '''
        return '''
        This plugin greps every page for traces of the Symfony framework and the lack of csrf protection.
        '''
------------------------------------------------------------------------------
Doing More with Less: The Next Generation Virtual Desktop 
What are the key obstacles that have prevented many mid-market businesses
from deploying virtual desktops?   How do next-generation virtual desktops
provide companies an easier-to-deploy, easier-to-manage and more affordable
virtual desktop model.http://www.accelacomm.com/jaw/sfnl/114/51426474/
_______________________________________________
W3af-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/w3af-users

Reply via email to