''' osCommanding.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.fuzzer import * import core.controllers.outputManager as om from core.controllers.basePlugin.baseAuditPlugin import baseAuditPlugin import core.data.kb.knowledgeBase as kb import core.data.parsers.urlParser as urlParser import core.data.kb.vuln as vuln class osCommanding(baseAuditPlugin): ''' This plugin tests for OS Commanding bugs. @author: Andres Riancho ( andres.riancho@gmail.com ) ''' def __init__(self): baseAuditPlugin.__init__(self) def _fuzzRequests(self, freq ): ''' Tests an URL for OS Commanding vulnerabilities. @param freq: A fuzzableRequest ''' om.out.debug( 'osCommanding plugin is testing: ' + freq.getURL() ) cList = self._getCommandList() onlyCommands = [ v.getCommand() for v in cList ] mutants = createMutants( freq , onlyCommands ) for mutant in mutants: if self._hasNoBug( 'osCommanding','osCommanding',mutant.getURL() , mutant.getVar() ): # Only spawn a thread if the mutant has a modified variable # that has no reported bugs in the kb targs = (mutant,) self._tm.startFunction( target=self._sendMutant, args=targs , ownerObj=self ) def _analyzeResult( self, mutant, response ): ''' Analyze results of the _sendMutant method. ''' if self._findFile( response.getBody() ): v = vuln.vuln( mutant ) # Search for the correct command and separator for comm in self._getCommandList(): if comm.getCommand() == mutant.getModValue(): v['os'] = comm.getOs() v['separator'] = comm.getSeparator() v.setDesc( 'OS Commanding was found at: ' + response.getURL() + ' . Using method: ' + v.getMethod() + '. The data sent was: ' + str(mutant.getDc()) ) v.setId( response.id ) kb.kb.append( self, 'osCommanding', v ) def end(self): ''' This method is called when the plugin wont be used anymore. ''' self._tm.join( self ) self.printUniq( kb.kb.getData( 'osCommanding', 'osCommanding' ), 'VAR' ) def _getCommandList( self ): ''' @return: This method returns a list of commands to try to execute. ''' class command: def __init__( self, comm, os, sep ): self._comm = comm self._os = os self._sep = sep def getOs( self ): return self._os def getCommand( self ): return self._comm def getSeparator( self ): return self._sep commands = [] commands.append( command("/bin/cat /etc/passwd",'unix','')) commands.append( command("&/bin/cat /etc/passwd",'unix','&')) commands.append( command("|/bin/cat /etc/passwd",'unix','|')) commands.append( command(";/bin/cat /etc/passwd",'unix',';')) commands.append( command("`/bin/cat /etc/passwd`",'unix','`')) commands.append( command("type C:\\boot.ini",'windows','')) commands.append( command("&type C:\\boot.ini",'windows','&')) commands.append( command("|type C:\\boot.ini",'windows','|')) commands.append( command(";type C:\\boot.ini",'windows',';')) return commands def getOptionsXML(self): ''' This method returns a XML containing the Options that the plugin has. Using this XML the framework will build a window, a menu, or some other input method to retrieve the info from the user. The XML has to validate against the xml schema file located at : w3af/core/ui/userInterface.dtd @return: XML with the plugin options. ''' return '\ \ \ ' def setOptions( self, OptionList ): ''' This method sets all the options that are configured using the user interface generated by the framework using the result of getOptionsXML(). @parameter OptionList: A dictionary with the options for the plugin. @return: No value is returned. ''' pass def _findFile( self, htmlString ): ''' This method finds out if the local file has been successfully included in the resulting HTML. @return: True / False. ''' for filePattern in self._getFilePatterns(): position = htmlString.find( filePattern ) if position != -1: om.out.debug('Found the file echoed by the command.') return True def _getFilePatterns(self): ''' @return: A list of strings to find in the resulting HTML in order to check for local file includes. ''' filePatterns = [] filePatterns.append("root:x:0:0:") filePatterns.append("daemon:x:1:1:") filePatterns.append(":/bin/bash") filePatterns.append(":/bin/sh") filePatterns.append("[boot loader]") filePatterns.append("default=multi(") filePatterns.append("[operating systems]") filePatterns.append("eval()'d code on line ") filePatterns.append("Cannot execute a blank command in") filePatterns.append("Fatal error: preg_replace") return filePatterns 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 will find OS commanding vulnerabilities. The detection is done by sending to every injectable parameter a command separator, like "&" or ";" , followed by a "cat /etc/passwd" command. If in the response the plugin finds a string like "root:x:0:0:" then the aplication has an OS commanding vulnerability. This plugin has a rather long list of command separators, commands, and return strings to try to match all platforms and installations. '''