Rating:
On the challenge we are given a website [https://base65536.ctf.insecurity-insa.fr/](https://base65536.ctf.insecurity-insa.fr/) if we browse to this website in our browser we get a 405 error, so we know the page is not expecting a GET request so let's try a POST request without data:
```
Param 'sample' is expected
```
So let's add the param sample with content-type as x-www-form-urlenconded
and we get the following response:
```
Your encrypted sample is ?ѕ and the flag is 劘??⯜䊍셶?釂?㈾ !
```
So it appears it encodes our input as Base65536 and also outputs the flag in base 65536 as well. Let's see if the enconding is the same by submitting a sample of string 'INSA' since we know that's part of the flag and we get the following response:
```
Your encrypted sample is 쎙? and the flag is 쎙???먚츘램✭ꋏ? !
```
From this output we can see the same encoding is used for the flag and our input, so it's rather simple to solve this.
At first I thought that every character encoded would result in a base65536 16 bit character(because 2\*\*16 == 65536) so I decided to create every possible combination of two characters like so:
```js
const alphabet="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}_-0123456789"
function generateNoRecursion(len, chars)
{
// Indices that indicate what char to use on corresponding place.
var indices = [];
for (var i = 0; i < len; ++i)
indices.push(0);
// While all indices in set of chars
while (indices[0] < chars.length)
{
// Print current solution
var str = "";
for (var i = 0; i < indices.length; ++i)
str += chars[indices[i]];
possibilities.push(str);
possibilities.push(str);
// Go to next solution by incrementing last index and adjusting
// if it is out of chars set.
indices[len-1]++;
for (var i = len-1; i > 0 && indices[i] == chars.length; --i)
{
indices[i] = 0;
indices[i-1]++;
}
}
}
generateNoRecursion(2, alphabet);
```
As I've said at first I thought only 2 byte chars were used for the encoding, but I was wrong, in fact it could be anything from 1 to 4 bytes that's why I push to the possibilities array the same string twice, so that I can later in the response figure out the number of enconded bytes.
So let's make a request with every possible combination and save each encoded pair of characters in a map/dictionary:
```js
function readNext(myEncodedInput) {
//shit code inc
if(myEncodedInput.length >= 8 && !(myEncodedInput[0] != myEncodedInput[4] || myEncodedInput[1] != myEncodedInput[5] || myEncodedInput[2] != myEncodedInput[6] || myEncodedInput[3] != myEncodedInput[7])) {
return myEncodedInput.slice(0, 4).toString('hex');
} else if(myEncodedInput.length >= 6 && !(myEncodedInput[0] != myEncodedInput[3] || myEncodedInput[1] != myEncodedInput[4] || myEncodedInput[2] != myEncodedInput[5])) {
return myEncodedInput.slice(0, 3).toString('hex');
} else if(myEncodedInput.length >= 4 && !(myEncodedInput[0] != myEncodedInput[2] || myEncodedInput[1] != myEncodedInput[3])) {
return myEncodedInput.slice(0, 2).toString('hex');
} else if(myEncodedInput.length >= 2 && !(myEncodedInput[0] != myEncodedInput[1])) {
return myEncodedInput.slice(0, 1.toString('hex');
}else{
console.log('warning unknown encoding');
process.exit(0);
}
}
function makeReq() {
request.post({
url: url,
encoding: null, //So that body is a buffer instead of string
form: {
sample: possibilities.join('')
}
}, function(err, response, body) {
var myInputEnd = body.indexOf(andTheFlagIs);
myEncodedInput = body.slice(0x19, myInputEnd);
flag = body.slice(myInputEnd + andTheFlagIs.length, body.length - 3);
var map = {};
for(var i = 0; i < possibilities.length; i += 2) {
var hexCode = readNext(myEncodedInput);
myEncodedInput = myEncodedInput.slice(hexCode.length);
map[hexCode] = possibilities[i];
//console.log(`map[${hexCode}] = ${map[hexCode]}`);
}
readTheFlag(map, flag)
})
}
```
With this done we only need to decode the flag with out generated map like so:
```js
function readTheFlag(map, flag) {
const decodedFlag = []
while(flag.length !== 0) {
for(var i = 0; i < 4; i++) {
const code = flag.slice(0, i+1).toString('hex');
const code = s[i].apply(this, flag.slice(0, 4));
if(map[code] !== undefined)
{
decodedFlag.push(map[code])
flag = flag.slice(i + 1)
break;
}
}
}
console.log(decodedFlag.join(''))
}
```
Put it all together and we get the flag:
**INSA{655e6_is_T0_Much}**