Introduction
As part of the Product Security Intern assignment for Fam (Trio), I was tasked with a Capture The Flag (CTF) challenge. The objective was straightforward yet testing: analyze an Android APK, identify vulnerabilities, navigate through a web challenge, and capture a hidden flag.
This write-up details my methodology, the “happy accidents” encountered along the way, and a comprehensive report on the security findings.
Phase 1: Reconnaissance & Static Analysis
The challenge began at https://challenge.fam-app.in. The landing page presented a clean interface asking for a “Secret” to proceed, along with a download link for an Android application (fam-CTF.apk).
Press enter or click to view image in full size
My first step was to perform static analysis on the provided APK file. Instead of running the app immediately, I wanted to inspect its internal structure. I uploaded the fam-CTF.apk to a Java decompiler to inspect the source code and resources.
The Discovery:
While browsing the AndroidManifest.xml file, I noticed a suspicious meta-data tag. Developers often leave API keys or configuration secrets in the manifest, and this case was no exception.
Press enter or click to view image in full size
I found the following entry:
<meta-data android:name="com.famctf.API_KEY" android:value="f4m_53cr37_70k3n" />The value f4m_53cr37_70k3n looked exactly like the API_KEY secret required on the web portal.
Phase 2: Gaining Access & Web Enumeration
Armed with the key found in the APK, I returned to the challenge website.
- I entered f4m_53cr37_70k3n into the secret input field.
- Upon submission, I was redirected to a new endpoint.
Press enter or click to view image in full size
The new page featured a simple file upload interface. In CTF scenarios, file upload forms are prime targets for Remote Code Execution (RCE) via malicious scripts (like PHP shells) or metadata exploits.
Phase 3: Exploitation & The “Happy Accident”
I initially attempted to upload a standard PHP backdoor (<?php $_GET[“cmd”] ?>) to see if I could execute commands on the server.
- Observation: The server accepted the PHP file without filtering the extension or MIME type.
- Result: However, on navigating to /uploads/filename.ext, the server returned the file content as plain text. The PHP was not executed, meaning the server was likely not configured to run PHP files in the upload directory.
The Pivot:
I decided to test how the server handled image files. I uploaded a PNG file. Interestingly, the server response headers contained a custom field: X-Message.
When I uploaded my PHP script earlier, the header read: “This is not a reverse code. Try harder!”
Press enter or click to view image in full size
However, when I uploaded a specific AI-generated image (a cat in a Dr. Strange outfit), the behavior changed entirely. The server responded with a 200 OK and a crucial set of headers:
Press enter or click to view image in full size
The Response Headers:
- X-Message: “Token generated. Use this token to access /new-assignment-security-intern”
- X-Auth-Token: a95e1f4e-2c67–4c91-ba08–98d3a63eda4b
- X-Endpoint-Hint: c3VibWl0LWFzc2lnbm1lbnQ=
Analysis of the “Accident”:
Why did a PNG trigger a success state when a PHP shell failed?
Upon inspecting the image metadata, I realized the AI-generated image contained Adobe XML tags (<x:xmpmeta…>). It appears the server-side security check was using a Regex or string matching to look for “code-like” syntax to detect reverse shells. Paradoxically, the innocent XML metadata in the image likely triggered a “False Positive” in the server’s security logic, which the system interpreted as a successful “exploit” of the level, granting me the token.
Phase 4: Token Enumeration & Flag Capture
With the token and the endpoint hint, I moved to the final stage.
Get Nishith P’s stories in your inbox
Join Medium for free to get updates from this writer.
Step 1: Decrypting the Hint
The header X-Endpoint-Hint contained a Base64 string: c3VibWl0LWFzc2lnbm1lbnQ=
Decoding this gave me the slug: submit-assignment.
Step 2: Retrieving Instructions
I navigated to /new-assignment-security-intern using the token I acquired. I passed it as a query parameter ?token=….
Press enter or click to view image in full size
The response provided a JSON object with instructions on how to submit the flag:
- Endpoint: /c3VibWl0LWFzc2lnbm1lbnQ= (which is /submit-assignment)
- Method: POST
- Body: JSON containing email, flag, name, and phone-number.
- Flag Logic: The response included a flag field: “RkBNe1NFQ18zNzM3M19IM3kwMDkxMTB9==”.
Step 3: The Final Submission
I constructed a POST request in Burp Suite to the submission endpoint.
Press enter or click to view image in full size
The server responded: “Submission received successfully”.
Step 4: Decoding the Flag
The challenge provided the final flag in Base64 format. Running it through a decoder revealed the victory text.
Press enter or click to view image in full size
Post-Mortem & Security Report
Vulnerability Analysis
- Hardcoded Credentials (APK):
The most critical vulnerability was the storage of the API key (f4m_53cr37_70k3n) in plain text within the AndroidManifest.xml. This allowed for trivial bypass of the initial authentication layer. - Insecure File Upload Logic:
The server lacked strict validation on file contents. While it didn’t execute PHP (a good defense), its detection mechanism for “malicious code” (Reverse Shell detection) was flawed. It relied on pattern matching that produced false positives on legitimate file metadata (Adobe XMP data), inadvertently allowing an attacker to bypass the challenge logic. - Token Re-use & Predictability:
During testing, I noticed the server mapped generated tokens to filenames.
- Uploading image.png generated Token A.
- Uploading image.png again (overwriting it) returned Token A.
- Renaming the file to image2.png generated Token B.
This suggests a deterministic generation or weak session management tied to file attributes rather than user sessions.
Recommendations
To improve the security posture of the application, I recommend the following:
- Secrets Management: Never hardcode API keys or secrets in the client-side code (APK). Use Android Keystore or fetch session-specific tokens from a secure backend upon user authentication.
- Robust File Validation:
- Implement strict allow-listing for file types (check Magic Bytes, not just extensions).
- Strip metadata (EXIF/XMP) from images upon upload to prevent payload hiding and logic errors like the one encountered.
- Logic Improvement: The “Reverse Shell” detection mechanism seems to rely on weak regex. It should be replaced with actual behavioral analysis or simply by ensuring the upload directory is non-executable ( noexec).
- Data Transmission: The challenge required sending the flag in Base64. In a production environment, sensitive data should never be encoded merely in Base64; use transport security and consider payload encryption if the data is highly sensitive. For example, we can use PGP keys with Emails for sending confidential data.
Conclusion
This challenge was a fantastic exercise in combining mobile reconnaissance with web exploitation. It highlighted how even “secure” file uploaders can have logic flaws and reinforced the golden rule of mobile dev: The Manifest is not a safe functionality.
Final Flag: F@M{SEC_58392_1765982406}