I'll be going to defcon for the first time this year and as soon as I had booked my tickets I started to think about what kinds of things I'll bring with me and how I'll stay in touch with the world in a hostile network environment. It didn't take long before I realized that I probably won't want to carry my laptop around and turning off my cell for a weekend might be a nice break from things.
That being said, this scenario where the goal is to communicate securely in a completely untrusted and malicious network has become a bit of a thought experiment for me. The objectives are as follows.
Separate my communications from my identity. I tend to be fairly open about who I am on the internet, and it's not very difficult to figure out who I am given you can find my account name on nearly any website and are capable of using google. In a hostile environment, this is unacceptable behavior. The perceived importance of any communications will likely be much higher if the sender and recipient can be identified.
Encrypt everything. With open source encryption tools and methodologies so readily accessible these days, there's little reason not to encrypt as much data as possible in a hostile environment. A variety of different protocols and suites should be used in order to guard against the possibility of any of them being compromised.
Assume all of your security measures are worthless. Nothing is perfect, especially when humans are involved. Assuming all technical means of security have been compromised. Is your data still intact? Recoverable? On the other hand, you may want the ability to make it all disappear at a moment's notice...
With those goals in mind, let the games begin! Now, if I were a real criminal, it would presumably be much easier for me to separate myself from my identity by fabricating a new one. Even just a few key falsified documents can go a long way toward establishing a dead end for anybody that comes looking for you. Alas, I am not a criminal and would prefer not to face prison time. For this reason, I'm going to establish enough of a roadblock for the casual stalker, but it's probably not enough to stop a government agency with enough probable cause to get subpoenas and warrants issued in a timely fashion.
I keep a couple of these gift cards purchased from credit card companies around just for such occasions. The one I chose to use for this experiment was actually given to me as a gift by a family member, who used cash to purchase it. The remaining value on the card was just over $14. As these gift cards are meant to be transferable, they're generally not imprinted with a specific person's name but instead carry a name like Gift Recipient. Depending on the issuer of the card and when it was purchased, there may be certain limitations to making online purchases. I've heard that more recent cards actually require a social security number to be activated. Figuring out how well those numbers are validated is an exercise left to the reader. In my case, no personally identifying information was needed to activate the card. After a few failed attempts to charge small transactions, I found that I needed to login to the credit card company's website using nothing more than the numbers on the card (skimmers anyone?) and provide some basic contact information (Name, Address, Phone Number) so that the credit processor could verify the owner of the card. The credit card company's website did absolutely no validation of this information so false (yet believable looking) values were used.
The next portion of my plan involves email access. Specifically, how can I continue to read email without compromising my existing account or changing my address? There are options like HushMail that provide "anonymous" email services, but over the last few years, such services have proven less resistant to legal action. I ended up creating a few hushmail accounts anyway, just so that I could deal with activation emails and the like.
If I cannot trust a third-party, and I don't trust the security measures of my existing mail service, then the only remaining option is to run my own mail server. Rather than just pointing the MX record for my domain at a new, anonymous server, I decided to register a new domain name and forward my mail to it from my existing account. This setup allows me to continue reading email without transmitting my real account's credentials across the network. Sending mail gets a bit trickier when the recipient's domain checks reverse DNS entries and SPF records.
Right, so I'm going to need a domain name and a server. As I only had $14 on my anonymous credit card, cheaper is better. Currently several registrars are offering the first year of a .info domain between $1 and $2. I only plan to use this domain for a weekend, so just letting the registration lapse after a year is not an issue. Using the gift card along with the same information provided to the credit card company and a hushmail address, I was able to register a new domain using the registrar's DNS servers, leaving one less thing to worry about anonymizing.
Getting an anonymous server is somewhat tricky. Most sysadmins aren't going to be very receptive to the idea of letting you plug a box in without knowing who you are first. If you're lucky enough to have access to cheap, clandestine, rack space then you're already far better off than most of us and can probably stop reading here. Otherwise, you'll have to make due. I ended up using Amazon EC2 to boot up a virtual machine. Yes, there are inherent assumptions made about security here, not the least of which being that I am putting absolute trust in Amazon to not go poking around on my VM or in my data while I'm not looking. My thoughts are that there are probably thousands of nearly identical VMs in the same cluster that Amazon's engineers need to worry about and as long as you don't do anyting to draw attention to yourself, there's little reason for anybody to go messing around with your data.
For the record, the domain registration cost $1.20 and the cheapest EC2 instance is $0.10 an hour. As I'll only be running the instance over the three days I'm at defcon, the total cost of keeping it online is $7.20, plus whatever storage and bandwidth charges I incur (minimal). So, with an EC2 instance running, the registrar's DNS records updated to point to the instance's IP, I'm ready to get to work hardening the VM. Most of Amazon's AMI images have SSH password authentication disabled by default, it's worth double-checking now. While you're there, it might be useful to enable ChallengeResponseAuthentication (I'll get to this in a minute) and set UseDNS to no as we don't really care about reverse lookups. We already know the client is on an untrusted network, best not to provoke it with requests for PTR records that could possibly contain malicious responses. Basic security practices should also be used here... Create a separate user to login as, without root privileges of any type. Setup iptables rules to only allow SSH traffic (or whatever else you might need) even though Amazon's security zones provide similar firewalling, it can't hurt to do the same thing on the host, just in case there's a configuration mistake somewhere else.
I also like to wipe out the motd as there have been demonstrated known plaintext attacks against SSH sessions and the default motd is a big chunk of predictable known plaintext at the beginning of every session. Now let's go back to the ChallengeResponseAuthentication bit. Ever since World War II (possibly earlier, I'm not an expert of crypto history) the idea of perfect secrecy via One Time Pads has circulated. The concept is simple: encode the plaintext using a key that is at least as long the plaintext and never use the same key twice. The pad is just a list of completely random numbers to be applied to the plaintext. Both parties are issues a copy of the pad and cross off a key once it has been used to send or receive a message.
There are some difficult problems to solve with OTPs... The most obvious being that you have to distribute the pads to both parties securely. In an ideal world, this is a physical transaction between two humans who have picked numbers completely at random. Unfortunately, we don't have physical access to the EC2 instance, so we'll just have to make the assumption that we're using a trusted network when initializing the pad. Furthermore, because one of the parties is a computer and cannot generate truly random numbers and the other is a human that is generally too lazy to sit around spitting out random numbers all day, we end up settling for a pseudo-random sequence generated by the computer, possibly seeded by a "real" random number provided by a human.
There are a few implementations of OTPs for login authentication. S/Key seems to be one of the more long-lived implementations, but it unfortunately requires patching sshd on Linux systems. If your server is a BSD machine, then this functionality is builtin and you just need to turn it on. On Linux, there is a PAM module that links the OPIE library to accomplish the same effect. Using a PAM module also has the advantage of adding OTPs not just to SSH logins, but all PAM enabled logins on the system (eg. sudo, apache, some vpn implementations). In addition to the PAM module configuration, you will also need a "client" program that can use the OPIE request along with your passphrase to generate a valid response to send to the server. If you're using the S/Key implementation, then the use of a client program is entirely optional as you can just ask the server to print out an ordered list of keys that are valid for authentication. You can then write these down, print them on the back of a business card, laminate it, laser etch them, or whatever you like as long as you remember to cross off each key after you use it.
As you may have noticed, the OTP keys are nowhere near as long as the number of bits transferred in your average SSH session. We still allow the SSH protocol to handle a lot of the heavy lifting to verify the server's fingerprint (you didn't just type yes, right?) and generate session keys. The advantages to using OTP over SSH are questionable, especially because if an attacker has found a way to sniff your password, they're probably going to see your entire session anyway. All this does is stop the attacker from replaying the same password to login as you. But, there is a certain geeky cool factor about keeping a list of secret one-time-use codes in your pocket that you have to key in... Makes it feel like you're not just checking your email, but instead you're arming a nuclear weapon.
With all of this hardening out of the way, now might be a good time to save your work. Amazon provides some tools for re-packaging the live system as an AMI image and saving it back to their storage service, S3. You'll end up spending a few pennies a month to store a reasonable sized image, especially if you delete it when you get home from defcon.
Finally, we get to the email part. This is actually pretty straightforward. Install the MTA and smtpd of your choosing, setup firewall rules to allow inbound emails from your real email account's servers, force TLS on incoming SMTP connections if your real account's servers support it, and add some forwarding rules to your real account.
In addition to email, you can also run things like IRC clients and VPN daemons on your semi-anonymous VM. In some situations, it's also useful to run a service like nstx that allows you to tunnel IP packets over DNS to get around some captive portals on wifi hotspots at airports. Read the openssh client manpage... There are a whole bunch of tricks for forwarding ports over the SSH connection, it can even run a local SOCKS proxy that you can point your browser at. If you're using firefox, make sure to also tunnel DNS requests through the SOCKS tunnel.
This post is getting to be a bit on the long side, but I feel that it's also worth mentioning that I'm planning to purchase a prepaid cell phone with hopes of getting some sort of tethering going. Based on some of the defcon videos from last year, it might be possible to get a reasonable price on data with a Verizon prepaid phone, although I've yet to try it. Don't assume GSM, GPRS, EDGE, or whatever else is secure either... Anybody with a USRP board could be recording everything for bruteforcing on some crazy FPGA grid. Such things are not unheard of at these conferences.
I realize that most of these measures are probably unnecessary or overkill, but I also think that it's worth taking some time to examine all possible attack vectors, even the unlikely ones because those are the first places you'll start to get hit after you've fixed all the likely ones.
In a few days I'll have been living in San Francisco for a full year and it's been anything but boring... Within the last 12 months, I've worked for two companies with awesome people who've introduced me to even more awesome people, I've written tons of code, taken lots of pictures, inhaled quite a bit of solder smoke, sold my car and walked hundreds of miles.
For as long as I had been making long-term goals and plans for myself, I knew that I wanted to live in California. Everything I had heard and read just made it sound like the perfect place for me. So, I chased my dreams and set out toward San Francisco. The cross country drive was a lot of fun and my only regret is that I couldn't spend more time hanging around all of the small towns I passed through. Someday I'll go back and find out what towns like Bettendorf, Iowa are really about.
By the time I got to San Francisco, I was left with a single day to find a place to live. Being the somewhat insane person that I am, I ended up picking a handful of places off craigslist and ended up signing the lease on the first one that looked reasonable. I had never lived in a city before. In hindsight, this may not have been the smartest move, but it could've been a lot worse. A year later, I'm renewing my lease.
On my first day of work, I showed up at 8am, only to find that there was nobody else there... I quickly learned that things are a lot more laid back around here. After work, I headed back home only to find an empty refrigerator, no furniture, and a car still full of boxes. Yet I was incredibly happy because I could finally say "I live in San Francisco!" I still smile every time I write my address.
I had heard talk of an awesome piece of furniture called the Lovesac, which is basically a beanbag chair except instead of little PVC beads, it's full of shredded mattress foam. I bought the biggest one I could find on craigslist and drove over to inner richmond to get it. The guy I bought it from was kinda strange, but had a definite innocence to him. The following few hours can only be described as a surreal scene from an indie film. Myself, this high school kid and his girlfriend spent the last few minutes of daylight pushing and pulling and rolling and turning the Lovesac through his apartment, down the stairs and into my car. It quickly became apparent that it wouldn't completely fit. Some clever knot work with a bit of loose cord got it tied up to the point where I was willing to drive, albeit slowly, back home with the hatchback wide open and the Lovesac hanging halfway out. I ended up driving around the city for at least an hour and a half after I got lost somewhere in the Mission district trying to get back home. I don't like the idea of having a GPS in the car... It makes you complacent because you never truly know where you are or where you're going. That being said, I have no problem asking for directions or looking at a map. Still, it was getting dark and I thankfully made it home safely. At this point, I alone squeezed the Lovesac into the elevator, down the hallway, and into my apartment.
Just thought I'd throw out a quick post with some examples of OpenSSH 5.1's key visualizations. See below.
Generating public/private rsa1 key pair.
Your identification has been saved in /opt/ssh/etc/ssh_host_key.
Your public key has been saved in /opt/ssh/etc/ssh_host_key.pub.
The key fingerprint is:
64:2a:99:60:92:db:f0:ad:39:15:75:c6:72:50:f3:10 root@wintermute
The key's randomart image is:
+--[RSA1 2048]----+
| o+E. |
| . ..oo+ |
|+ o . oo . |
| B o + + |
|. o * . S |
| + . |
| + |
| . |
| |
+-----------------+
Generating public/private dsa key pair.
Your identification has been saved in /opt/ssh/etc/ssh_host_dsa_key.
Your public key has been saved in /opt/ssh/etc/ssh_host_dsa_key.pub.
The key fingerprint is:
db:21:5a:98:3f:40:97:98:60:bd:43:e1:cf:73:02:bb root@wintermute
The key's randomart image is:
+--[ DSA 1024]----+
| o... |
| . ooo . |
| .*.o |
| .oO |
| =.S o |
| * B . |
| E + . |
| . |
| |
+-----------------+
Generating public/private rsa key pair.
Your identification has been saved in /opt/ssh/etc/ssh_host_rsa_key.
Your public key has been saved in /opt/ssh/etc/ssh_host_rsa_key.pub.
The key fingerprint is:
d8:5b:4c:4f:be:41:d9:ab:d0:a9:54:6c:86:9c:c2:7a root@wintermute
The key's randomart image is:
+--[ RSA 2048]----+
| |
| . . + o |
| o = O . |
| + + X . . |
| o E = * . |
| . + o + |
| . . o |
| |
| |
+-----------------+
My pet project, NikiWiki is starting to grow up. Since my last post, I've added a number of features and can cross a few items off the todo list. The most visible change is that NikiWiki can now be used for a basic blog.
I moved neohippie.net over to NikiWiki about a month ago and have been fairly impressed with how easily I can reshape the site with very little effort. Any subdirectory can become a "blog" by adding a .index file inside it with a comma delimited list of page names and unix timestamps. While this certainly isn't the most elegant solution, it works fairly well and doesn't get in the way too much.
NikiWiki now has PAM authentication using Chris Lee's incredibly simple pam.py module. You can implement a number of different authentication methods just by loading and unloading PAM modules. However, if you feel the need to add something a bit more custom, simply implement an authenticate(username, password) method that returns a True or False value indicating whether or not the user has been authenticated. For example, if you wanted to read from an htpasswd file:
from crypt import crypt
def authenticate(username, password):
for line in file('/path/to/htpasswd'):
line = line.split(':', 1)
if line[0] == username and line[1] == crypt(password):
return True
else:
return False
It's possible that some users won't want to use PAM for authentication but I think it makes sense to push users in that direction anyway. Standard authentication methods are a good thing. If you don't like it, change it.
NikiWiki now includes a module I've been working on called nstore. nstore provides a fairly clean and pythonic method for building complicated data storage systems for key->value pairs. The default NikiWiki build just uses a simple FileStore, but you can change this to give you all sorts of neat configurations. For example, I run neohippie.net on a set of three servers in two physical locations. I keep a central authoritative data store on one server, with local caches on the others. My NikiWiki data store looks like this:
I've added the newlines for clarity. In a nutshell, this configuration performs reads and writes through a CacheDict that uses an HTTPStore as the primary data store and the local filesystem as a cache. The first time an element is read, it is read from the HTTPStore and saved in the local FileStore. On successive reads, the element is read directly out of the local FileStore.
There are a few obvious limitations to this approach, the most notable is that local caches are not updated after the first fetch and they never expire. This is fine for seldom updated sites where I just clear the caches after I change anything but may be a problem for more complicated sites.
I've got some interesting ideas for nstore (DHT anyone?) that should materialize in the near future. Until then, feel free to hack around with it. I've found that writing new UserDicts for nstore can be a lot of fun.
Back to NikiWiki. The other large change introduced recently was a WSGIApp class that completely negates the need for web.py. I was using very little of the functionality within web.py and decided that it would be nice to have one less dependency to worry about. Usage is fairly simple:
server = WSGIServer(WSGIApp(urls)).run()
This is assuming that your WSGIServer takes a method reference as it's first argument. NikiWiki uses flup to provide a FastCGI interface that you can plug into your web server but any WSGI server should work.
For those not keeping track, the current list of dependencies looks like this:
Python 2.5
flup
nstore.py (included)
pam.py
markdown.py
All of the dependencies except for Python and nstore can be installed with easy_install.
Known bugs:
WSGIApp is not thread safe
The browser sends more than one request when you click save
Feel free to bug me via email or jabber if you have problems with NikiWiki.
I've been playing around with a toy wiki implementation for a few months and apparently I haven't really announced it. NikiWiki is a simple file-based wiki written in Python using web.py and markdown syntax to avoid having to create yet another wiki syntax. It started out as a fork of the code that runs my blog in an attempt to clean up and genericize the code a bit. However, when I took a step back, I realized that I wasn't very far off from having a functional wiki, so I decided to pursue that course with the intent of eventually turning it into a wiki-based blog. I'm still not exactly sure how that's all going to fit together, but I have a few ideas.
In my mind, the definition of a wiki is a website that can be edited by anyone, including the ability to add, change, or delete arbitrary pages and/or content. At such an early stage, nikiwiki just about meets those criteria and little else. nikiwiki currently does not include any form of version control, making it prone to defacement or editing mistakes. In my own deployment of nikiwiki, I setup the data directory as a git repository, giving me some basic control over the pages, but this methodology has many obvious problems, particularly that I have to manually run git commit when I want to save the state of the site.
Todo
Version control
This brings me to my list of ideas for future features... I think version control is an important part of a wiki and will need to be addressed fairly soon. I like the idea of keeping everything within git or svn or some other existing versioning system, rather than attempting to re-invent the wheel. For that reason, I'll probably end up just building a REST interface for manipulating the git repository storing the pages and trigger certain actions automatically when a page is updated; git commit, for instance.
Authorization
I have already started implementing user authentication with PAM. I feel that PAM is the right way to go because it avoids having to create a separate user store and trying to figure out how to get it to integrate with the rest of your environment. Just configure PAM to supply authentication using whatever method you want eg. LDAP, NIS, RADIUS, Kerberos, etc. At some point, I may decide to implement some form of authorization as well (that is, allowing some users to edit certain pages, but not others) but I think that violates the philosophy of a wiki to some extent so unless somebody else wants it, security is an all or nothing approach.
Photo gallery
Right before I started driving across the country, I bought a new digital camera and started investigating options for putting a large number of pictures online. I knew that there were quite a few sites like Flickr, SmugMug, Picasa, etc that offered free photo hosting, but they all impose limits upon the number of photos you can upload or bandwidth usage or some other metric due to the realities of disk space and bandwidth (their tubes are clogged). In an attempt to avoid the inevitable situation of having too many pictures for the service I subscribe to, I decided to pursue the idea of hosting it on my own servers. I've built my environment to scale reasonably, so in theory I should be able to just add more disk/servers if I run out of space. This may not be cheaper, but in my mind, it's more fun.
Unfortunately, the open source photo galleries I was able to find were somewhat disappointing. They were either too limited in the features they offered, too reliant on things I don't want to deal with (read: PHP) or too difficult to integrate into an existing site without rewriting a large number of templates. This got me thinking that I could write a custom photo gallery similar to the way I wrote nikiwiki. Then I decided to take the idea a step further and just build it on top of the same codebase, essentially treating each directory full of pictures as a singular wiki page (with a predefined template for rendering the content of the page).
I still haven't worked out all the details, but I'm pretty sure that directories will be separate "albums" and each image under that will be accessible as a separate page containing a scaled version of the image along with any metadata gleaned from EXIF tags. The URL layout will reflect the on-disk representation closely, so where a normal wiki page would be /My_favorite_page, a photo gallery would be /My_favorite_album, and each image under that would simply be another page /My_favorite_album/First_photo with various GET variables to determine the presentation of the page.
I'm not entirely sure what effect the POST and PUT methods will have on these pages, if I implement them at all. Uploading new images will probably need to be done manually to start, in order to make sure the file layout is correct. I'm not really a fan of web-based uploading tools as they tend to cause more problems than they solve. Until I change my mind, you'll probably just have to use SFTP or some similar method to get the files to the server.
Blog
Coming full circle back to my original intent for nikiwiki, I'd like to find a way to build a blog on top of it, eliminating the need for me to maintain a separate (yet extremely similar) codebase for my blog. The biggest requirement for blogs is that posts (pages) be displayed chronologically. Currently, there is no metadata stored with wiki pages aside from what's on the filesystem. The mtime attribute might suffice, but that may cause problems down the road if I need to recover the pages from a backup or something. In my blog's current codebase, I've solved this problem by maintaining a separate file containing a list of two item tuples in the form (page name, timestamp) where timestamp is elapsed seconds since the epoch. This works well, but I don't really like that the index needs to be updated every time a page is added or changes because it provides a case where the index could get lost somewhere. Maybe I could pull the modification times from the git log of the underlying pages...
The remaining problem with storing blog posts in the wiki is that they will need to be differentiated from normal pages in some way, so that normal pages aren't indexed and displayed on the front page. I haven't given this one much thought, but I think something like a simple naming convention may work.
Site index and tagging
Finally, I think it would be nice to have some automatically generated site map pages similar to Special:NewPages in MediaWiki. Some form of taxonomy, perhaps in the form of tags might also help people to find relevant content, but this brings me back to the problem of maintaining a separate index of all pages, rather than something generated by the content.
It appears that I am now too tired to come up with coherent, or even useful ideas for nikiwiki, so I should probably call it a night. Feel free to send me questions and comments about nikiwiki by sending email to synack at neohippie.net. Hmm... Maybe nikiwiki also needs some form of comment system...