CHALLENGE NAME#
NeoVault#
Description:
Neovault is a trusted banking application that allows users to effortlessly transfer funds to one another and conveniently download their transaction history. We invite you to explore the application for any potential vulnerabilities and uncover the flag hidden within its depths.
📝 Related Bug Bounty Reports
Bug Report #1Â -Â Mongo Object ID Prediction
Bug Report #2Â -Â IDOR
First, I read the two given reports, which really helped set my expectations for the challenge. I began my initial phase by visiting the website, noting its technologies, and navigating every available page. By doing that I saw there was only a login page and a register page. I quickly signed up for an account, logged into the web application, then fired up Burp Suite and started clicking every button I could find. While poking around, I saw a request that exposed some IDs and usernames:
I was logged in as user102
, but the response also revealed another user, neosystem
, which I noted. After spending some time without any obvious leads, I looked into the JavaScript files and yes, I found what I expected. There were some juciey endpoints , which I discovered:
What was interesting was that there was an /api/v1
namespace, while most dashboard features used /api/v2
except for the deposit feature, which didn’t work under v2. I tried hitting several /api/v1
endpoints, but most returned:
API version 1.0 is deprecated .
I kept wondering if the developer had forgotten to remove some old routes. That thought led me back to exploring every request until I reached the transaction history page, where you can download your transaction history as a PDF:
When I clicked “Download PDF,” Burp showed a POST to /api/v2/transactions/download-transactions
:
I replaced v2
with v1
in the URL and got a new, intriguing error:
The response complained that _id
was not provided at that moment I knew I’d found my way in. I added the header
ContentType: applicationjson
and included an _id
parameter in the JSON body:
{ "_id": "replacetheid" }
First, I used my own _id
to verify if it downloads my PDF or not, which it did:
Next, I swapped in neosystem
’s _id
and I was able to download that user’s PDF too. Inside, it mentioned user_with_flag
, hinting that I should target that account next:
╰─ python3 mongo-object.py 685faa8d76d134ba8f5bc5c6 > ../id.txt
Then I fuzzed the _id
parameter in the request body using ffuf:
└──╼ $ffuf -X POST -u "http://83.136.255.113:54902/api/v1/transactions/download-transactions" -H "Content-Type: application/json" -H "Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY4NWY5YTIxNDViYTNmYzI0ODFiYWVlMSIsImlhdCI6MTc1MTA5NTg4NywiZXhwIjoxNzUxMDk5NDg3fQ.AFZsJaD3Mmunb0soNw-GTTNnsS8fuYxJRe3x_sCkA7I" -d '{"_id": "FUZZ"}' -w id.txt
SNIP................
685f985145ba3fc2481baea0 [Status: 200, Size: 1936, Words: 142, Lines: 121, Duration: 176ms]
Within minutes, I got a match. I plugged that ID into my request, downloaded the PDF, and finally retrieved the flag.