3
FUZZING SOAP ENDPOINTS

image

As a penetration tester, you may run into applications or servers that offer programmatic API access via SOAP endpoints. SOAP, or Simple Object Access Protocol, is a common enterprise technology that enables language-agnostic access to programming APIs. Generally speaking, SOAP is used over the HTTP protocol, and it uses XML to organize the data sent to and from the SOAP server. The Web Service Description Language (WSDL) describes the methods and functionality exposed through SOAP endpoints. By default, SOAP endpoints expose WSDL XML documents that clients can easily parse so that they can interface with the SOAP endpoints, and C# has several classes that make this possible.

This chapter builds on your knowledge of how to programmatically craft HTTP requests to detect XSS and SQL injection vulnerabilities, except that it focuses on SOAP XML instead. This chapter also shows you how to write a small fuzzer to download and parse the WSDL file exposed by a SOAP endpoint and then use the information in the WSDL file to generate HTTP requests for the SOAP service. Ultimately, you’ll be able to systematically and automatically look for possible SQL injection vulnerabilities in SOAP methods.

Setting Up the Vulnerable Endpoint

For this chapter, you’ll use a vulnerable endpoint in a preconfigured virtual appliance called CsharpVulnSoap (which should have a file extension of .ova) available on the VulnHub website (http://www.vulnhub.com/). After downloading the appliance, you can import it into VirtualBox or VMware on most operating systems by double-clicking the file. Once the appliance is installed, log in with a password of password or use a Guest session to open a terminal. From there, enter ifconfig to find the virtual appliance’s IP address. By default, this appliance will be listening on a host-only interface, unlike in previous chapters where we bridged the network interfaces.

After bringing the endpoint up in a web browser, as shown in Figure 3-1, you can use the menu items on the left side of the screen (AddUser, ListUsers, GetUser, and DeleteUser) to see what the functions exposed by the SOAP endpoint return when used. Navigating to http://<ip>/Vulnerable.asmx?WSDL should present you with the WSDL document describing the available functions in a parseable XML file. Let’s dig into the structure of this document.

image

Figure 3-1: The vulnerable endpoint as seen from Firefox

Parsing the WSDL

WSDL XML documents are a bit complicated. Even a simple WSDL document like the one we’ll parse is not trivial. However, because C# has excellent classes for parsing and consuming XML files, getting the WSDL parsed correctly and into a state that lets us interact with the SOAP services in an object-oriented fashion is pretty bearable.

A WSDL document is essentially a bunch of XML elements that relate to one another in a logical way, from the bottom of the document to the top. At the bottom of the document, you interact with the service to make a request to the endpoint. From the service, you have the notion of ports. These ports point to a binding, which in turn points to a port type. The port type contains the operations (or methods) available on that endpoint. The operations contain an input and an output, which both point to a message. The message points to a type, and the type contains the parameters required to call the method. Figure 3-2 explains this concept visually.

image

Figure 3-2: The basic logical layout of a WSDL document

Our WSDL class constructor will work in reverse order. First, we’ll create the constructor, and then we’ll create a class to handle parsing each part of the WSDL document, from types to services.

Creating a Class for the WSDL Document

When you’re parsing WSDL programmatically, it’s easiest to start at the top of the document with the SOAP types and work your way down the document. Let’s create a class called WSDL that encompasses the WSDL document. The constructor is relatively simple, as shown in Listing 3-1.

public WSDL (XmlDocument doc)
{
  XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
  nsManager.AddNamespace("wsdl", doc.DocumentElement.NamespaceURI);
  nsManager.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema");

  ParseTypes(doc, nsManager);
  ParseMessages(doc, nsManager);
  ParsePortTypes(doc, nsManager);
  ParseBindings(doc, nsManager);
  ParseServices(doc, nsManager);
}

Listing 3-1: The WSDL class constructor

The constructor of our WSDL class calls just a handful of methods (which we’ll write next), and it expects the retrieved XML document that contains all the definitions of the web service as a parameter. The first thing we need to do is define the XML namespaces we’ll be referencing while using XPath queries (which are covered in Listing 3-3 and later listings) when we implement the parsing methods. To do this, we create a new XmlNamespaceManager and use the AddNamespace() method to add two namespaces, wsdl and xs. Then we call the methods that will parse the elements of the WSDL document, starting with types and working our way down to services. Each method takes two arguments: the WSDL document and the namespace manager.

We also need access to a few properties of the WSDL class that correspond to the methods called in the constructor. Add the properties shown in Listing 3-2 to the WSDL class.

public List<SoapType> Types { get; set; }
public List<SoapMessage> Messages { get; set; }
public List<SoapPortType> PortTypes { get; set; }
public List<SoapBinding> Bindings { get; set; }
public List<SoapService> Services { get; set; }

Listing 3-2: Public properties of the WSDL class

These properties of the WSDL class are consumed by the fuzzer (which is why they are public) and by the methods called in the constructor. The properties are lists of the SOAP classes we’ll implement in this chapter.

Writing the Initial Parsing Methods

First, we’ll write the methods that are called in Listing 3-1. Once we have those methods implemented, we’ll move on to create the classes each method relies on. This is going to be a bit of work, but we’ll get through it together!

We’ll start by implementing the first method called in Listing 3-1, ParseTypes(). All the methods called from the constructor are relatively simple and will look similar to Listing 3-3.

private void ParseTypes(XmlDocument wsdl, XmlNamespaceManager nsManager)
{
  this.Types = new List<SoapType>();
  string xpath = "/wsdl:definitions/wsdl:types/xs:schema/xs:element";
  XmlNodeList nodes = wsdl.DocumentElement.SelectNodes(xpath, nsManager);
  foreach (XmlNode type in nodes)
    this.Types.Add(new SoapType(type));
}

Listing 3-3: The ParseTypes() method called in the WSDL class constructor

Because these methods are only called internally in the WSDL constructor, we use the private keyword so that only the WSDL class can access them. The ParseTypes() method accepts a WSDL document and the namespace manager (used to resolve namespaces in the WSDL document) as arguments. Next, we instantiate a new List object and assign it to the Types property. We then iterate over the XML elements in the WSDL using the XPath facilities available to XML documents in C#. XPath lets a programmer traverse and consume an XML document based on node paths within the document. In this example, we use an XPath query to enumerate all the SOAP type nodes from the document using the SelectNodes() method. Then we iterate over those SOAP types and pass each node to the SoapType class constructor, which is one of the classes we’ll implement after entering the initial parsing methods. Finally, we add the newly instantiated SoapType objects to the SoapType list property of the WSDL class.

Easy enough, right? We’ll employ this pattern of using an XPath query to iterate over specific nodes a few more times to consume a few other types of nodes we need from the WSDL document. XPath is quite powerful and is great for working with the C# language in general.

Now we’ll implement the next method called in the WSDL constructor to parse the WSDL document, ParseMessages(), as detailed in Listing 3-4.

private void ParseMessages(XmlDocument wsdl, XmlNamespaceManager nsManager)
{
  this.Messages = new List<SoapMessage>();
  string xpath = "/wsdl:definitions/wsdl:message";
  XmlNodeList nodes = wsdl.DocumentElement.SelectNodes(xpath, nsManager);
  foreach (XmlNode node in nodes)
    this.Messages.Add(new SoapMessage(node));
}

Listing 3-4: The ParseMessages() method called in the WSDL class constructor

First, we need to instantiate and assign a new List to hold the SoapMessage objects. (SoapMessage is a class we’ll implement in “Creating the SoapMessage Class to Define Sent Data” on page 60.) Using an XPath query to select the message nodes from the WSDL document, we iterate over the nodes returned by the SelectNodes() method and pass them to the SoapMessage constructor. These newly instantiated objects are added to the Messages property of the WSDL class for later consumption.

The next few methods called from the WSDL class are similar to the previous two. By now, they should seem relatively straightforward to you, given how the previous two methods have worked. These methods are all detailed in Listing 3-5.

private void ParsePortTypes(XmlDocument wsdl, XmlNamespaceManager nsManager)
{
  this.PortTypes = new List<SoapPortType>();
  string xpath = "/wsdl:definitions/wsdl:portType";
  XmlNodeList nodes = wsdl.DocumentElement.SelectNodes(xpath, nsManager);
  foreach (XmlNode node in nodes)
  this.PortTypes.Add(new SoapPortType(node));
}

private void ParseBindings(XmlDocument wsdl, XmlNamespaceManager nsManager)
{
  this.Bindings = new List<SoapBinding>();
  string xpath = "/wsdl:definitions/wsdl:binding";
  XmlNodeList nodes = wsdl.DocumentElement.SelectNodes(xpath, nsManager);
  foreach (XmlNode node in nodes)
    this.Bindings.Add(new SoapBinding(node));
}

private void ParseServices(XmlDocument wsdl, XmlNamespaceManager nsManager)
{
  this.Services = new List<SoapService>();
  string xpath = "/wsdl:definitions/wsdl:service";
  XmlNodeList nodes = wsdl.DocumentElement.SelectNodes(xpath, nsManager);
  foreach (XmlNode node in nodes)
    this.Services.Add(new SoapService(node));
}

Listing 3-5: The rest of the initial parsing methods in the WSDL class

To fill the PortTypes, Bindings, and Services properties, we use XPath queries to find and iterate over the relevant nodes; then we instantiate specific SOAP classes, which we’ll implement next, and add them to the lists so that we can access them later when we need to build the WSDL fuzzer logic.

That’s it for the WSDL class. A constructor, a handful of properties to store data relevant to the WSDL class, and some methods to parse out a WSDL document are all that you need to get started. Now we need to implement the supporting classes. Within the parsing methods, we used some classes that haven’t yet been implemented (SoapType, SoapMessage, SoapPortType, SoapBinding, and SoapService). We’ll start with the SoapType class.

Writing a Class for the SOAP Type and Parameters

To complete the ParseTypes() method, we need to implement the SoapType class. The SoapType class is a relatively simple one. All it needs is a constructor and a couple of properties, as shown in Listing 3-6.

public class SoapType
{
  public SoapType(XmlNode type)
  {
    this.Name = type.Attributes["name"].Value;
    this.Parameters = new List<SoapTypeParameter>();
    if (type.HasChildNodes && type.FirstChild.HasChildNodes)
    {

      foreach (XmlNode node in type.FirstChild.FirstChild.ChildNodes)
        this.Parameters.Add(new SoapTypeParameter(node));
    }
  }

  public string Name { get; set; }
  public List<SoapTypeParameter> Parameters { get; set; }
}

Listing 3-6: The SoapType class used in the WSDL fuzzer

The logic in the SoapType constructor is similar to that in the previous parsing methods (in Listings 3-4 and 3-5), except we’re not using XPath to enumerate the nodes we’re iterating over. We could have, but I wanted to show you another way of iterating over XML nodes. Usually, when you’re parsing XML, XPath is the way to go, but XPath can be computationally expensive. In this case, we’ll write an if statement to check whether we have to iterate over the child nodes. Iterating over the child nodes using a foreach loop to find the relevant XML element involves slightly less code than using XPath in this particular instance.

The SoapType class has two properties: a Name property, which is a string, and a list of parameters (the SoapTypeParameter class, which we’ll implement shortly). Both of these properties are used in the SoapType constructor and are public so that they can be consumed outside the class later on.

We use the Attributes property on the node passed into the constructor arguments to retrieve the node’s name attribute. The value of the name attribute is assigned to the Name property of the SoapType class. We also instantiate the SoapTypeParameter list and assign the new object to the Parameters property. Once this is done, we use an if statement to determine whether we need to iterate over child nodes in the first place, since we’re not using XPath to iterate over any child nodes. Using the HasChildNodes property , which returns a Boolean value, we can determine whether we have to iterate over the child nodes. If the node has child nodes, and if the first child of that node also has child nodes, we’ll iterate over them.

Every XmlNode class has a FirstChild property and a ChildNodes property that returns an enumerable list of the child nodes available. In the foreach loop, we use a chain of FirstChild properties to iterate over the child nodes of the first child of the first child of the node passed in.

An example of an XML node that would be passed to the SoapType constructor is shown in Listing 3-7.

After iterating over the relevant child nodes in the SoapType node that’s passed in, we instantiate a new SoapTypeParameter class by passing the current child node into the SoapTypeParameter constructor. The new object is stored in the Parameters list for access later on.

<xs:element name="AddUser">
  <xs:complexType>
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" name="username" type="xs:string"/>
      <xs:element minOccurs="0" maxOccurs="1" name="password" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

Listing 3-7: Sample SoapType XML

Now let’s create the SoapTypeParameter class. The SoapTypeParameter class is also relatively simple. In fact, no iteration over child nodes is required, just basic information gathering, as Listing 3-8 shows.

public class SoapTypeParameter
{
  public SoapTypeParameter(XmlNode node)
  {
  if (node.Attributes["maxOccurs"].Value == "unbounded")
      this.MaximumOccurrence = int.MaxValue;
    else
      this.MaximumOccurrence = int.Parse(node.Attributes["maxOccurs"].Value);

    this.MinimumOccurrence = int.Parse(node.Attributes["minOccurs"].Value);
    this.Name = node.Attributes["name"].Value;
    this.Type = node.Attributes["type"].Value;
  }
  public int MinimumOccurrence { get; set; }
  public int MaximumOccurrence { get; set; }
  public string Name { get; set; }
  public string Type { get; set; }
}

Listing 3-8: The SoapTypeParameter class

An example of an XML node passed to the SoapTypeParameter constructor is shown in Listing 3-9.

<xs:element minOccurs="0" maxOccurs="1" name="username" type="xs:string"/>

Listing 3-9: Sample XML node passed to the SoapTypeParameter constructor

Given an XML node like this, we can expect a few things to happen in our method. First, this is a very basic WSDL parameter that defines a parameter named username that is of type string. It can occur at a minimum zero times and at most once. Look closely at the code in Listing 3-8, and you’ll notice that there’s an if statement that checks the value of maxOccurs. Unlike minOccurs, maxOccurs can be either an integer or the string value unbounded, so we have to check the maxOccurs value before passing it to the int.Parse() method to see what the value is.

Within our SoapTypeParameter constructor, we first assign the MaximumOccurrence property based on the node’s maxOccurs attribute. We then assign the MinimumOccurrence, Name, and Type properties based on the corresponding node attributes.

Creating the SoapMessage Class to Define Sent Data

A SOAP message defines a set of data that the web service either expects or responds with for a given operation. It references the SOAP types and parameters previously parsed to present data to or consume data from the client application and is made up of parts, which is the technical term. An example of a SOAP 1.1 message XML element is provided in Listing 3-10.

<message name="AddUserHttpGetIn">
  <part name="username" type="s:string"/>
  <part name="password" type="s:string"/>
</message>

Listing 3-10: Sample SOAP message XML element

Our SoapMessage class, which consumes an XML element like the one in Listing 3-10, is detailed in Listing 3-11.

public class SoapMessage
{
  public SoapMessage(XmlNode node)
  {
    this.Name = node.Attributes["name"].Value;
    this.Parts = new List<SoapMessagePart>();
    if (node.HasChildNodes)
    {
      foreach (XmlNode part in node.ChildNodes)
        this.Parts.Add(new SoapMessagePart(part));
    }
  }
  public string Name { get; set; }
  public List<SoapMessagePart> Parts { get; set; }
}

Listing 3-11: The SoapMessage class

First, we assign the name of the message to the Name property of the SoapMessage class. We then instantiate a new List of parts called SoapMessagePart and iterate over each <part> element, passing the element to the SoapMessagePart constructor and saving the new SoapMessagePart for later use by adding it to the Parts list.

Implementing a Class for Message Parts

Like the previous SOAP classes we have implemented, the SoapMessagePart class is a simple class, as Listing 3-12 shows.

public class SoapMessagePart
{
  public SoapMessagePart(XmlNode part)
  {
    this.Name = part.Attributes["name"].Value;
    if (part.Attributes["element"] != null)
      this.Element = part.Attributes["element"].Value;
    else if ( part.Attributes["type"].Value != null)
      this.Type = part.Attributes["type"].Value;
    else
      throw new ArgumentException("Neither element nor type is set.", "part");
  }
  public string Name { get; set; }
  public string Element { get; set; }
  public string Type  { get; set; }
}

Listing 3-12: The SoapMessagePart class

The SoapMessagePart class constructor takes a single argument, XmlNode, that contains the name and the type or element of the part within the SoapMessage. The SoapMessagePart class defines three public properties: the part’s Name, Type, and Element, all of which are strings. First, we store the name of the part in the Name property . Then, if we have an attribute called element , we assign the value of the element attribute to the Element property. If the element attribute doesn’t exist, the type attribute must exist, so we assign the value of the type attribute to the Type property. Only two of these properties will be set for any given SOAP part—a SOAP part always has a Name and either a Type or Element. The Type or Element will be set depending on whether the part is a simple type (such as a string or integer) or a complex type encompassed by another XML element within the WSDL. We have to create a class for each kind of parameter, and we’ll start by implementing the Type class.

Defining Port Operations with the SoapPortType Class

With the SoapMessage and SoapMessagePart classes defined to complete the ParseMessages() method from Listing 3-4, we move on to create the SoapPortType class, which will complete the ParsePortTypes() method. The SOAP port type defines the operations available on a given port (not to be confused with a network port), and parsing it is detailed in Listing 3-13.

public class SoapPortType
{
  public SoapPortType(XmlNode node)
  {
    this.Name = node.Attributes["name"].Value;
    this.Operations = new List<SoapOperation>();
    foreach (XmlNode op in node.ChildNodes)
      this.Operations.Add(new SoapOperation(op));
  }
  public string Name { get; set; }
  public List<SoapOperation> Operations { get; set; }
}

Listing 3-13: The SoapPortType class used in the ParsePortTypes() method

The pattern of how these SOAP classes work continues: the SoapPortType class in Listing 3-13 defines a small constructor that accepts an XmlNode from the WSDL document. It requires two public properties: a SoapOperation list and a Name string. Within the SoapPortType constructor, we first assign the Name property to the XML name attribute. We then create a new SoapOperation list and iterate over each of the child nodes in the portType element. As we iterate, we pass the child node to the SoapOperation constructor (which we build in the next section) and store the resulting SoapOperation in our list. An example of an XML node from the WSDL document that would be passed to the SoapPortType class constructor is shown in Listing 3-14.

<portType name="VulnerableServiceSoap">
  <operation name="AddUser">
    <input message="s0:AddUserSoapIn"/>
    <output message="s0:AddUserSoapOut"/>
  </operation>
  <operation name="ListUsers">
    <input message="s0:ListUsersSoapIn"/>
    <output message="s0:ListUsersSoapOut"/>
  </operation>
  <operation name="GetUser">
    <input message="s0:GetUserSoapIn"/>
    <output message="s0:GetUserSoapOut"/>
  </operation>
  <operation name="DeleteUser">
    <input message="s0:DeleteUserSoapIn"/>
    <output message="s0:DeleteUserSoapOut"/>
  </operation>
</portType>

Listing 3-14: Sample portType XML node passed to the SoapPortType class constructor

As you can see, the portType element contains the operations we’ll be able to perform, such as listing, creating, and deleting users. Each of the operations maps to a given message, which we parsed in Listing 3-11.

Implementing a Class for Port Operations

In order to use the operations from the SoapPortType class constructor, we need to create the SoapOperation class, as shown in Listing 3-15.

public class SoapOperation
{
  public SoapOperation(XmlNode op)
  {
    this.Name = op.Attributes["name"].Value;
    foreach (XmlNode message in op.ChildNodes)
    {
      if (message.Name.EndsWith("input"))
        this.Input = message.Attributes["message"].Value;
      else if (message.Name.EndsWith("output"))
        this.Output = message.Attributes["message"].Value;
    }
  }
  public string Name { get; set; }
  public string Input { get; set; }
  public string Output { get; set; }
}

Listing 3-15: The SoapOperation class

The SoapOperation constructor accepts an XmlNode as the single argument. The first thing we do is assign a property of the SoapOperation class called Name to the name attribute of the operation XML element passed to the constructor. We then iterate over each of the child nodes, checking whether the name of the element ends with either "input" or "output". If the name of the child node ends with "input", we assign the Input property to the name of the input element. Otherwise, we assign the Output property to the name of the output element. Now that the SoapOperation class has been implemented, we can move on to the classes we need to finish up the ParseBindings() method.

Defining Protocols Used in SOAP Bindings

The two general types of bindings are HTTP and SOAP. It seems redundant, but the HTTP bindings transport data over the general HTTP protocol, using an HTTP query string or POST parameters. SOAP bindings use either the SOAP 1.0 or SOAP 1.1 protocol over simple TCP sockets or named pipes, which encompass the data flowing to and from the server in XML. The SoapBinding class lets you decide how to communicate with a given SOAP port depending on the binding.

A sample binding node from the WSDL is shown in Listing 3-16.

<binding name="VulnerableServiceSoap" type="s0:VulnerableServiceSoap">
  <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
  <operation name="AddUser">
    <soap:operation soapAction="http://tempuri.org/AddUser" style="document"/>
    <input>
      <soap:body use="literal"/>
    </input>
    <output>
      <soap:body use="literal"/>
    </output>
  </operation>
</binding>

Listing 3-16: Sample binding XML node from the WSDL

In order to parse this XML node, our class needs to pull some key information out of the binding node, as shown in Listing 3-17.

public class SoapBinding
{
  public SoapBinding(XmlNode node)
  {
    this.Name = node.Attributes["name"].Value;
    this.Type = node.Attributes["type"].Value;
    this.IsHTTP = false;
    this.Operations = new List<SoapBindingOperation>();
    foreach (XmlNode op in node.ChildNodes)
    {
      if (op.Name.EndsWith("operation"))
      {
        this.Operations.Add(new SoapBindingOperation(op));
      }
      else if (op.Name == "http:binding")
      {
        this.Verb = op.Attributes["verb"].Value;
        this.IsHTTP = true;
      }
    }
  }
  public string Name { get; set; }
  public List<SoapBindingOperation> Operations { get; set; }
  public bool IsHTTP { get; set; }
  public string Verb { get; set; }
  public string Type { get; set; }
}

Listing 3-17: The SoapBinding class

After accepting an XmlNode as the argument to the SoapBinding constructor, we first assign the values of the name and type attributes of the node to the Name and Type properties of the SoapBinding class. By default, we set the IsHTTP Boolean property to false. The IsHTTP property helps us determine how to send the data we want to fuzz, using either HTTP parameters or SOAP XML.

As we iterate over the child nodes, we test whether each child node’s name ends with "operation" , and, if so, we add the operation to the SoapBindingOperation list. If the child node’s name does not end with "operation", the node should be an HTTP binding. We ensure this is the case with an else if statement, and we set the HTTP Verb property to the value of the verb attribute of the child node. We also set IsHTTP to true. The Verb property should contain either GET or POST, which tells us whether the data sent to the SOAP endpoint will be in query string (GET) parameters or POST parameters.

Next, we’ll implement the SoapBindingOperation class.

Compiling a List of Operation Child Nodes

The SoapBindingOperation class is a small class consumed in the SoapBinding class constructor. It defines a few string properties that will be assigned values based on the operation node passed to the constructor, as shown in Listing 3-18.

public class SoapBindingOperation
{
  public SoapBindingOperation(XmlNode op)
  {
    this.Name = op.Attributes["name"].Value;
    foreach (XmlNode node in op.ChildNodes)
    {
      if (node.Name == "http:operation")
        this.Location = node.Attributes["location"].Value;
      else if (node.Name == "soap:operation" || node.Name == "soap12:operation")
      this.SoapAction = node.Attributes["soapAction"].Value;
    }
  }
  public string Name { get; set; }
  public string Location { get; set; }
  public string SoapAction { get; set; }
}

Listing 3-18: The SoapBindingOperation class

Using the XmlNode that’s passed to the constructor, we first assign the Name property to the value of the name attribute on the XML node. The operation node contains a few child nodes, but we only really care about three specific nodes: http:operation, soap:operation, and soap12:operation. As we iterate over the child nodes to find a node we care about, we check whether the operation is an HTTP operation or a SOAP operation. If it is an HTTP operation , we store the location of the endpoint for the operation, which is a relative URI such as /AddUser. If it’s a SOAP operation, we store the SoapAction, which is used in a specific HTTP header when making SOAP calls against the SOAP endpoint. When we write the fuzzing logic, this information will be used to send the data to the correct endpoint.

Finding the SOAP Services on Ports

Before we can begin fuzzing, we need to finish parsing the WSDL. We’ll implement two more small classes that encompass the SOAP services available and the SOAP ports on those services. We must implement the SoapService class first, as shown in Listing 3-19.

public class SoapService
{
  public SoapService(XmlNode node)
  {
    this.Name = node.Attributes["name"].Value;
    this.Ports = new List<SoapPort>();
    foreach (XmlNode port in node.ChildNodes)
      this.Ports.Add(new SoapPort(port));
  }
  public string Name { get; set; }
  public List<SoapPort> Ports { get; set; }
}

Listing 3-19: The SoapService class

The SoapService class takes an XML node as the only argument to the constructor. We first assign the name of the service to the Name property of the class and then create a new list of ports, called SoapPort. As we iterate over the child nodes in the service node, we use each child node to create a new SoapPort and add the new object to the SoapPort list for later reference.

A sample service XML node with four child port nodes from a WSDL document is shown in Listing 3-20.

<service name="VulnerableService">
  <port name="VulnerableServiceSoap" binding="s0:VulnerableServiceSoap">
    <soap:address location="http://127.0.0.1:8080/Vulnerable.asmx"/>
  </port>
  <port name="VulnerableServiceSoap12" binding="s0:VulnerableServiceSoap12">
    <soap12:address location="http://127.0.0.1:8080/Vulnerable.asmx"/>
  </port>
  <port name="VulnerableServiceHttpGet" binding="s0:VulnerableServiceHttpGet">
    <http:address location="http://127.0.0.1:8080/Vulnerable.asmx"/>
  </port>
  <port name="VulnerableServiceHttpPost" binding="s0:VulnerableServiceHttpPost">
    <http:address location="http://127.0.0.1:8080/Vulnerable.asmx"/>
  </port>
</service>

Listing 3-20: A sample service node from a WSDL document

The last thing to do is implement the SoapPort class to complete the ParseServices() method and then finish parsing the WSDL for fuzzing. The SoapPort class is shown in Listing 3-21.

public class SoapPort
{
  public SoapPort(XmlNode port)
  {
    this.Name = port.Attributes["name"].Value;
    this.Binding = port.Attributes["binding"].Value;
    this.ElementType = port.FirstChild.Name;
    this.Location = port.FirstChild.Attributes["location"].Value;
  }
  public string Name { get; set; }
  public string Binding { get; set; }
  public string ElementType { get; set; }
  public string Location { get; set; }
}

Listing 3-21: The SoapPort class

To finish parsing the WSDL document, we grab a few attributes from the port node passed to the SoapPort constructor. We first store the name of the port in the Name property and the binding in the Binding property. Then, referencing the port node’s only child node with the FirstChild property , we store the name and location data of the child node in the ElementType and Location properties, respectively.

Finally, we have broken apart the WSDL document into manageable pieces that will allow us to easily write a fuzzer to find potential SQL injections. With the various parts of the WSDL described as classes, we can programmatically drive automatic vulnerability detection and reporting.

Automatically Fuzzing the SOAP Endpoint for SQL Injection Vulnerabilities

Now that the building blocks for the WSDL fuzzer have been built, we can start doing some real fun tool development. Using the WSDL class, we can interact with the data in the WSDL in an object-oriented manner, which makes fuzzing the SOAP endpoint much easier. We start by writing a new Main() method that accepts a single argument (the URL to the SOAP endpoint), which can be created in its own file inside of its own Fuzzer class, as shown in Listing 3-22.

private static WSDL _wsdl = null;
private static string _endpoint = null;
public static void Main(string[] args)
{
  _endpoint = args[0];
  Console.WriteLine("Fetching the WSDL for service: " + _endpoint);
  HttpWebRequest req = (HttpWebRequest)WebRequest.Create(_endpoint + "?WSDL");
  XmlDocument wsdlDoc = new XmlDocument();
  using (WebResponse resp = req.GetResponse())
  using (Stream respStream = resp.GetResponseStream())
    wsdlDoc.Load(respStream);

  _wsdl = new WSDL(wsdlDoc);
  Console.WriteLine("Fetched and loaded the web service description.");

  foreach (SoapService service in _wsdl.Services)
    FuzzService(service);
}

Listing 3-22: The Main() method of the SOAP endpoint fuzzer

We first declare a couple of static variables at the class level before the Main() method. These variables will be used throughout methods we write. The first variable is the WSDL class , and the second stores the URL to the SOAP endpoint .

Within the Main() method, we assign the _endpoint variable to the value of the first argument passed to the fuzzer . Then we print a friendly message alerting the user that we are going to fetch the WSDL for the SOAP service.

After storing the URL to the endpoint, we create a new HttpWebRequest to retrieve the WSDL from the SOAP service by appending ?WSDL to the end of the endpoint URL. We also create a temporary XmlDocument to store the WSDL and to pass to the WSDL class constructor. Passing the HTTP response stream to the XmlDocument Load() method , we load the XML returned by the HTTP request into the XML document. We then pass the resulting XML document to the WSDL class constructor to create a new WSDL object. Now we can iterate over each of the SOAP endpoint services and fuzz the service. A foreach loop iterates over the objects in the WSDL class Services property and passes each service to the FuzzService() method, which we’ll write in the next section.

Fuzzing Individual SOAP Services

The FuzzService() method takes a SoapService as an argument and then determines whether we need to fuzz the service using SOAP or HTTP parameters, as shown in Listing 3-23.

static void FuzzService(SoapService service)
{
  Console.WriteLine("Fuzzing service: " + service.Name);

  foreach (SoapPort port in service.Ports)
  {
    Console.WriteLine("Fuzzing " + port.ElementType.Split(':')[0] + " port: " + port.Name);
    SoapBinding binding = _wsdl.Bindings.Single(b => b.Name == port.Binding.Split(':')[1]);

    if (binding.IsHTTP)
      FuzzHttpPort(binding);
    else
      FuzzSoapPort(binding);
  }
}

Listing 3-23: The FuzzService() method used to determine how to fuzz a given SoapService

After printing the current service we’ll be fuzzing, we iterate over each SOAP port in the Ports service property. Using the Language-Integrated Query (LINQ) Single() method , we select a single SoapBinding that corresponds to the current port. Then we test whether the binding is plain HTTP or XML-based SOAP. If the binding is an HTTP binding , we pass it to the FuzzHttpPort() method to fuzz. Otherwise, we assume the binding is a SOAP binding and pass it to the FuzzSoapPort() method.

Now let’s implement the FuzzHttpPort() method. The two types of possible HTTP ports when you’re dealing with SOAP are GET and POST. The FuzzHttpPort() method determines which HTTP verb will be used when sending the HTTP requests during fuzzing, as shown in Listing 3-24.

static void FuzzHttpPort(SoapBinding binding)
{
  if (binding.Verb == "GET")
    FuzzHttpGetPort(binding);
  else if (binding.Verb == "POST")
    FuzzHttpPostPort(binding);
  else
    throw new Exception("Don't know verb: " + binding.Verb);
}

Listing 3-24: The FuzzHttpPort() method

The FuzzHttpPort() method is very simple. It tests whether the SoapBinding property Verb equals GET or POST and then passes the binding to the appropriate method—FuzzHttpGetPort() or FuzzHttpPostPort(), respectively. If the Verb property does not equal either GET or POST, an exception is thrown to alert the user that we don’t know how to handle the given HTTP verb.

Now that we’ve created the FuzzHttpPort() method, we’ll implement the FuzzHttpGetPort() method.

Creating the URL to Fuzz

Both of the HTTP fuzzing methods are a bit more complex than the previous methods in the fuzzer. The first half of the FuzzHttpGetPort() method, covered in Listing 3-25, builds the initial URL to fuzz.

static void FuzzHttpGetPort(SoapBinding binding)
{
  SoapPortType portType = _wsdl.PortTypes.Single(pt => pt.Name == binding.Type.Split(':')[1]);
  foreach (SoapBindingOperation op in binding.Operations)
  {
    Console.WriteLine("Fuzzing operation: " + op.Name);
    string url = _endpoint + op.Location;
    SoapOperation po = portType.Operations.Single(p => p.Name == op.Name);
    SoapMessage input = _wsdl.Messages.Single(m => m.Name == po.Input.Split(':')[1]);
    Dictionary<string, string> parameters = new Dictionary<string, string>();

    foreach (SoapMessagePart part in input.Parts)
      parameters.Add(part.Name, part.Type);

    bool first = true;
    List<Guid> guidList = new List<Guid>();
    foreach (var param in parameters)
    {
      if (param.Value.EndsWith("string"))
      {
        Guid guid = Guid.NewGuid();
        guidList.Add(guid);
        url += (first ? "?" : "&") + param.Key + "=" + guid.ToString();
      }
      first = false;
    }

Listing 3-25: The first half of the FuzzHttpGetPort() method, where we build the initial URL to fuzz

The first thing we do in the FuzzHttpGetPort() method is use LINQ to select the port type from our WSDL class that corresponds to the current SOAP binding. We then iterate over the current binding’s Operations property, which contains information regarding each operation we can call and how to call the given operation. As we iterate, we print which operation we are going to fuzz. We then create the URL that we’ll use to make the HTTP request for the given operation by appending the Location property of the current operation to the _endpoint variable we set at the very beginning of the Main() method . We select the current SoapOperation (not to be confused with the SoapBindingOperation!) from the Operations property of the portType using the LINQ method Single(). We also select the SoapMessage used as the input for the current operation using the same LINQ method, which tells us what information the current operation is expecting when called.

Once we have the information we need to set up the GET URL, we create a dictionary to hold the HTTP parameter names and the parameter types we’ll be sending. We iterate over each of the input parts using a foreach loop. As we iterate, we add the name of each parameter and the type, which in this case will always be a string, to the dictionary. After we have all of our parameter names and their respective types stored alongside each other, we can build the initial URL to fuzz.

To begin, we define a Boolean called first , which we’ll use to determine whether the parameter that’s appended to the operation’s URL is the first parameter. This is important because the first query string parameter is always separated from the base URL by a question mark (?), and subsequent parameters are separated with an ampersand (&), so we need to be sure of the distinction. Then, we create a Guid list, which will hold unique values that we send along with the parameters so we can reference them in the second half of the FuzzHttpGetPort() method.

Next, we iterate over the parameters dictionary using a foreach loop. In this foreach loop, first we test whether the current parameter’s type is a string. If it’s a string, we create a new Guid that will be used as the parameter’s value; then we add the new Guid to the list we created so we can reference it later. We then use the += operator to append the parameter and the new value to the current URL. Using a ternary operation , we determine whether we should prefix the parameter with a question mark or ampersand. This is how the HTTP query string parameters must be defined per the HTTP protocol. If the current parameter is the first parameter, it is prepended with a question mark. Otherwise, it is prepended with an ampersand. Finally, we set the parameter to false so that subsequent parameters will be prepended with the correct separating character.

Fuzzing the Created URL

After creating the URL with query string parameters, we can make HTTP requests while systematically replacing parameter values with tainted values that could induce a SQL error from the server, as shown in Listing 3-26. This second half of the code completes the FuzzHttpGetPort() method.

  Console.WriteLine("Fuzzing full url: " + url);
  int k = 0;
  foreach(Guid guid in guidList)
  {
    string testUrl = url.Replace(guid.ToString(), "fd'sa");
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(testUrl);
    string resp = string.Empty;
    try
    {
      using (StreamReader rdr = new StreamReader(req.GetResponse().GetResponseStream()))
        resp = rdr.ReadToEnd();
    }
   catch (WebException ex)
    {
      using (StreamReader rdr = new StreamReader(ex.Response.GetResponseStream()))
          resp = rdr.ReadToEnd();

        if (resp.Contains("syntax error"))
          Console.WriteLine("Possible SQL injection vector in parameter: " + input.Parts[k].Name);
      }
      k++;
    }
  }
}

Listing 3-26: The second half of the FuzzHttpGetPort() method, sending the HTTP requests

Now that we have the full URL that we’ll be fuzzing, we print it for the user to see. We also declare an integer, k, that will be incremented as we iterate over the parameter values in the URL to keep track of potentially vulnerable parameters. Then, using a foreach loop, we iterate over the Guid list we used as the values for our parameters. Within the foreach loop, the first thing we do is replace the current Guid in the URL with the string "fd'sa" using the Replace() method , which should taint any SQL queries using the value without proper sanitization. We then create a new HTTP request with the modified URL and declare an empty string called resp that will hold the HTTP response.

Within a try/catch block, we attempt to read the response of the HTTP request from the server using a StreamReader . Reading the response will cause an exception if the server returns a 500 error (which would happen if a SQL exception occurred on the server side). If an exception is thrown, we catch the exception in the catch block and attempt to read the response from the server again. If the response contains the string syntax error, we print a message alerting the user that the current HTTP parameter could be vulnerable to a SQL injection. In order to tell the user precisely which parameter could be vulnerable, we use the integer k as the index of the Parts list and retrieve the Name of the current property. When all is said and done, we increment the integer k by 1 and start back at the beginning of the foreach loop with a new value to test.

That’s the full method for fuzzing HTTP GET SOAP ports. Next, we need to implement FuzzHttpPostPort() to fuzz POST SOAP ports.

Fuzzing the HTTP POST SOAP Port

Fuzzing the HTTP POST SOAP port for a given SOAP service is very similar to fuzzing the GET SOAP port. The only difference is that the data is sent as HTTP POST parameters instead of query-string parameters. When passing the SoapBinding for the HTTP POST port to the FuzzHttpPostPort() method, we need to iterate over each operation and systematically taint values sent to the operations to induce SQL errors from the web server. Listing 3-27 shows the first half of the FuzzHttpPostPort() method.

static void FuzzHttpPostPort(SoapBinding binding)
{
 SoapPortType portType = _wsdl.PortTypes.Single(pt => pt.Name == binding.Type.Split(':')[1]);
  foreach (SoapBindingOperation op in binding.Operations)
  {
    Console.WriteLine("Fuzzing operation: " + op.Name);
    string url = _endpoint + op.Location;
   SoapOperation po = portType.Operations.Single(p => p.Name == op.Name);
    SoapMessage input = _wsdl.Messages.Single(m => m.Name == po.Input.Split(':')[1]);
    Dictionary<string, string> parameters = new Dictionary<string, string>();

    foreach (SoapMessagePart part in input.Parts)
      parameters.Add(part.Name, part.Type);

Listing 3-27: Determining the operation and parameters to fuzz within the FuzzHttpPostPort() method

First we select the SoapPortType that corresponds to the SoapBinding passed to the method. We then iterate over each SoapBindingOperation to determine the current SoapBinding using a foreach loop. As we iterate, we print a message that specifies which operation we are currently fuzzing, and then we build the URL to send the data we are fuzzing to. We also select the corresponding SoapOperation for the portType variable so that we can find the SoapMessage we need, which contains the HTTP parameters we need to send to the web server. Once we have all the information we need to build and make valid requests to the SOAP service, we build a small dictionary containing the parameter names and their types to iterate over later.

Now we can build the HTTP parameters we’ll send to the SOAP service, as shown in Listing 3-28. Continue entering this code into the FuzzHttpPostPort() method.

  string postParams = string.Empty;
  bool first = true;
  List<Guid> guids = new List<Guid>();
  foreach (var param in parameters)
  {
    if (param.Value.EndsWith("string"))
    {
      Guid guid = Guid.NewGuid();
      postParams += (first ? "" : "&") + param.Key + "=" + guid.ToString();
      guids.Add(guid);
    }
    if (first)
      first = false;
  }

Listing 3-28: Building the POST parameters to be sent to the POST HTTP SOAP port

We now have all the data we need to build the POST requests. We declare a string to hold the POST parameters, and we declare a Boolean, which will determine whether the parameter will be prefixed with an ampersand, to delineate the POST parameters. We also declare a Guid list so that we can store the values we add to the HTTP parameters for use later in the method.

Now we can iterate over each of the HTTP parameters using a foreach loop and build the parameters string that we’ll send in the POST request body. As we iterate, first we check whether the parameter type ends with string . If it does, we create a string for a parameter value. To track which string values we use and to ensure each value is unique, we create a new Guid and use this as the parameter’s value. Using a ternary operation , we determine whether we should prefix the parameter with an ampersand. We then store the Guid in the Guid list. Once we have appended the parameter and value to the POST parameters string, we check the Boolean value and, if it is true, set it to false so that later POST parameters will be delineated with an ampersand.

Next, we need to send the POST parameters to the server and then read the response and check for any errors, as Listing 3-29 shows.

  int k = 0;
  foreach (Guid guid in guids)
  {
    string testParams = postParams.Replace(guid.ToString(), "fd'sa");
    byte[] data = System.Text.Encoding.ASCII.GetBytes(testParams);

    HttpWebRequest req = (HttpWebRequest) WebRequest.Create(url);
    req.Method = "POST";
    req.ContentType = "application/x-www-form-urlencoded";
    req.ContentLength = data.Length;
    req.GetRequestStream().Write(data, 0, data.Length);

    string resp = string.Empty;
    try
    {
      using (StreamReader rdr = new StreamReader(req.GetResponse().GetResponseStream()))
        resp = rdr.ReadToEnd();
    } catch (WebException ex)
    {
      using (StreamReader rdr = new StreamReader(ex.Response.GetResponseStream()))
        resp = rdr.ReadToEnd();

      if (resp.Contains("syntax error"))
        Console.WriteLine("Possible SQL injection vector in parameter: " + input.Parts[k].Name);
    }
    k++;
  }
}

Listing 3-29: Sending the POST parameters to the SOAP service and checking for server errors

To start off, we declare an integer named k, which will be incremented and used throughout the fuzzing to keep track of potentially vulnerable parameters, and we assign k a value of 0. Then we iterate over the Guid list using a foreach loop. As we iterate, the first thing we do is create a new POST parameter string by replacing the current Guid with a tainted value using the Replace() method . Because each Guid is unique, when we replace the Guid, it will only change a single parameter’s value. This lets us determine exactly which parameter has a potential vulnerability. Next, we send the POST request and read the response.

Once we have the new POST parameter string to send to the SOAP service, we convert the string to an array of bytes using the GetBytes() method that will be written to the HTTP stream. We then build the HttpWebRequest to send the bytes to the server and set the HttpWebRequest’s Method property to "POST", the ContentType property to application/x-www-form-urlencoded, and the ContentLength property to the size of the byte array. Once this is built, we write the byte array to the request stream by passing the byte array, the index of the array to begin writing from (0), and the number of bytes to write to the Write() method .

After the POST parameters have been written to the request stream, we need to read the response from the server. After declaring an empty string to hold the HTTP response, we use a try/catch block to catch any exceptions thrown while reading from the HTTP response stream. Creating a StreamReader in the context of a using statement, we attempt to read the entire response with the ReadToEnd() method and assign the response to an empty string. If the server responds with an HTTP code of 50x (which means an error occurred on the server side), we catch the exception, attempt to read the response again, and reassign the response string to the empty string to update it. If the response contains the phrase syntax error , we print a message alerting the user that the current HTTP parameter could be vulnerable to a SQL injection. To determine which parameter was vulnerable, we use the integer k as the index of the parameter list to get the current parameter’s Name. Finally, we increment the k integer by 1 so that the next parameter will be referenced in the next iteration, and then we start the process over again for the next POST parameter.

That completes the FuzzHttpGetPort() and FuzzHttpPostPort() methods. Next, we’ll write the FuzzSoapPort() method to fuzz the SOAP XML port.

Fuzzing the SOAP XML Port

In order to fuzz the SOAP XML port, we need to dynamically build XML to send to the server, which is slightly more difficult than building HTTP parameters to send in a GET or POST request. Starting off, though, the FuzzSoapPort() method is similar to FuzzHttpGetPort() and FuzzHttpPostPort(), as shown in Listing 3-30.

static void FuzzSoapPort(SoapBinding binding)
{
  SoapPortType portType = _wsdl.PortTypes.Single(pt => pt.Name == binding.Type.Split(':')[1]);

  foreach (SoapBindingOperation op in binding.Operations)
  {
    Console.WriteLine("Fuzzing operation: " + op.Name);
    SoapOperation po = portType.Operations.Single(p => p.Name == op.Name);
    SoapMessage input = _wsdl.Messages.Single(m => m.Name == po.Input.Split(':')[1]);

Listing 3-30: Gathering initial information to build dynamic SOAP XML

As with the GET and POST fuzzing methods, we need to collect some information about what we are going to fuzz before we can do anything. We first grab the corresponding SoapPortType from the _wsdl.PortTypes property using LINQ; then we iterate over each operation with a foreach loop. As we iterate, we print the current operation we are fuzzing to the console . In order to send the correct XML to the server, we need to select the SoapOperation and SoapMessage classes that correspond to the SoapBinding class passed to the method. Using the SoapOperation and SoapMessage, we can dynamically build the XML required. To do this, we use LINQ to XML, which is a set of built-in classes in the System.Xml.Linq namespace that lets you create simple, dynamic XML, as shown in Listing 3-31.

XNamespace soapNS = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace xmlNS = op.SoapAction.Replace(op.Name, string.Empty);
XElement soapBody = new XElement(soapNS + "Body");
XElement soapOperation = new XElement(xmlNS + op.Name);

soapBody.Add(soapOperation);

List<Guid> paramList = new List<Guid>();
SoapType type = _wsdl.Types.Single(t => t.Name == input.Parts[0].Element.Split(':')[1]);
foreach (SoapTypeParameter param in type.Parameters)
{
  XElement soapParam = new XElement(xmlNS + param.Name);
  if (param.Type.EndsWith("string"))
  {
    Guid guid = Guid.NewGuid();
    paramList.Add(guid);
    soapParam.SetValue(guid.ToString());
  }
  soapOperation.Add(soapParam);
}

Listing 3-31: Building the dynamic SOAP XML using LINQ to XML in the SOAP fuzzer

We first create two XNameSpace instances to use when building the XML. The first XNameSpace is the default SOAP namespace, but the second XNameSpace will change based on the current operation’s SoapAction property . After the namespaces are defined, we create two new XML elements using the XElement class. The first XElement (which will be called <Body>) is a standard XML element used in SOAP and will encapsulate the data for the current SOAP operation. The second XElement will be named after the current operation . The XElement instances use the default SOAP namespace and the SOAP operation namespace, respectively. We then add the second XElement to the first using the XElement Add() method so that the SOAP <Body> XML element will contain the SOAP operation element.

After creating the outer XML elements, we create a Guid list to store the values we generate, and we also select the current SoapType with LINQ so that we can iterate over the parameters required for the SOAP call. As we iterate, we first create a new XElement for the current parameter . If the parameter type is a string, we assign the XElement a Guid for a value using SetValue() and store the Guid in the Guid list we created for reference later. We then add the XElement to the SOAP operation element and move on to the next parameter.

Once we have completed adding the parameters to the SOAP operation XML node, we need to put the whole XML document together, as shown in Listing 3-32.

XDocument soapDoc = new XDocument(new XDeclaration("1.0", "ascii", "true"),
  new XElement(soapNS + "Envelope",
    new XAttribute(XNamespace.Xmlns + "soap", soapNS),
    new XAttribute("xmlns", xmlNS),
    soapBody));

Listing 3-32: Putting the whole SOAP XML document together

We need to create an XDocument with one more XElement called the SOAP Envelope . We create a new XDocument by passing a new XElement to the XDocument constructor. The XElement, in turn, is created with a couple of attributes defining the node’s XML namespaces, as well as with the SOAP body we built with the parameters .

Now that the XML is built, we can send the XML to the web server and attempt to induce SQL errors, as Listing 3-33 shows. Continue to add this code to the FuzzSoapPort() method.

int k = 0;
foreach (Guid parm in paramList)
{
  string testSoap = soapDoc.ToString().Replace(parm.ToString(), "fd'sa");
  byte[] data = System.Text.Encoding.ASCII.GetBytes(testSoap);
  HttpWebRequest req = (HttpWebRequest) WebRequest.Create(_endpoint);
  req.Headers["SOAPAction"] = op.SoapAction;
  req.Method = "POST";
  req.ContentType = "text/xml";
  req.ContentLength = data.Length;
  using (Stream stream = req.GetRequestStream())
    stream.Write(data, 0, data.Length);

Listing 3-33: Creating the HttpWebRequest to send the SOAP XML to the SOAP endpoint

As with the fuzzers covered previously in the chapter, we iterate over each Guid in the list of values that we created while building the XML for the SOAP operation. As we iterate, we replace the current Guid in the SOAP XML body with a value that should induce a SQL error if that value is being used in a SQL query unsafely . After we replace the Guid with the tainted value, we convert the resulting string into a byte array using the GetBytes() method, which we’ll write to the HTTP stream as POST data.

We then build the HttpWebRequest that we’ll use to make the HTTP request and read the result. One special piece to note is the SOAPAction header . This SOAPAction HTTP header will be used by the SOAP endpoint to determine which action is performed with the data, such as listing or deleting users. We also set the HTTP method to POST, the content type to text/xml, and the content length to the length of the byte array we created. Finally, we write the data to the HTTP stream . Now we need to read the response from the server and determine whether the data we sent induced any SQL errors, as Listing 3-34 shows.

   string resp = string.Empty;
   try
   {
     using (StreamReader rdr = new StreamReader(req.GetResponse().GetResponseStream()))
       resp = rdr.ReadToEnd();
   }
   catch (WebException ex)
   {
     using (StreamReader rdr = new StreamReader(ex.Response.GetResponseStream()))
       resp = rdr.ReadToEnd();

     if (resp.Contains("syntax error"))
       Console.WriteLine("Possible SQL injection vector in parameter: ");
       Console.Write(type.Parameters[k].Name);
   }
   k++;
  }
 }
}

Listing 3-34: Reading the HTTP stream in the SOAP fuzzer and looking for errors

Listing 3-34 uses almost the same code as the fuzzers in Listings 3-26 and 3-29 to check for a SQL error, but in this case we’re handling the detected error differently. First, we declare a string to hold the HTTP response and begin a try/catch block. Then, within the context of a using statement, we use a StreamReader to attempt to read the contents of the HTTP response and store the response in a string . If an exception is thrown because the HTTP server returned a 50x error, we catch the exception and try to read the response again. If an exception is thrown and the response data contains the phrase syntax error , we print a message to alert the user about a possible SQL injection and the potentially vulnerable parameter name. Finally, we increment k and go on to the next parameter.

Running the Fuzzer

We can now run the fuzzer against the vulnerable SOAP service appliance CsharpVulnSoap. The fuzzer takes a single argument: the URL to the vulnerable SOAP endpoint. In this case, we’ll use http://192.168.1.15/Vulnerable.asmx. Passing the URL as the first argument and running the fuzzer should yield similar output to Listing 3-35.

$ mono ch3_soap_fuzzer.exe http://192.168.1.15/Vulnerable.asmx
Fetching the WSDL for service: http://192.168.1.15/Vulnerable.asmx
Fetched and loaded the web service description.
Fuzzing service: VulnerableService
Fuzzing soap port: VulnerableServiceSoap
Fuzzing operation: AddUser
Possible SQL injection vector in parameter: username
Possible SQL injection vector in parameter: password
--snip--
Fuzzing http port: VulnerableServiceHttpGet
Fuzzing operation: AddUser
Fuzzing full url: http://192.168.1.15/Vulnerable.asmx/AddUser?username=a7ee0684-
fd54-41b4-b644-20b3dd8be97a&password=85303f3d-1a68-4469-bc69-478504166314
Possible SQL injection vector in parameter: username
Possible SQL injection vector in parameter: password
Fuzzing operation: ListUsers
Fuzzing full url: http://192.168.1.15/Vulnerable.asmx/ListUsers
--snip--
Fuzzing http port: VulnerableServiceHttpPost
Fuzzing operation: AddUser
Possible SQL injection vector in parameter: username
Possible SQL injection vector in parameter: password
Fuzzing operation: ListUsers
Fuzzing operation: GetUser
Possible SQL injection vector in parameter: username
Fuzzing operation: DeleteUser
Possible SQL injection vector in parameter: username

Listing 3-35: Partial output from the SOAP fuzzer running against the CsharpVulnSoap application

From the output, we can see the various stages of the fuzzing. Starting with the VulnerableServiceSoap port , we find that the AddUser operation might be vulnerable to SQL injection in the username and password fields passed to the operation. Next is the VulnerableServiceHttpGet port . We fuzz the same AddUser operation and print the URL we built, which we can paste into a web browser to see what the response of a successful call is. Again, the username and password parameters were found to be potentially vulnerable to SQL injection. Finally, we fuzz the VulnerableServiceHttpPost SOAP port , first fuzzing the AddUser operation, which reports the same as the previous ports. The ListUsers operation reports no potential SQL injections, which makes sense because it has no parameters to begin with. Both the GetUser and DeleteUser operations are potentially vulnerable to SQL injection in the username parameter.

Conclusion

In this chapter, you were introduced to the XML classes available from the core libraries. We used the XML classes to implement a full SOAP service SQL injection fuzzer, and we covered a few of the methods of interacting with a SOAP service.

The first and most simple method was via HTTP GET requests, where we built URLs with dynamic query string parameters based on the how the WSDL document described the SOAP service. Once this was implemented, we built a method to fuzz POST requests to the SOAP service. Finally, we wrote the method to fuzz the SOAP XML using the LINQ to XML libraries in C# to dynamically create the XML used to fuzz the server.

The powerful XML classes in C# make consuming and dealing with XML a breeze. With so many enterprise technologies reliant on XML for cross-platform communication, serialization, or storage, understanding how to efficiently read and create XML documents on the fly can be incredibly useful, especially for a security engineer or pentester.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset