Earlier today I wanted to explore using Growl / GNTP to listen for notifications from a remote server. I checked out the Growl developer bindings page, found the Python implementation, and started working on a simple app to send me notifications about various things.
I was planning on running this on my server so I could also interface with Twilio and accept callbacks, without having to expose a webserver on my local machine to the internet. To do this, I was going to accept remote notifications in Growl using a password. I realized pretty quickly this was a worse idea.
I started poking around in the source code, and found that the password is hashed using MD5 by default. In fact, it’s quite a pain to change from the default, since there is no configuration option to change the algorithm within the basic helper methods that are actually documented. This appears to be the case for all the other language bindings as well. This isn’t necessarily the end of the world, but it’s definitely not great.
More poking revealed that the packet contents are not encrypted with the password, but the password is merely used to determine whether the listening Growl instance will accept notifications from the remote source. A notification will actually come across the wire looking like this:
19:32:20.244428 IP (tos 0x0, ttl 64, id 53700, offset 0, flags [DF], proto TCP (6), length 13716, bad cksum 0 (->359d)!)
localhost.60465 > localhost.23053: Flags [P.], cksum 0x3389 (incorrect -> 0xe50a), seq 1:13665, ack 1, win 12759, options [nop,nop,TS val 266111329 ecr 266111329], length 13664
...a...aGNTP/1.0 NOTIFY NONE MD5:B80803CFA6C2F303266DC99501ED837D.D89A5B677CDA639FDF3305D233FA0487
Notification-Title: Timer Alert
As you can see, the name of the application, the name of the notification, the actual contents of that notification, and the title of the notification are easily readable (in blue).
What about that weird string starting with “MD5” (in red)?
The meat of the password hashing algorithm can be seen here. Basically, they use a hash of the system’s time as a salt (which they call a “seed”), and include it with messages sent to the server (D89A…0487 above). The other component of the string is a hash of the concatenation of the password and the salt’s hash (B808…837D above).
To see if it was really as easy as it appeared to crack these hashes, I wrote a quick script called Growl Crack that will first bruteforce the “seed” (timestamp/salt), then the “secret” (password + salt). Obviously the difficulty of cracking the password is dependent on its complexity, but the seed is usually cracked pretty much instantly.
In short, if you’re using Growl remotely, you should probably stop unless you want all your notifications being read, or want to expose your password for easy cracking to anyone listening to your communications.