Written on November 10, 2021
tl;dr be careful what you’re clicking, copying, looking at
There has been a fair bit written about homoglyphic attacks targeting domain names. A homoglyph is a character from one character set that looks like a character in a different character set, and has a different underlying value. The common defense for this attack targeting domain names was to display the domain name as Punycode. I wanted to take a look at a potential use case for this attack as it relates to query parameters and rendered HTML text. Specifically, ENS names used as parameters in links and rendered HTML text.
If someone has an ENS name that they’d like you to send payment to, they may post a link on their own webpage, a blog/forum, or social media profile, that would take the user to an app and autopopulate the address field with the ENS name. An attacker may provide a link via a phishing message, or a hijacked/spoofed webpage/blog post/social media account. The link would appear to have the correct name, but would actually be using a homoglyph.
I tested this in both Firefox 94.0 and Chromium 95.0 on Linux, Chrome 95.0 on Android 12, and Safari on iOS 14.2(yes, its old but is what I had laying around). You may copy & paste the plain text shown below into the search field on etherscan.io. Note that the search results don’t take you to the same place, because they are actually different ENS names, even though the links and text look the same.
For security reasons, many people have been taught to hover over links to see where the href points. This is only practically done on desktop browsers. In this case, note that when hovering over the links you will see that the Cyrllic dze is indistinguishable from an ASCII “s”. And as a final check, note that after clicking the bad link below, you will see that the dze is rendered in the browser’s URL bar as an “s” in the desktop browsers as well as Safari on iOS. Chrome on Android did percent-encode the dze in the URL bar, but practically no one will scroll to the end of a URL in a mobile browser to look at it.
Legit: sassal.eth sassal.eth
Bad: sasѕal.eth sasѕal.eth
Browsers and apps could mitigate the risk by rendering non-ASCII as Punycode, not just if its a DNS name. That would suck for internationalization, so is should be done conditionally. Telegram did not render the bad “sassal.eth” text any differently than the good one, though the link is rewritten to percent-encode the dze. Twitter also does not render the bad “sassal.eth” text any differently than the good one, and also has the downside of cutting off links & rewriting them to t.co. Twitter does have a tool tip with the dze percent-encoded, but I imagine few users are paying attention to this, and could be further obfuscated by percent-encoding the entire value, not just the dze.
app.ens.domains will actually warn you if you try to register a name that contains non-ASCII characters, and did render the dze in a different(bold) font. Pasting the bad name into Coinbase did not show any difference in rendering the legit sassal.eth text vs the bad one, though it did quickly resolve each to their respective hash. The key will be for end users to double-check the hash before finalizing the transaction.
I should note that this attack is not specific to ENS names, it could happen with any links and rendered text. I just thought it was an interesting use case as people use ENS names as transaction recipients.