The vulnerability to be detected for this challenge was an access control flaw due to improper handling of case sensitivity and improper validation of path equivalence.
The challenge resolution required knowledge of the Node.js web framework Express.
Note: This article is also available in french 🇫🇷. The challenge was announced in this tweet 🐦.
Explanation
By default, the routing of the Express framework is not case-sensitive. Let’s look at what the documentation is saying:
app.set(name, value)
…
Application Settings
…
Property Type Description Default case-sensitive routing Boolean Enable case sensitivity. When enabled, "/Foo" and "/foo" are different routes. When disabled, "/Foo" and "/foo" are treated the same. NOTE: Sub-apps will inherit the value of this setting. N/A (undefined) express.Router([options])
…
Property Description Default Availability caseSensitive Enable case sensitivity. Disabled by default, treating “/Foo” and “/foo” as the same. –
Therefore, routing to /secret
, /SECRET
, /SeCrEt
, etc. will have the same endpoint. On the other hand, the authentication middleware that is supposed to protect the /secret
endpoint is case-sensitive and only checks the token when the route starts exactly with /secret
. So contacting /secret
, or any other form with a different case, is enough to bypass the access control, because Express will still route the request correctly even though authentication will not be performed.
Fixed code
Here is the corrected code:
Here, the global settings of the application have been changed so that the routes are case-sensitive.
Another solution would have been to keep the application case-insensitive and only do a case-insensitive check for the /secret
route, but the same blunder could happen elsewhere in the code.
The source code is available on the Github repository Acceis/vulnerable-code-snippets.
About the author
Article written by Alexandre ZANNI aka noraj, Penetration Testing Engineer at ACCEIS.