Python for Security Automation
Security professionals rarely perform attacks one HTTP request at a time. Real-world penetration testing, bug hunting, and CTF competitions all require the ability to send dozens — sometimes thousands — of crafted requests in rapid succession, parse responses programmatically, and extract results automatically. Python has become the language of choice for this kind of work, and understanding why will make you a far more effective practitioner.
Why Python?
Python occupies a sweet spot between expressiveness and ecosystem. You can write a working HTTP exploit in under twenty lines, import a battle-tested library with a single command, and run the result immediately without a compilation step. The language's readable syntax lowers the barrier between "I understand what this attack does conceptually" and "I have a working proof of concept."
The security community has also converged on Python. Tools such as Scapy (packet crafting), Impacket (Windows protocol exploitation), Volatility (memory forensics), and many Metasploit modules are Python-based. When you learn Python for scripting, you gain the ability to read, modify, and extend those tools as well.
The requests Library
The requests library is the standard way to make HTTP calls from Python. It is not part of the standard library, but it is installed almost everywhere security tooling runs.
The key calls you will use in this lab:
import requests
# Send a POST request with a JSON body
response = requests.post(url, json={"key": "value"}, headers={"Authorization": "Bearer token"})
# Check the status code
print(response.status_code) # e.g. 200, 403, 500
# Read the body as a string
print(response.text)
# Parse the body as JSON directly
data = response.json()requests handles cookies, redirects, TLS certificates, and connection pooling automatically. For exploit scripting it is almost always sufficient.
The re Module — Regular Expressions
Once you have a response, you need to extract useful information from it. The re module (built into Python's standard library) gives you compiled regular expressions — patterns that describe the shape of text you are looking for.
import re
body = '{"result": "49", "debug": "CTF{py7h0n_4ut0m4tes_4tt4cks}"}'
# Search for a pattern anywhere in the string
match = re.search(r'CTF\{[^}]+\}', body)
if match:
flag = match.group(0) # group(0) is the entire match
print(flag) # CTF{py7h0n_4ut0m4tes_4tt4cks}The pattern CTF\{[^}]+\} reads as: the literal text CTF{, then one or more characters that are not }, then the closing }. This is precisely the shape of a CTF flag.
File I/O
Exploit scripts frequently log results to disk so they can be shared with a teammate, attached to a bug report, or reviewed later. Python's built-in open() function makes this straightforward:
with open("results.txt", "w") as f:
f.write(flag)The with statement ensures the file is closed properly even if an exception occurs. Writing in "w" mode creates the file if it does not exist and overwrites it if it does.
Server-Side Template Injection (SSTI)
The vulnerability this lab exploits is Server-Side Template Injection (SSTI). Many web applications use a templating engine — such as Jinja2 in Python Flask applications — to generate dynamic HTML. The engine processes a template string and replaces placeholders like {{ username }} with real values before sending the response.
SSTI occurs when an application passes **user-supplied input directly into render_template_string()** (or an equivalent function) instead of only substituting it as a variable. When this happens, the template engine evaluates your input as part of its own expression language.
A classic confirmation payload is {{7*7}}. If the server echoes back 49 rather than the literal string {{7*7}}, the input is being rendered by the engine and the application is vulnerable. From there, attackers can escalate to reading files, executing system commands, or dumping sensitive environment variables.
In this lab, the endpoint at http://vuln-app.internal/api/search is intentionally vulnerable to SSTI via Jinja2. Your script will send a confirmation payload, detect the evaluated result in the response body, and extract the flag that the server embeds in its debug output when the injection succeeds.
What You Will Build
Your task is to complete a skeleton Python script that:
- Constructs the SSTI payload string.
- Sets the correct
Content-Typeheader. - Sends the request using
requests.post. - Reads the HTTP status code from the response.
- Uses a regular expression to extract the CTF flag from the response body.
When all five sections are filled in correctly, running the script produces the flag, writes it to results.txt, and prints it to the console.