<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Luca Reggiannini</title><link>https://reggia.xyz/index.html</link><description>Recent content on Luca Reggiannini</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sat, 11 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://reggia.xyz/index.xml" rel="self" type="application/rss+xml"/><item><title>DNS Reverse Shell using arbitrary domain names (google.com)</title><link>https://reggia.xyz/posts/dns-reverse-shell-using-arbitrary-domain-names.html</link><pubDate>Sat, 11 Apr 2026 00:00:00 +0000</pubDate><guid>https://reggia.xyz/posts/dns-reverse-shell-using-arbitrary-domain-names.html</guid><description/></item><item><title>Reverse Shell without Internet access (COM Port &amp; Rogue AP)</title><link>https://reggia.xyz/posts/reverse-shell-without-internet-access.html</link><pubDate>Wed, 24 Dec 2025 00:00:00 +0000</pubDate><guid>https://reggia.xyz/posts/reverse-shell-without-internet-access.html</guid><description/></item><item><title>Invisible Unicode Obfuscation: Beyond GlassWorm</title><link>https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html</link><pubDate>Thu, 18 Dec 2025 00:00:00 +0000</pubDate><guid>https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html</guid><description>&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href="https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html#introduction"&gt;Introduction&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html#research"&gt;Research&lt;/a&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href="https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html#encoding-logic"&gt;Encoding logic&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html#poc"&gt;POC&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html#simulation"&gt;Simulation&lt;/a&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href="https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html#windows"&gt;Windows&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html#linux"&gt;Linux&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html#detection"&gt;Detection&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html#references"&gt;References&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;&#10;&lt;p&gt;While analyzing several malware samples, I recently observed the use of &lt;em&gt;mock directories&lt;/em&gt; (folders crafted to closely resemble default Windows directories but containing embedded spaces) to mislead analysts. A documented example of this technique can be found here: &lt;a href="https://security.googlecloudcommunity.com/community-blog-42/finding-malware-dirtybulk-and-friends-usb-infections-to-fuel-cybercriminal-coinmining-operations-5552"&gt;https://security.googlecloudcommunity.com/community-blog-42/finding-malware-dirtybulk-and-friends-usb-infections-to-fuel-cybercriminal-coinmining-operations-5552&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm/0.png" alt="Mock Windows folders with deceptive embedded spaces" width="748" height="55" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;div class="img-caption"&gt;Mock directories abusing embedded spaces to visually mimic legitimate Windows folders&lt;/div&gt;&#10;&#10;&lt;p&gt;Shortly after, John Hammond released a video on &lt;strong&gt;GlassWorm&lt;/strong&gt;&lt;br&gt;&#10;(&lt;a href="https://www.youtube.com/watch?v=0XumkGQFEEk"&gt;https://www.youtube.com/watch?v=0XumkGQFEEk&lt;/a&gt;), a malware that infects VS Code extensions by embedding obfuscated payloads made of &lt;em&gt;invisible Unicode characters&lt;/em&gt; directly into the source code. These characters are visually similar to whitespace, making the malicious logic extremely hard to notice.&lt;/p&gt;</description></item><item><title>Invisible Unicode Obfuscator</title><link>https://reggia.xyz/tools/invisible-unicode-obfuscator.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://reggia.xyz/tools/invisible-unicode-obfuscator.html</guid><description>&lt;p&gt;Client-side tool that encodes and decodes strings using 420 invisible Unicode characters. It allows selecting the Unicode character pair used for binary encoding, shows a codepoint reveal view, and supports local export of encoded, decoded, and revealed data. Implemented in JavaScript and executed entirely in the browser; no data is sent or transmitted anywhere. Read more about the context and practical use cases of this tool in &lt;a href="https://reggia.xyz/posts/invisible-unicode-obfuscation-beyond-glassworm.html"&gt;this article&lt;/a&gt;.&lt;/p&gt;&#10;&#10;&#10;&#10; &lt;style&gt;&#10;&#9;.io-box {&#10;&#9;&#9;width: 100%;&#10;&#9;&#9;height: 100px;&#10;&#9;&#9;box-sizing: border-box;&#10;&#9;}&#10;&#9;.action-row {&#10;&#9;&#9;margin-top: 8px;&#10;&#9;&#9;display: flex;&#10;&#9;&#9;gap: 8px;&#10;&#9;&#9;align-items: center;&#10;&#9;&#9;flex-wrap: wrap;&#10;&#9;}&#10;&lt;/style&gt;&#10;&#10;&lt;div&gt;&#10;&#9;&lt;label&gt;Mode:&lt;/label&gt;&#10;&#9;&lt;select id="mode" onchange="updateMode()"&gt;&#10;&#9;&#9;&lt;option value="encode" selected&gt;Encode&lt;/option&gt;&#10;&#9;&#9;&lt;option value="decode"&gt;Decode&lt;/option&gt;&#10;&#9;&lt;/select&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;div style="margin-top:8px;"&gt;&#10;&#9;&lt;label&gt;Plain / decoded&lt;/label&gt;&lt;br&gt;&#10;&#9;&lt;textarea id="plain" class="io-box"&gt;&lt;/textarea&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;div id="encodeOptions" style="margin-top:8px;"&gt;&#10;&#9;&lt;label&gt;Unicode for bit 0:&lt;/label&gt;&#10;&#9;&lt;select id="u0"&gt;&lt;/select&gt;&#10;&#10;&#9;&lt;label style="margin-left:12px;"&gt;Unicode for bit 1:&lt;/label&gt;&#10;&#9;&lt;select id="u1"&gt;&lt;/select&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;div class="action-row"&gt;&#10;&#9;&lt;button type="button" id="actionBtn" onclick="onAction()"&gt;Encode ↓&lt;/button&gt;&#10;&#10;&#9;&lt;!-- Encode-mode buttons --&gt;&#10;&#9;&lt;button type="button" id="saveEncodedBtn" onclick="saveEncoded()" disabled&gt;Save encoded&lt;/button&gt;&#10;&#9;&lt;button type="button" id="saveRevealBtn" onclick="saveReveal()" disabled&gt;Save revealed&lt;/button&gt;&#10;&#10;&#9;&lt;!-- Decode-mode button --&gt;&#10;&#9;&lt;button type="button" id="saveDecodedBtn" onclick="saveDecoded()" disabled&gt;Save decoded&lt;/button&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;div style="margin-top:8px;"&gt;&#10;&#9;&lt;label&gt;Invisible / encoded&lt;/label&gt;&lt;br&gt;&#10;&#9;&lt;textarea id="obf" class="io-box"&gt;&lt;/textarea&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;div style="margin-top:8px;"&gt;&#10;&#9;&lt;label&gt;Reveal (codepoints)&lt;/label&gt;&lt;br&gt;&#10;&#9;&lt;textarea id="reveal" class="io-box" readonly style="background:var(--code-background-color);"&gt;&lt;/textarea&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;div id="error" style="margin-top:8px; color:red; font-weight:bold;"&gt;&lt;/div&gt;&#10;&#10;&lt;script&gt;&#10;const INV_CP = [&#10;&#9;0x0009,0x000A,0x000D,0x001B,0x0020,0x00A0,0x00AD,0x034F,0x061C,&#10;&#9;0x115F,0x1160,0x1680,0x180E,0x2028,0x2029,0x202F,0x205F,&#10;&#9;0x2800,0x3000,0x3164,0xFEFF,0xFFA0&#10;];&#10;&#10;function addRange(start, end) {&#10;&#9;for (let cp = start; cp &lt;= end; cp++) INV_CP.push(cp);&#10;}&#10;&#10;addRange(0x2000, 0x200F);&#10;addRange(0x202A, 0x202E);&#10;addRange(0x2060, 0x206F);&#10;addRange(0xFE00, 0xFE0F);&#10;addRange(0x1D173, 0x1D17A);&#10;INV_CP.push(0xE0001);&#10;addRange(0xE0020, 0xE007F);&#10;addRange(0xE0100, 0xE01EF);&#10;&#10;function buildSelect(id, defCp) {&#10;&#9;const sel = document.getElementById(id);&#10;&#9;sel.innerHTML = "";&#10;&#9;INV_CP.forEach(cp =&gt; {&#10;&#9;&#9;const opt = document.createElement("option");&#10;&#9;&#9;const hex = cp.toString(16).toUpperCase();&#10;&#9;&#9;const padded = cp &gt; 0xFFFF ? hex.padStart(5,"0") : hex.padStart(4,"0");&#10;&#9;&#9;opt.value = String.fromCodePoint(cp);&#10;&#9;&#9;opt.textContent = "U+" + padded;&#10;&#9;&#9;if (cp === defCp) opt.selected = true;&#10;&#9;&#9;sel.appendChild(opt);&#10;&#9;});&#10;}&#10;&#10;document.addEventListener("DOMContentLoaded", () =&gt; {&#10;&#9;document.getElementById("mode").value = "encode";&#10;&#9;document.getElementById("plain").value = "";&#10;&#9;document.getElementById("obf").value = "";&#10;&#9;document.getElementById("reveal").value = "";&#10;&#9;document.getElementById("error").textContent = "";&#10;&#10;&#9;buildSelect("u0", 0x0020); // SPACE&#10;&#9;buildSelect("u1", 0x0009); // TAB&#10;&#10;&#9;document.getElementById("obf").addEventListener("input", onObfChange);&#10;&#9;document.getElementById("plain").addEventListener("input", updateSaveButtons);&#10;&#10;&#9;updateMode();&#10;});&#10;&#10;function updateMode() {&#10;&#9;const mode = document.getElementById("mode").value;&#10;&#9;const encOpts = document.getElementById("encodeOptions");&#10;&#9;const btn = document.getElementById("actionBtn");&#10;&#9;const plain = document.getElementById("plain");&#10;&#9;const obf = document.getElementById("obf");&#10;&#9;const reveal = document.getElementById("reveal");&#10;&#9;const error = document.getElementById("error");&#10;&#10;&#9;plain.value = "";&#10;&#9;obf.value = "";&#10;&#9;reveal.value = "";&#10;&#9;error.textContent = "";&#10;&#10;&#9;// Toggle encode/decode UI behavior&#10;&#9;if (mode === "encode") {&#10;&#9;&#9;encOpts.style.visibility = "visible";&#10;&#9;&#9;btn.textContent = "Encode ↓";&#10;&#9;&#9;plain.readOnly = false;&#10;&#9;&#9;plain.style.backgroundColor = "";&#10;&#9;&#9;obf.readOnly = true;&#10;&#9;&#9;obf.style.backgroundColor = "var(--code-background-color)";&#10;&#9;} else {&#10;&#9;&#9;encOpts.style.visibility = "hidden";&#10;&#9;&#9;btn.textContent = "Decode ↑";&#10;&#9;&#9;plain.readOnly = true;&#10;&#9;&#9;plain.style.backgroundColor = "var(--code-background-color)";&#10;&#9;&#9;obf.readOnly = false;&#10;&#9;&#9;obf.style.backgroundColor = "";&#10;&#9;}&#10;&#10;&#9;updateSaveButtons();&#10;}&#10;&#10;function updateSaveButtons() {&#10;&#9;const mode = document.getElementById("mode").value;&#10;&#10;&#9;const plainVal = document.getElementById("plain").value || "";&#10;&#9;const obfVal = document.getElementById("obf").value || "";&#10;&#9;const revealVal = document.getElementById("reveal").value || "";&#10;&#10;&#9;const saveEncodedBtn = document.getElementById("saveEncodedBtn");&#10;&#9;const saveRevealBtn = document.getElementById("saveRevealBtn");&#10;&#9;const saveDecodedBtn = document.getElementById("saveDecodedBtn");&#10;&#10;&#9;if (mode === "encode") {&#10;&#9;&#9;saveEncodedBtn.style.display = "";&#10;&#9;&#9;saveRevealBtn.style.display = "";&#10;&#9;&#9;saveDecodedBtn.style.display = "none";&#10;&#10;&#9;&#9;saveEncodedBtn.disabled = obfVal.length === 0;&#10;&#9;&#9;saveRevealBtn.disabled = revealVal.trim().length === 0;&#10;&#9;} else {&#10;&#9;&#9;saveEncodedBtn.style.display = "none";&#10;&#9;&#9;saveRevealBtn.style.display = "none";&#10;&#9;&#9;saveDecodedBtn.style.display = "";&#10;&#10;&#9;&#9;saveDecodedBtn.disabled = plainVal.length === 0;&#10;&#9;}&#10;}&#10;&#10;function onAction() {&#10;&#9;const mode = document.getElementById("mode").value;&#10;&#9;document.getElementById("error").textContent = "";&#10;&#9;if (mode === "encode") encodeInvisible();&#10;&#9;else decodeInvisible();&#10;&#9;updateSaveButtons();&#10;}&#10;&#10;function encodeInvisible() {&#10;&#9;const plain = document.getElementById("plain").value || "";&#10;&#9;const u0 = document.getElementById("u0").value;&#10;&#9;const u1 = document.getElementById("u1").value;&#10;&#9;if (!u0 || !u1) return;&#10;&#10;&#9;let out = "";&#10;&#9;for (const ch of plain) {&#10;&#9;&#9;const code = ch.codePointAt(0) &amp; 0xFF;&#10;&#9;&#9;const bits = code.toString(2).padStart(8,"0");&#10;&#9;&#9;for (const b of bits) out += (b === "0" ? u0 : u1);&#10;&#9;}&#10;&#9;document.getElementById("obf").value = out;&#10;&#9;updateReveal();&#10;&#9;updateSaveButtons();&#10;}&#10;&#10;function decodeInvisible() {&#10;&#9;const obf = document.getElementById("obf").value || "";&#10;&#9;const { ok, ch0, ch1, error } = detectTwoUnicode(obf);&#10;&#9;if (!ok) {&#10;&#9;&#9;document.getElementById("error").textContent = error;&#10;&#9;&#9;document.getElementById("plain").value = "";&#10;&#9;&#9;updateReveal();&#10;&#9;&#9;updateSaveButtons();&#10;&#9;&#9;return;&#10;&#9;}&#10;&#10;&#9;const bits = [];&#10;&#9;for (const ch of obf) {&#10;&#9;&#9;if (ch === ch0) bits.push("0");&#10;&#9;&#9;else if (ch === ch1) bits.push("1");&#10;&#9;}&#10;&#10;&#9;let plain = "";&#10;&#9;for (let i = 0; i + 7 &lt; bits.length; i += 8) {&#10;&#9;&#9;const byte = bits.slice(i, i + 8).join("");&#10;&#9;&#9;const val = parseInt(byte, 2);&#10;&#9;&#9;if (!Number.isNaN(val)) plain += String.fromCharCode(val);&#10;&#9;}&#10;&#9;document.getElementById("plain").value = plain;&#10;&#9;updateReveal();&#10;&#9;updateSaveButtons();&#10;}&#10;&#10;function detectTwoUnicode(text) {&#10;&#9;const set = new Set();&#10;&#9;for (const ch of text) {&#10;&#9;&#9;const cp = ch.codePointAt(0);&#10;&#9;&#9;if (!INV_CP.includes(cp)) continue;&#10;&#9;&#9;set.add(ch);&#10;&#9;}&#10;&#9;const arr = [...set];&#10;&#9;if (arr.length !== 2) {&#10;&#9;&#9;if (arr.length === 0) {&#10;&#9;&#9;&#9;return {&#10;&#9;&#9;&#9;&#9;ok: false,&#10;&#9;&#9;&#9;&#9;ch0: null,&#10;&#9;&#9;&#9;&#9;ch1: null,&#10;&#9;&#9;&#9;&#9;error: "Error: could not detect two valid invisible Unicode characters in the encoded text."&#10;&#9;&#9;&#9;};&#10;&#9;&#9;}&#10;&#9;&#9;return {&#10;&#9;&#9;&#9;ok: false,&#10;&#9;&#9;&#9;ch0: null,&#10;&#9;&#9;&#9;ch1: null,&#10;&#9;&#9;&#9;error: "Error: detected " + arr.length + " distinct invisible Unicode characters, expected exactly 2."&#10;&#9;&#9;};&#10;&#9;}&#10;&#9;return { ok: true, ch0: arr[0], ch1: arr[1], error: "" };&#10;}&#10;&#10;function onObfChange() {&#10;&#9;updateReveal();&#10;&#9;const mode = document.getElementById("mode").value;&#10;&#9;if (mode === "decode") {&#10;&#9;&#9;document.getElementById("error").textContent = "";&#10;&#9;&#9;const obf = document.getElementById("obf").value || "";&#10;&#9;&#9;const res = detectTwoUnicode(obf);&#10;&#9;&#9;if (!res.ok) document.getElementById("error").textContent = res.error;&#10;&#9;}&#10;&#9;updateSaveButtons();&#10;}&#10;&#10;function updateReveal() {&#10;&#9;const obf = document.getElementById("obf").value || "";&#10;&#9;const cps = [];&#10;&#9;for (const ch of obf) {&#10;&#9;&#9;const cp = ch.codePointAt(0);&#10;&#9;&#9;const hex = cp.toString(16).toUpperCase();&#10;&#9;&#9;const padded = cp &gt; 0xFFFF ? hex.padStart(5,"0") : hex.padStart(4,"0");&#10;&#9;&#9;cps.push("U+" + padded);&#10;&#9;}&#10;&#9;document.getElementById("reveal").value = cps.join(" ");&#10;}&#10;&#10;/* ---------- Download helpers ---------- */&#10;&#10;function downloadText(filename, text) {&#10;&#9;const blob = new Blob([text], { type: "text/plain;charset=utf-8" });&#10;&#9;const url = URL.createObjectURL(blob);&#10;&#9;const a = document.createElement("a");&#10;&#9;a.href = url;&#10;&#9;a.download = filename;&#10;&#9;document.body.appendChild(a);&#10;&#9;a.click();&#10;&#9;a.remove();&#10;&#9;URL.revokeObjectURL(url);&#10;}&#10;&#10;function saveDecoded() {&#10;&#9;const plain = document.getElementById("plain").value || "";&#10;&#9;downloadText("decoded_payload.txt", plain);&#10;}&#10;&#10;function saveEncoded() {&#10;&#9;const obf = document.getElementById("obf").value || "";&#10;&#9;// NB: encoded contains invisible chars; keep as UTF-8 text&#10;&#9;downloadText("encoded_invisible_payload.txt", obf);&#10;}&#10;&#10;function saveReveal() {&#10;&#9;const reveal = document.getElementById("reveal").value || "";&#10;&#9;downloadText("revealed_codepoints.txt", reveal);&#10;}&#10;&lt;/script&gt;</description></item></channel></rss>