siunam's Website

My personal website

Home Writeups Blog Projects About E-Portfolio

Referrrrer

Table of Contents

  1. Overview
  2. Background
  3. Enumeration
  4. Exploitation
  5. Conclusion

Overview

Background

Defeated the security of the website which implements authentication based on the Referer header.

URL : http://static-01.heroctf.fr:7000
Format : Hero{flag}
Author : xanhacks

Enumeration

Home page:

Seems empty??

In this challenge, we can download a file:

┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Web/Referrrrer)-[2023.05.13|13:58:02(HKT)]
└> file Referrrrer.zip 
Referrrrer.zip: Zip archive data, at least v1.0 to extract, compression method=store
┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Web/Referrrrer)-[2023.05.13|13:58:03(HKT)]
└> unzip Referrrrer.zip 
Archive:  Referrrrer.zip
   creating: app/
  inflating: app/package.json        
  inflating: app/index.js            
  inflating: app/package-lock.json   
  inflating: app/Dockerfile          
  inflating: docker-compose.yml      
   creating: nginx/
  inflating: nginx/nginx.conf

In app/index.js, we see this:

const express = require("express")
const app = express()


app.get("/", (req, res) => {
    res.send("Hello World!");
})

app.get("/admin", (req, res) => {
    if (req.header("referer") === "YOU_SHOUD_NOT_PASS!") {
        return res.send(process.env.FLAG);
    }

    res.send("Wrong header!");
})

app.listen(3000, () => {
    console.log("App listening on port 3000");
})

When we send a GET request to /admin, if the request header Referer is strictly equal to YOU_SHOUD_NOT_PASS!, it’ll response us with the flag.

With that said, we have to some how pass the header check…

In nginx/nginx.conf, we can see there’s a rule for location /admin:

[...]
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://express_app;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /admin {
        if ($http_referer !~* "^https://admin\.internal\.com") {
            return 403;
        }

        proxy_pass http://express_app;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
[...]

If the Referer header is equal to https://admin.internal.com, it’ll let us pass go to /admin.

So… We need to provide Referer header with 2 value: https://admin.internal.com AND YOU_SHOUD_NOT_PASS!?

However, I tried to include 2 Referer header in the /admin request:

But it doesn’t work, because it only checks the first Referer header and ignoring the second one.

Exploitation

After some research, I found this StackOverflow post:

Oh! They are the same thing in Express 4.x?

Let’s try that!

Nice! We got the flag!

Conclusion

What we’ve learned:

  1. Exploiting Referer-based Access Control In Node.js Express