JavaScript

Stage 001

BRIEFING

Difficulty: Introductory

We heard you like JavaScript? So we scrambled some nice JavaScript ☕ code for you to review! Review the provided code snippet and send appropriate API request to get the flag!

Stage 001: http://js.pwn.site:1995/

Work/Solution

Here's the challenge:

ctf-notes/sans/offensive-ops-ctf-2024/assets/Pasted image 20240228101135.png

router.post('/api/stages/1', async (req, res) => {
	const { password } = req.body;

	if (password == "b" + "a" + +"a" + "a") {
		return res.json({ flag: flags[0] });
	}

	return res.status(401).json({ message: 'No flag for you!' });
});

The exact format of the POST request took me a while to figure out. An embarrassingly long while actually.

Anyway, first I used my browser console to get the exact string that would be used in the compare statement on the server side of things.

var testPass = "b" + "a" + +"a" + "a"
> undefined
console.log(testPass)
> baNaNa

Then I POSTed the string to the API endpoint as JSON.

POST /api/stages/1 HTTP/1.1
Host: js.pwn.site:1995
Accept: application/json
Connection: close
Content-Type: application/json
Content-Length: 23

{ "password":"baNaNa" }
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 47
Date: Wed, 28 Feb 2024 15:39:09 GMT
Connection: close

{"flag":"flag{B-baNaNa?baNaNa!baNaNa!baNaNa!}"}

Stage 002

BRIEFING

Difficulty: Introductory

We heard you like JavaScript? So we scrambled some nice JavaScript ☕ code for you to review! Review the provided code snippet and send appropriate API request to get the flag!

Stage 002: http://js.pwn.site:1995/stage2

Work/Solution

ctf-notes/sans/offensive-ops-ctf-2024/assets/Pasted image 20240228105023.png

router.post('/api/stages/1', async (req, res) => {
	const { password } = req.body;

	if (password == "b" + "a" + +"a" + "a") {
		return res.json({ flag: flags[0] });
	}

	return res.status(401).json({ message: 'No flag for you!' });
});
var password = 0.1 + 0.2
> undefined
console.log(password)
> 0.30000000000000004
POST /api/stages/2 HTTP/1.1
Host: js.pwn.site:1995
Accept: application/json
Connection: close
Content-Type: application/json
Content-Length: 36

{ "password":"0.30000000000000004" }
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 44
Date: Wed, 28 Feb 2024 15:52:32 GMT
Connection: close

{"flag":"flag{IEEE-754-floating-with-you!}"}

Stage 003

BRIEFING

Difficulty: Introductory

We heard you like JavaScript? So we scrambled some nice JavaScript ☕ code for you to review! Review the provided code snippet and send appropriate API request to get the flag!

Stage 003: http://js.pwn.site:1995/stage3

Work/Solution

ctf-notes/sans/offensive-ops-ctf-2024/assets/Pasted image 20240228105355.png

router.post('/api/stages/3', async (req, res) => {
    const { password } = req.body;

    const secret = ([] + {})[+!![]] +
        (![] + {})[+!![] + [+[]]] +
        (!![] + [])[+[]] +
        ([] + {})[+!![]] +
        (![] + {})[+!![] + [+[]]] +
        (![] + [])[+!![]] +
        (!![] + [])[+[]];

    if (password == secret) {
        return res.json({ flag: flags[2] });
    }

    return res.status(401).json({ message: 'No flag for you!' });
});
var secret = ([] + {})[+!![]] +
        (![] + {})[+!![] + [+[]]] +
        (!![] + [])[+[]] +
        ([] + {})[+!![]] +
        (![] + {})[+!![] + [+[]]] +
        (![] + [])[+!![]] +
        (!![] + [])[+[]];
> undefined
console.log(secret)
> octocat
POST /api/stages/3 HTTP/1.1
Host: js.pwn.site:1995
Accept: application/json
Connection: close
Content-Type: application/json
Content-Length: 24

{ "password":"octocat" }
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 41
Date: Wed, 28 Feb 2024 15:57:23 GMT
Connection: close

{"flag":"flag{w31rD-j4v45cr1p7-m0m3nt!}"}

Stage 004

BRIEFING

Difficulty: Introductory

We heard you like JavaScript? So we scrambled some nice JavaScript ☕ code for you to review! Review the provided code snippet and send appropriate API request to get the flag!

Stage 004: http://js.pwn.site:1995/stage4

Work/Solution

ctf-notes/sans/offensive-ops-ctf-2024/assets/Pasted image 20240228105907.png

router.post('/api/stages/4', async (req, res) => {
    const { days } = req.body;

    if ( typeof days !== "number" ) {
        return res.status(401).json({ message: 'Only days in number is accepted!' });
    }

    let dayOfWeek = Math.abs(parseInt(days) % 7);

    switch(dayOfWeek) {
        case 0:
            day = "Saturday";
            break;
        case 1:
            day = "Sunday";
            break;
        case 2:
            day = "Monday";
            break;
        case 3:
            day = "Tuesday";
            break;
        case 4:
            day = "Wednesday";
            break;
        case 5:
            day = "Thursday";
            break;
        case 6:
            day = "Friday";
            break
        default:
            day = "Payday";
    }

    if (day == "Payday" ) {
        return res.json({ flag: flags[3] });
    }

    return res.status(401).json({ message: 'No flag for you!' });
});

This one took quite a while also. I struggled with how we could possibly get a remainder larger than the divisor, which is obviously impossible. I also looked at trying to send objects of the Number JS type that weren't regular numbers, which included undefined, NaN, and Infinity, however all these were returning with 400 bad request errors.

I searched for how to represent Infinity in JSON, and discovered that 1e500 represents Infinity in JavaScript/JSON.

POST /api/stages/4 HTTP/1.1
Host: js.pwn.site:1995
Accept: application/json
Connection: close
Content-Type: application/json
Content-Length: 15

{ "days":1e500}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 38
Date: Wed, 28 Feb 2024 16:38:13 GMT
Connection: close

{"flag":"flag{t00-biiiig-to-handle!}"}