Introduction
Bypass the security of a website that implements Referer-based authentication.
Solution
By looking at the challenge sources, we find two folders: app
and nginx
.
In the nginx
folder, we find an nginx.conf
file that contains the server’s configuration.
|
|
We can see that there is a /admin
location that checks if the Referer
header starts with https://admin.internal.com
. If it doesn’t, a 403 error is returned.
On the app
side, there is an index.js
file that contains the server’s code.
|
|
These are the only files that are useful to solve the challenge.
We understand that the goal of the challenge is to access the /admin
endpoint to retrieve the flag.
There are two checks to pass:
- In
nginx.conf
: the$http_referer
variable must start withhttps://admin.internal.com
. - In
index.js
: thereq.header("referer")
variable must be equal toYOU_SHOUD_NOT_PASS!
.
By taking a closer look at the Referer
header, we find this page that explains that this header is sent by the browser when clicking on a link.
We also learn that “referer” is a misspelling of “referrer,” which is why it is written with a single “r.”
In nginx, $http_referer
is a variable that contains the value of the Referer
header sent by the browser.
However, for index.js
, req.header("referer")
is a function that does not work like the other getters.
On the official documentation of req.get(...)
in Express v4.x, we learn that this function returns the value of the Referer
or Referrer
header sent by the browser.
This is where the vulnerability of the challenge lies.
We can craft a request that contains the Referrer
header with the value YOU_SHOUD_NOT_PASS!
and the Referer
header with the value https://admin.internal.com
.
|
|
Flag: Hero{ba7b97ae00a760b44cc8c761e6d4535b}
Alternative Solution
It is possible to bypass the nginx check by exploiting the fact that Express routes are case-insensitive while nginx routes are case-sensitive.
Accessing the /Admin
route will not trigger the nginx check on $http_referer
since the nginx route is /admin
.
Express, on the other hand, does not differentiate between /admin
and /Admin
and triggers the check on req.header("referer")
.
The Express check passes if req.header("referer")
is equal to YOU_SHOUD_NOT_PASS!
.
|
|
Tips & Tricks
- The header
Referer
is a misspelling ofReferrer
(source). $http_referer
is an nginx variable that contains the value of theReferer
header sent by the browser.- In Express v4.x, calling the function
req.get("referer")
returns the value of theReferer
orReferrer
header sent by the browser. - Route names exposed with Express v4.x are case-insensitive;
/Admin
and/admin
are equivalent (source).CaseSensitive: Disabled by default, treating “/Foo” and “/foo” as the same.
- Route names in the nginx
location
configuration are case-sensitive;/Admin
and/admin
are not equivalent.