This year I'm attending 31C3, the 31st invocation of the Chaos Computer Congress. Since I'll be in an environment full of creative hacker types, it doesn't make a whole lot of sense for me to bring my everyday laptop to it stuff with super seekrit things like SSH keys and whatnot.

As an exercise in security and privacy, I decided to experiment with building a portable system that I can use with impunity and be fairly certain that I am secure and my communications remain private. As with most security minded topics, it make sense to come up with a threat model of sorts. Here's mine for this experiment:

  • My current "home server" is hosted on AWS as I have not yet found time to bring up an actual metal server in my apartment, so I'll assume that my AWS resources are safe from any internal attacks by Amazon, such as dumping my VMs' memory to extract keys or bulk copies of my EBS disks for later analysis.
  • All of my data will be captured, logged, and possibly the logs retained between now and my return.
  • There is a non-zero chance that spooky-action-at-a-distance-like hacks such as reading line voltages, EM radiation, variations in pixel emissions, acoustic analysis, etc could be used to extract secrets from any device I interact with.
  • My address books are full of other people's information that they might not want leaked.
  • I really can't afford to lose a $1,200 laptop
  • If I'm being broken into, I need to know ASAP when my communications are no longer secure.
  • Since I'm the only user with legitimate uses for hackerbots.net and it is well-known that I will be in Hamburg at CCC, anonymizing access for connections to hackerbots.net doesn't add much.
  • I will assume it is impossible to perform a compromise of my hardware if it is always within a locally trusted physical environment such as within my sight or the sight of another trusted party.

Port of entry: xor.hackerbots.net

My end goal was to be able to login to hackerbots.net via ssh for keeping of notes and processing tasks while I had no connection to the 'net, and to anonymize all of my network traffic while at CCC.

Starting with SSH, I created a tiny AWS instance, allocated an elastic IP to survive reboots, and gave it the hostname xor.hackerbots.net. It currently runs Fedora 21, Tor 0.2.5.10, and mosh 1.2.4. A fresh SSH key was generated for use with it:

ssh-keygen -f ~/.ssh/hackerbots-bastion-root

My ssh client was then configured to use it by adding the following to ~/.ssh/config:

Host xor.hackerbots.net
IdentityFile "~/.ssh/hackerbots-bastion-root"
User fedora

To jump from xor.hackerbots.net to hackerbots.net, I generated a new ssh key on xor.hackerbots.net with a strong password and added the public key to ~/.authorized_keys on hackerbots.net. For extra caution, I double-checked /etc/ssh/sshd_config to make sure only publickey authentication was permitted.

PasswordAuthentication no

To allow mosh to work, I opened up ports 22 and 60000-61000 in my AWS security group. Easy enough. To help with knowing where I'm at, I created /etc/profile.d/xor.sh with the following:

PS1='\[\e[1;31m\]BASTION -> [\u@\h \W]\$\[\e[0m\] '

Which results in a bright red prompt letting me know where I'm at.

I left the default 'fedora' user in the wheel group with sudo access, as the only way to enter that way is through the separate bastion-root ssh key.

The Hardware

I took this opportunity to acquire an Acer C720 Chromebook. I picked it due to the low cost ($219 at the time) and known compatibility with Linux.

After some futzing with the firmware, I was able to install a fresh copy of Fedora 21 on it. I selected the default partition setup and opted to encrypt my swap and filesystems. Once that was finished, I created my default tdfischer user and generated a fresh SSH key:

$ ssh-keygen

The key was then copied to the bastion host and used to set up passwordless authentication for a non-privileged user. Now I had a shell open on hackerbots.net that was still totally usable over a flaky connection and could only be accessed through my Chromebook.

Login Notifications

Since I wanted immediate notification of when I'm compromised, I decided to set up my bastion host to e-mail and SMS me whenever anyone logs in to it. First I created a free trial account on Twilio. Second, I configured pam_exec to run a script on login by adding a line at the top of /etc/pam.d/postlogin:

session   required    pam_exec.so   /usr/local/bin/login-notify

And the corresponding source for that login-notify tool:

#!/usr/bin/python
import smtplib
from email.mime.text import MIMEText
import os
import sys
from twilio.rest import TwilioRestClient
import imp

config = imp.load_source('login_notify.config', '/etc/sysconfig/login-notify')

if 'PAM_RHOST' in os.environ:
  host = os.environ['PAM_RHOST']
else:
  host = os.environ['PAM_TTY']
user = os.environ['PAM_USER']

msgText = """
A new login has occured for the user '%s', originating from '%s'.
""" % (user, host)

msg = MIMEText(msgText)
msg['Subject'] = "New login for %s from %s" % (user, host)
msg['To'] = config.EMAIL_FROM
msg['From'] = "login-notify"

s = smtplib.SMTP('localhost')
s.sendmail('login-notify', config.EMAIL_TO, msg.as_string())
s.quit()

sms = TwilioRestClient(config.TWILIO_ACCOUNT, config.TWILIO_TOKEN)
sms.messages.create(to_=config.TWILIO_SMS_TO, from_=config.TWILIO_SMS_FROM, body=msgText)

sys.exit(0)

Also available on github as a gist.

To use this, drop it in /usr/local/bin/login-notify, chmod +x it, and configure it with /etc/sysconfig/login-notify:

TWILIO_ACCOUNT="foo"
TWILIO_TOKEN="bar"
TWILIO_SMS_FROM="+15555555555"
TWILIO_SMS_TO="+15555555555"
EMAIL_FROM="login-notify@xor.hackerbots.net"
EMAIL_TO="tdfischer@hackerbots.net"

Now whenever anyone logs in to this host via su, ssh, ftp, or any other service that somehow gets installed, I get an SMS and e-mail notification about the event.

Pervasive Tor

Now that I had a secure mechanism for communications between me and my personal data, I needed to anonymize everything else. On the chromebook I installed Tor.

Starting with the instructions on the Tor project's site, I enabled Tor's transparent proxy and DNS proxy by adding this to /etc/tor/torrc:

VirtualAddrNetworkIPv4 10.192.0.0/10
AutomapHostsOnResolve 1
TransPort 9040
DNSPort 53

Then I configured SELinux to allow Tor to bind to any port:

$ sudo setsebool -P tor_bind_all_unreserved_ports 1

Finally, enabling and starting tor:

$ sudo systemctl enable tor.service
$ sudo systemctl restart tor.service

Following the example script that configures iptables, I adapted it to Fedora's new firewalld via firewall-cmd:

$ firewall-cmd --permanent --direct --add-chain ipv4 nat tor
$ firewall-cmd --permanent --direct --add-rule ipv4 nat tor 0 -m owner --uid-owner 986 -j RETURN
$ firewall-cmd --permanent --direct --add-rule ipv4 nat tor 1 -p udp --dport 53 -j REDIRECT --to-ports 53
$ firewall-cmd --permanent --direct --add-rule ipv4 nat tor 2 -d 127.0.0.0/8 -j RETURN
$ firewall-cmd --permanent --direct --add-rule ipv4 nat tor 2 -d 54.197.234.238 -j RETURN
$ firewall-cmd --permanent --direct --add-rule ipv4 nat tor 3 -p tcp --syn -j REDIRECT --to-ports 9040
$ firewall-cmd --permanent --direct --add-chain ipv4 filter tor
$ firewall-cmd --permanent --direct --add-rule ipv4 filter tor 0 -m state --state ESTABLISHED,RELATED -j ACCEPT
$ firewall-cmd --permanent --direct --add-rule ipv4 filter tor 0 ! -o lo ! -d 127.0.0.1 ! -s 127.0.0.1 -p tcp -m tcp --tcp-flags ACK,FIN ACK,RST -j DROP
$ firewall-cmd --permanent --direct --add-rule ipv4 filter tor 0 ! -o lo ! -d 127.0.0.1 ! -s 127.0.0.1 -p tcp -m tcp --tcp-flags ACK,RST ACK,RST -j DROP
$ firewall-cmd --permanent --direct --add-rule ipv4 filter tor 1 -m owner --uid-owner 986 -j ACCEPT
$ firewall-cmd --permanent --direct --add-rule ipv4 filter tor 2 -d 54.197.234.238 -j RETURN
$ firewall-cmd --permanent --direct --add-rule ipv4 filter tor 2 -d 127.0.0.0/8 -j ACCEPT
$ firewall-cmd --permanent --direct --add-rule ipv4 filter tor 3 -j REJECT
$ firewall-cmd --permanent --direct --add-rule ipv4 nat OUTPUT 0 -j tor
$ firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 0 -j tor

This creates a pair of chains in the nat and filter tables, routes all traffic except tor and mosh to xor.hackerbots.net's elastic IP through tor's transparent proxy port, and installs the chains at the top of the firewall rules. Should I ever want to break out of tor temporarily, I just need to run:

$ firewall-cmd --direct --remove-chain ipv4 nat tor
$ firewall-cmd --direct --remove-chain ipv4 filter tor

Restarting firewalld will bring the tor rules back up:

$ sudo systemctl restart firewalld.service

Conclusion

I now have a (mostly) disposable laptop with access to my private resources and with anonymized communications. If this laptop got stolen, misplaced, or compromized, it can be made fairly trivial to revoke access to that device by way of granting revocation access to other trusted friends in advance, which I plan on doing immediately prior to leaving for the airport. The multiple layers of security and anonymity with instant notifications of any activity gives me enough buffer time to quickly cut off access should some layer be breeched.