IDN Spoofing Defense for Safari
- UPDATE:
- Apple has properly resolved this issue with Safari, see About Safari International Domain Name Support.
Soon after I got home from ShmooCon, I saw that the Shmoo Group came up with a new domain spoofing exploit for which "no defense exists". It's pretty amazing that browsers actually implement IDN without any kind of protection, so I decided to quickly hack up a defense for Safari on Mac OS X 10.3 (and probably later).

- Application:
- IDNSnitch.app.tgz (335k) USE AT YOUR OWN RISK. This probably will cause instability in Safari.
- Source:
- http://svn.red-bean.com/pyobjc/trunk/pyobjc/Examples/Inject/IDNSnitch
The hack is implemented in two parts, an application and a plugin.
Application
IDNSnitch.py is a simple application that scans NSWorkspace for Safari instances, and registers for application launch notifications for new Safari instances. When it sees an instance of Safari, it uses objc.inject to load the plugin into the target pid.
Plugin
IDNSnitchPlugin.py is where all the magic happens. It swizzles NSURLRequest's designated initializer by creating a category after caching the original IMP. This swizzled initializer calls into another method that checks the NSURL and has an opportunity to return a different one. The implemented checker that looks for the ACE (ASCII compatible encoding) prefix in the host of the given NSURL. If it sees an ACE prefix, it presents an alert panel to the user showing them the raw IDN URL, the "display" host name, and the unicode escaped host name. The user can then decide whether to allow or deny requests from this host, and this decision is cached for the rest of their Safari session, but not persisted. If they choose Deny, it simply returns about:blank rather than the original URL.
Discovery
In order to discover how to implement this hack, I attached gdb to Safari, like so:
% ps -auxwww|grep Safari bob 21062 0.0 3.9 254720 40976 ?? S 5:23PM 0:57.19 /Applications/Safari.app/Contents/MacOS/Safari -psn_0_193331201 bob 21103 0.0 0.0 17052 8 std R+ 5:40PM 0:00.00 grep Safari [meth:~] bob% gdb attach 21062
I then thought that I could easily pick out when Safari used URLs by putting a break point on NSURL's designated initializer:
(gdb) fb -[NSURL initWithString:relativeToURL:] Breakpoint 1 at 0x90a2d51c (gdb) c
After going to a few URLs, I noticed that it would often have the URL cached somehow. So then I looked at a NSURL backtrace and saw that NSURLRequest was probably used more often, so I put a break point on its designated initializer:
^C Program received signal SIGINT, Interrupt. 0x900074c8 in mach_msg_trap () (gdb) fb -[NSURLRequest initWithURL:cachePolicy:timeoutInterval:] Breakpoint 2 at 0x90a0b0b8 (gdb) c
NSURLRequest is indeed used all the time, so I took a look at what a spoofed URL looks like:
Breakpoint 2, 0x90a0b0b8 in -[NSURLRequest initWithURL:cachePolicy:timeoutInterval:] () (gdb) po $r5 https://www.xn--pypal-4ve.com/
At this point I had everything I needed to know, so I wrote the code.
UPDATE:
- Rewritten in pure Python (requires svn trunk of PyObjC), hopefully fixed threading bugs.
- Fixed some more bugs and made it smaller
- An alternate implementation of this is available in Saft v7.5.1 and later (have not tried it myself)
- One of the authors of the IDN standard writes about a more balanced solution to this issue. I had actually considered doing it this way, but I simply didn't have the time or interest in creating the custom dialogs required. This functionality should be in unicodedata, but it's not, though Blocks.txt would be trivial to parse.
- An up and coming Mozilla extension, TrustBar, attempts to solve this and other issues for Mozilla and FireFox
I don’t know ObjC or Mac internals, but the guy who writes Saft also released a free hack to do the same thing:
http://haoli.dnsalias.com/
It goes in /Library/InputManagers like Saft does, which a whole lot of people seem to use so hopefully it’s not evil (!) I’ve had it running since this morning, no stability issues and it seems to work (gotten maybe a few false negatives (?) on long adserver URLs actually).
Comment by ToddG — 2005-02-08 @ 6:08 pm
That’s cool, it’s better off being part of Saft. I have no plans of supporting this, it’s just a proof-of-concept.
Comment by Bob Ippolito — 2005-02-08 @ 6:16 pm
Nice work. It’s stuff like this that keeps the internet alive. :) Cheers, ericj
Comment by Eric J — 2005-02-08 @ 9:43 pm
That’s a splendid bit of hacking. Mind you Safari did crash on me a bit later in CFDictionaryGetValue + 0xec…
If you want me to attach with gdb and poke at it again, let me know.
Comment by Kevin Marks — 2005-02-08 @ 11:39 pm
If you downloaded it recently, it shouldn’t crash. Older versions crashed for some reason. I haven’t isolated the bug beyond “import Foundation”, but the current version uses objc.lookUpClass exclusively (except for an AppKit import from the main thread).
If you still have the problem, for whatever reason, don’t bother gdb’ing it unless you have access to the Foundation framework’s source code.. it’s a gremlin.
Comment by Bob Ippolito — 2005-02-08 @ 11:46 pm
Hao Li’ s IDN detection (at least in Saft_Lite) has one problem however: It detects and then only lets you ‘ OK’ or ‘ Tell me more’ but not deny following the link.. :-(
Comment by Mathias — 2005-02-09 @ 8:13 am
the IDSnitch seems to work fine, though I have not been able to figure out how to make it such that it is active for new Safari sessions (and all users). Seems I have to run it separately after I start Safari? A short install document would be nice,,
Comment by Mathias — 2005-02-09 @ 8:21 am
There is no installation, it simply has to be running at the same time as Safari to take effect. It could be rewritten as an InputManager that binds to Safari like Saft does, but I am not interested in doing that. Your best bet would be to contact the author of Saft and ask for feature requests. Mine is merely a proof-of-concept that I have no intentions of supporting.
Comment by Bob Ippolito — 2005-02-09 @ 12:09 pm
The way this works looks very nice, but I’d rather not have to keep a separate process running to inject code into Safari, and I’d rather not have to initialize PyObjC in Safari. I also don’t want to install SaftLite because I hear it conflicts with PithHelmet. Would you mind if I converted your PyObjC code into a SIMBL bundle (equivalent to an Input Manager, but SIMBL does the work of only loading your bundle into Safari and not into any other app)?
Comment by Kevin Ballard — 2005-02-11 @ 3:51 pm
By the way it works, I really mean that picture of a dialog. I haven’t looked at the actual code itself yet.
Comment by Kevin Ballard — 2005-02-11 @ 3:51 pm
Do what you want, it’s MIT licensed.
Comment by Bob Ippolito — 2005-02-11 @ 3:57 pm
BTW: Converting it to a SIMBL bundle would simply mean taking the plugin and copying it to the right place and making whatever plist changes you need to do for SIMBL. You would of course have to change the setup.py so that it doesn’t build the plugin inside the app, though.
Comment by Bob Ippolito — 2005-02-11 @ 3:59 pm
Congratulation and thanks for your solution.
But is there the same thing for PC/Windows uszers?
Regards
Comment by kareldjag — 2005-02-12 @ 9:58 am
Cool! You may also want to consider adopting our secure-UI enhancement approach, currently available as extension for Mozilla and FireFox, from http://TrustBar.MozDev.Org. It addresses this specific attack, but much more, as it provides the user with a secure area (bar) at the top of each browser window, containing the logo of the site and of the CA. You can also get the source code if it’ll help you adapt to your browser (and this is open source, of course). We are trying to convince all browsers to implement such functionality.
Best, Amir Herzberg
Prof., dept of computer science, Bar Ilan University
Comment by Amir Herzberg — 2005-02-17 @ 2:46 pm
Mac G4, OS 10.3.8 (maybe later than Bob was using?) Safari 1.2.4
Tried snitch; when I closed the popup warning box, Safari crashed. Thanks anyhow!
Now trying SAFT Lite… so far Safari is stable.
Comment by David Elliott — 2005-02-21 @ 7:51 pm
To kareldjag,
Safari fixes for Windows users? Err, no. Try reading before commenting.
Comment by Pete — 2005-03-12 @ 6:27 pm