Monday, October 21, 2013

Pianobar

INTRODUCTION

In this post I'm going to go over Pianobar. We'll grab the latest source, compile it, set it up, and run it. Pianobar is a awesome opensource console based client for Pandora Radio.

Step One:

First we'll need to install git so we can grab the latest source from github. We're going to grab the source from git so we have the latest code, otherwise we could easily install it from the repositories. So jumping to your terminal you'll just need to
$ sudo apt-get install git

Step Two:

We need to get the latest source of pianobar. So in the terminal again type the following
$ git clone https://github.com/PromyLOPh/pianobar.git

Step Three:

We need to install the dependencies for pianobar to work correctly. Again the your terminal type the following:
sudo apt-get install libao-dev libmad0-dev libfaad-dev libgnutls-dev libjson0-dev libgcrypt11-dev

Step Four:

Now all we need to do is compile and install the git source we got earlier. So in the same directory that you were in when you used git to get pianobar just `cd` to the pianobar directory and use:
$ cd pianobar
$ make
$ sudo make install

Step Five:

At this point pianobar should be installed assuming we didn't get any errors along the way. So the next step is to add information to the config file in your home directory. Pianobar should have a directory within the .config directory, if not create it.
cat ~/.config/pianobar/config
We'll need to add some information to the config file in order to make pianobar work correctly. If there is no config file in the pianobar directory create a blank text file named 'config'.
password = pandora account password here
Adding your username and password are optional, but it saves you from having to type in your username and password every time.

Step Six:

Now to run the beauty that is pianobar for the first time. You can run pianobar by just typing pianobar and hitting enter into your terminal.

Optional steps:

So now that we have pianobar functional we can work on other things. For instance getting our plaintext password to be encrypted, keybinding, etc.

Password Encryption:

Keybinds:

If you're using a multimedia keyboard, you can add keybinds for pianobar. For my setup I have a microsoft wireless comfort keyboard 4000, and I'm running crunchbang with openbox. Openbox keybinds are located in the rc.xml config file. What we'll also need is to grab control-pianobar.sh files. Make sure you're in your .config/pianobar directory before you use the following command:
git clone https://github.com/Bruce-Connor/control-pianobar.git
First we need to know exactly what the keys do in order to map them to a command. So we'll use xev tool for that. So in  your terminal type in xev and hit enter, next hit one of the multimedia keys on your keyboard. You'll see output like this:
KeyPress event, serial 46, synthetic NO, window 0x4e00001,
root 0x370, subw 0x0, time 2488373614, (943,113), root:(1395,1057),
state 0x10, keycode 164 (keysym 0x1008ff30,
XF86Favorites), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False

KeyRelease event, serial 46, synthetic NO, window 0x4e00001,
root 0x370, subw 0x0, time 2488373806, (943,113), root:(1395,1057),
state 0x10, keycode 164 (keysym 0x1008ff30, XF86Favorites), same_screen YES,
XLookupString gives 0 bytes:
XFilterEvent returns: False
XF86Favorites is what we'll need to configure our keybind. So open up your rc.xml file and navigate to where the keybind area is and add the xml portion to execute a command from the control-pianobar.sh. The button I'm setting up is the "star" button on my keyboard which I'm going to use to tell pianobar that I like that song. In the rc.xml file I'm going to add:
<keybind key="XF86Favorites"> 
    <action name="Execute"> 
        <command>/home/xplicit/.config/pianobar/control-pianobar.sh +</command>
    </action> 
</keybind>

Now all we need to do is save the rc.xml file and reconfigure openbox then test it.
┌─[*********@*******]─[~/.config/pianobar]
└──╼ pianobar
Welcome to pianobar (2012.05.06)! Press ? for a list of commands.
(i) Control fifo at /home/username/.config/pianobar/ctl opened
(i) Login... Ok.
(i) Get stations... Ok.
  0) q   2Pac (Tupac) Radio
  1) q   A Day To Remember Radio
  2) q   Eazy-E Radio
  3) q   Eminem Radio
  4) q   Mac Miller Radio
  5) q   New Found Glory Radio
  6)  Q  QuickMix
  7) q   Tate Stevens Radio
  8) q   Travie McCoy Radio
[?] Select station: q
  6)  Q  QuickMix
[?] Select station: 6
|>  Station QuickMix
(i) Receiving new playlist... Ok.
|>  The Last Thing I Do by Tate Stevens on Tate Stevens @ Tate Stevens Radio
|>  I'd Rather Fuck You by Eazy-E on Eternal E (Explicit) @ Eazy-E Radio
|>  Mr. Highway's Thinking About The End by A Day To Remember on Homesick @ A Day To Remember Radio
You can see all my keybinds for pianobar here.

Links and Sources:

Pianobar Project
Bruce Connor fifo script

Saturday, October 12, 2013

Dynamic Subdomains with OpenVPN and PyTinyDNS

Introduction

As I have covered in a previous post about PyTinyDNS there are multiple uses for a dynamic DNS service like this. One of my side projects is hosting a private Virtual Private Network (VPN). Along with hosting my own TLDs, I also wanted to have a custom solution for dynamically assigning a subdomain to each individual client that connects to the network. This way if the user happens to get assigned a different IP, others on the net will be able to easily connect to their services without any issues.

Redis

PyTinyDNS uses redis to make dynamic additions of domains and subdomains possible without adding extra config files or restarting the daemon. PyTinyDNS also comes with an import script that allows you to add either a text file full of domains or individual domains via the command line arguments. We'll strip the functionality from the import tool and use it to assign dynamic subdomains through OpenVPN's scripting features.

OpenVPN

OpenVPN comes with built-in options to add custom scripts that are triggered by multiple events. The following are example events that you can configure in order to take advantage of endless custom solutions.

  • --up (Executed after TCP/UDP socket bind and TUN/TAP open.)
  • --tls-verify (Executed when we have a still untrusted remote peer.)
  • --ipchange (Executed after connection authentication, or remote IP address change.)
  • --client-connect (Executed in --mode server mode immediately after client authentication.)
  • --route-up (Executed after connection authentication, either immediately after, or some number of seconds after as defined by the --route-delay option.)
  • --client-disconnect (Executed in --mode server mode on client instance shutdown.)
  • --down (Executed after TCP/UDP and TUN/TAP close.)
  • --learn-address (Executed in --mode server mode whenever an IPv4 address/route or MAC address is added to OpenVPN's internal routing table.)
  • --auth-user-pass-verify (Executed in --mode server mode on new client connections, when the client is still untrusted.)

The only event that we need to watch in order to add custom A PTRs to PyTinyDNS is --client-connect. Go ahead and create a directory to store the custom script in.

$ mkdir /etc/openvpn/scripts

Now at the bottom of your OpenVPN server.conf, add the following lines.

script-security 2
client-connect '/usr/bin/python /etc/openvpn/scripts/connect.py'

The Script

The following is a quick Python script used to add the correct subdomain based on the user's common name used in the client's certificate.

#!/usr/bin/python
import redis
import os
 
def insert_record(domain, ip, redis_server):
 r_server = redis.Redis(redis_server)

 try:
  r_server.hset('pytinydns.domains', domain, ip) 
 except:
  pass

def main():
 redis_server = 'localhost'

 try:
  insert_record(os.environ['common_name'] + ".myvpn.net.",os.environ['ifconfig_pool_remote_ip'],redis_server) 
 except:
  pass

 return 0

if __name__ == '__main__':
 main()

The reason for the pass statements is that we must return the value 0 or OpenVPN will deny the client entry. If records are not being added, check to make sure that the server is running and that it is in fact running on localhost.

Now you need to restart OpenVPN in order for the changes to server.conf to go into effect.

$ sudo service openvpn restart

Considerations

Using the default configs with PyTinyDNS, non locally resolved domains are forwarded to the system's default DNS server. In order to avoid information leakage of local common names, you could implement a method to not forward any requests with a particular domain name or disable this option completely by setting the PyTinyDNS option "Resolve_Nonmatch" to no.

Thursday, October 10, 2013

Debunking the False Security of Cardless ATMs

According to CNN, FIS financial services is launching a new way for customers to access cash without an ATM card or debit card. This technology has been piloted by three banks in the recent months using a mobile application called “Cardless Cash Access”, and is slated for widespread implementation by mid-2014. They claim it is safer than using an ATM card. First, lets review the process described there to withdraw from an ATM without the use of a card:

  1. Log into an application on your mobile device that interacts with your bank
  2. Place an order for your cash
  3. Upon arrival to the ATM, use the application to scan a code on the ATM to prove you are physically there
  4. The ATM sees that you are there and relinquishes the requested cash

This methodology was reviewed by Mary Monahan of Javelin Strategies & Research, and she labeled it as more secure than traditional ATM cards for the following reasons:

  • Because there is no card, there can be no “card skimming”
  • In the event your phone is stolen, the application still needs additional log-in information and PIN information

A card skimmer is a small hardware device that can be inserted into an ATM to record the information on the ATM card when it is inserted into the machine. Her full analysis of FIS' program, “Cardless Cash Access”, is behind a pay gate; I wasn't about actually pay money for something that should be completely free information. Besides, she's wrong.

Construction of an ATM “card skimmer” is difficult, and placing one is risky to any potential attacker. Retrieving one could be even riskier. I'd argue that this technology is even less safe than online banking. Online banking can be unsafe due to the fact that malware and software viruses can record information on a victim's computer, allowing criminals access to bank accounts; however, the criminals in question have to jump through many hoops to actually turn this online access into cash that they can use. Usually they lose some of the money in the process, and there's a trail leading back to them. To avoid this they use scams to trick yet more victims into withdrawing and depositing the cash for them, usually with something like western union, so that transactions cant be “charged back” or otherwise tracked back to the criminal.

With the advent of mobile malware, I've uncovered a hypothetical way that criminals could cause much more severe damage. Similar to computers, mobile phones can be vulnerable to keylogging attacks. A keylogger is a piece of software that allows an attacker to record the buttons pressed on a keyboard, or in this case, the software keyboard on a smart phone. Smart phone keyloggers already exist, and are nothing new. Also similar to computers, proxy software can be installed on a mobile phone. Proxy software is software that allows a user to use a computer or mobile device to make it look like they are coming from the device the proxy is on, as opposed to their real location.

So what relevance does this have to “Cardless Cash Access”? Its simple, really. An attacker could create a piece of malware that infects a person's smart phone with both a proxy and a keylogger. From there, he could record the information entered into the application. After that, it would be trivial to install the application on his own mobile device, log in, request cash, and scan the ATM code. Suppose for a moment that this didn't work, for whatever reason (like the application being locked on a per-user basis to a particular phone). At this point, the attacker could use a proxy in the malware to impersonate the victim's phone, upload the scanned key to the application from the victim's phone, resulting in the ATM dispensing the cash anyway. Not only does this make it easier for cybercriminals to access the data required without physical intervention, it also makes it easier for a criminal to turn his access directly into cash without using a scam or jumping through the various hoops required while using a skimmer. There is also much less risk involved to the criminal. To hide his or her identity and “cash out”, the criminal only need bring a can of black spray paint to the ATM camera.

I talked with a mobile malware analyst, Matt McDevitt, to get an idea of how easy it would be for a malware author to write such a virus, and to determine the likelihood of such an attack. He responded saying that it would be incredibly easy for a malware author to write and deliver such a virus, and that the likelihood of such a virus being written is extreme. He further went on to say, "another [malicious] provider could come out with a trojanized version of this application". What he means here is that someone could unpack the "Cardless Cash Access" application, backdoor it, and then pack it back up for shipping to unsuspecting users. There is also the risk of a supply chain attack, which is by far more sophisticated, but not impossible. Supply chain attacks are used by some of the world's brightest computer criminals. If the master copy of "Cardless Cash Access" to be distributed to all of the end users were to be compromised, the entire financial grid could become at risk.

I was able to come up with several ideas for making this model more secure, however they all involve more “big brother” type things. For example, a thumbprint scanner at the ATM could work just as well, or using the cellular GPRS data to confirm that the user is actually physically in the same cellular grid that the ATM was located in would be a good start. However, many privacy advocates (including myself) prefer disabling GPRS and dislike giving their thumbprint to machines.

Moving on, there is another feasibility problem with the “Cardless Cash Access” program. Sometimes there are cellular connectivity problems in the areas ATM's are located in. To address this, FIS has proposed an “offline mode” that would allow usage of the application on the phone regardless of connectivity problems. This is nothing but an opening for “replay” attacks in which an attacker could record the data from an “offline mode” transaction and “replay” the data into an ATM, making it dispense the cash.

In conclusion, this cardless ATM methodology removes much of the risk of getting caught from criminals intent on stealing money. While Mary Monahan is quoted as saying, "The phone is becoming a security blanket; the more you can do with it, the better,”; attackers have been using mobile devices as a proverbial malware playground. With mobile malware on the rise, the less control a phone has over your real life, the better.


Tuesday, September 17, 2013

CryptHook: Secure TCP/UDP Connection Wrapper

Introduction

CryptHook is a modular implementation for securing existing applications with symmetrical block cipher encryption. It works by hooking the base system calls for network communication send/sendto and recv/recvfrom. CryptHook will work with existing applications that rely on these system calls.

Download the Code

$ git clone https://github.com/chokepoint/CryptHook.git
or
$ wget https://github.com/chokepoint/CryptHook/archive/master.zip

Hooking the Calls

Hooking system calls is relatively simple, and is often used to deploy userland rootkits such as Jynx/Jynx2. For this, we're really only interested in hooking four system calls, as previously mentioned. With these hooks, we are able to intercept any data before it is sent across the network (for encryption), and also any data before it touches the client/server application (for decryption).

static ssize_t (*old_recv)(int sockfd, void *buf, size_t len, int flags);
static ssize_t (*old_send)(int sockfd, void *buf, size_t len, int flags);
static ssize_t (*old_recvfrom)(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
static ssize_t (*old_sendto)(int sockfd, void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

ssize_t recv(int sockfd, void *buf, size_t len, int flags) {
....
}

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { 
....
}

ssize_t send(int sockfd, const void *buf, size_t len, int flags) {
....
}

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) {
....
}

Encrypting / Decrypting Data *Updated*

As part of this proof of concept, I've focused primarily on Advanced Encryption Standard (AES). CryptHook is now only set up with AES 256 in GMC mode, but it would be relatively simple to implement additional algorithms that are already a part of the OpenSSL library.

#define BLOCK_CIPHER EVP_aes_256_cbc()  // EVP_aes_256_cbc() and EVP_bf_cbc() have been tested
#define BLOCK_SIZE 16    // Blowfish = 8 AES = 16
#define KEY_SIZE 32     // Blowfish is variable, lets go w/ 256 bits

The key is passed to the library using an environment variable. The plain text is then used to derive a key using PBKDF2 with multiple iterations. If you're going to use this in a live environment, I highly encourage you to change the salt and number of iterations. If no key is passed to the library, it defaults back to PASSPHRASE defined below.

#define PASSPHRASE "Hello NSA"

Example Usage

As discussed earlier, this can be use with many different client/server applications. As a demonstration, lets add a layer of encryption to SSHd.

Server side:
$ LD_PRELOAD=./crypthook.so UC_KEY=OHarroNSA sshd -p 5000
Client Side:
$ LD_PRELOAD=./crypthook.so UC_KEY=OHarroNSA ssh localhost -p 5000

Wireshark Capture

As you can see, the packets show up as malformed, because Wireshark doesn't know how to interpret them, and the data is obviously encrypted.

Going Beyond

It'd be relatively simple to add an SSL header to each packet so that the packets look even more innocuous to anyone casually observing the transaction. SSL headers for application data are five bytes. Adding a fake SSL handshake immediately upon connection would also be a nice touch.

[SSL Record Type][SSL Version][Data Length]
[1 Byte]         [2 Bytes]    [2 Bytes]

Friday, September 13, 2013

Linux Kernel Structure Definition Lookup Script

Introduction

If you've ever written anything kernel side for Linux, I'm sure you've bashed your head on the keyboard as many times as I have looking through lackluster documentation and scouring source files to find structure definitions. Here's a little script that will show you the source file and line number of the given structure definition.

First of all, this script relies on a fantastic website that allows you to easily search through the Linux source files http://lxr.linux.no. I simply wrote a script to parse the output to show structure definition locations. Change the URL in the script depending on your current kernel version number.

Example

$ ./structure.py crypto_tfm
[-] Searching for all structure definitions of: crypto_tfm
[+] drivers/staging/rtl8192e/rtl8192e/rtl_crypto.h, line 186
[+] drivers/staging/rtl8192u/ieee80211/rtl_crypto.h, line 189
[+] include/linux/crypto.h, line 413

The Source

#!/usr/bin/python
# Linux Kernel Structure Search

import sys
from BeautifulSoup import BeautifulSoup
import requests

def main(argv):
 struct_search = "http://lxr.linux.no/linux+v3.11/+code=" + argv[0]
 in_struct = 0
 
 print "[-] Searching for all structure definitions of: " + argv[0]
 
 req = requests.get(struct_search)
 soup = BeautifulSoup(req.text)

 spanTag = soup.findAll('span')
 for tag in spanTag:
  try: 
   myclass = tag['class']
   if myclass == 'identtype':
    if tag.string == "Structure":
     in_struct = 1
    elif in_struct:
     break
  
   if myclass == "resultline" and in_struct:
    aTag = tag.find('a')
    print "[+] " + aTag.text
  except: 
   ohnoez=1

 if not in_struct:
  print "[-] No Structures Found"
  
if __name__ == "__main__":
 main(sys.argv[1:])

Tuesday, September 10, 2013

sslnuke -- SSL without verification isn't secure!

A video demonstration of the tool described in this post can be seen at ascii.io.

We have all heard over and over that SSL without verification is not secure. If an SSL connection is not verified with a cached certificate, it can easily be hijacked by any attacker. So in 2013, one would think we had totally done away with this problem. Browsers cache certificates and very loudly warn the user when a site has offered up a self-verified certificate and should not be trusted, browser vendors have pretty much solved this problem. However, HTTPS is not the only protocol that uses SSL. Unfortunately, many clients for these other protocols do not verify by default and even if they did, there is no guarantee of secure certificate transfer. After all, how many people are willing to pay $50 for an SSL certificate for their FTPS server?

A common protocol that uses SSL but is rarely verified is IRC. Many IRC clients verify by default, but most users will turn this off because IRC servers administrators tend not to purchase legitimate SSL certificates. Some popular clients even leave SSL verification off by default (IRSSI, for example). We already know that this is unwise, any attacker between a user and the IRC server can offer an invalid certificate and decrypt all of the user's traffic (including possibly sensitive messages). Most users don't even consider this fact when connecting to an SSL "secured" IRC server.

The purpose of sslnuke is to write a tool geared towards decrypting and intercepting "secured" IRC traffic. There are plenty of existing tools that intercept SSL traffic already, but most of these are geared towards HTTP traffic. sslnuke targets IRC directly in order to demonstrate how easy it is to intercept "secured" communications. sslnuke usage is simple.

Usage

First, add a user account for sslnuke to run as and add iptables rules to redirect traffic to it:

    # useradd -s /bin/bash -m sslnuke
    # grep sslnuke /etc/passwd
    sslnuke:x:1000:1000::/home/sslnuke:/bin/bash
    # iptables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner 1000 -m tcp \
      --dport 6697 --tcp-flags FIN,SYN,RST,ACK SYN -j REDIRECT --to-ports 4444

Finally, login as sslnuke, build, and run sslnuke:

    # su -l sslnuke
    # cd sslnuke
    # make
    # ./sslnuke

Run an IRC client and login to your favorite IRC network using SSL, IRC messages will be printed to stdout on sslnuke.

    [*] Received connection from: 192.168.0.5:58007
    [*] Opening connection to: 1.1.1.1:6697
    [*] Connection Using SSL!
    [*] irc.com -> AUTH (1.1.1.1): *** Looking up your hostname...
    [*] irc.com -> AUTH (1.1.1.1): *** Found your hostname
    [*] irc.com -> victim (1.1.1.1): *** You are connected to irc.com with TLSv1.2-AES256-GCM-SHA384-256bits
    [*] 192.168.0.5 -> nickserv (192.168.0.5): id hello
    [*] NickServ!services@irc.com -> victim (1.1.1.1): Password accepted - you are now recognized.

sslnuke will automatically detect a client using SSL and determine whether or not to use SSL. The code could also be easily modified to show web site passwords or FTP data, anything using SSL. To attack users on a network, sslnuke can be used in conjunction with an ARP poisoning tool, such as the one found at Blackhat Library or it can be deployed on a gateway.

Mitigation

Now on to the important part, how do we verify SSL connections? The first step is to transfer the SSL certificate over an alternative medium, the best way would be to have the administrator directly give you the certificate. However, if this is not possible, openssl can download the certificate from the server:

    # openssl s_client -showcerts -connect irc.com:6697 </dev/null

Save the certificate into "~/.irssi/ssl/irc.com.crt". It is best to run the command from a computer on a different network than yours to prevent this from being intercepted. Next, to configure IRSSI to use the certificate, save a network:

    /network add irc
    /server add -ssl_cafile ~/.irssi/ssl/irc.com.crt -network irc -port 6697 irc.com

If IRSSI ever gets an invalid certificate, it will warn you and disconnect immediately. However, for the truly paranoid, a Tor hidden service or VPN should be used. To configure automatic Tor hidden service redirection on Linux one can run the following commands:

    # echo "VirtualAddrNetwork 10.192.0.0/10" >> /etc/tor/torrc
    # echo "AutomapHostsOnResolve 1" >> /etc/tor/torrc
    # echo "TransPort 9040" >> /etc/tor/torrc
    # echo "DNSPort 5353" >> /etc/tor/torrc
    # killall -HUP tor
    # iptables -t nat -A OUTPUT -p tcp -d 10.192.0.0/10 -j REDIRECT --to-ports 9040
    # iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 5353
    # ncat xxxxxxxxxxxxxxx.onion 6667
    :irc.com NOTICE AUTH :*** Looking up your hostname...
    :irc.com NOTICE AUTH :*** Couldn't resolve your hostname; using your IP address instead
    ^C

Ultimately, IRC clients should use an SSH-style key verification. On first connect, present the certificate fingerprint to the user and force the user to confirm it and then cache the certificate. If it changes the next time, do not allow the connection.

Source

The source code can be downloaded on Github.

Saturday, September 7, 2013

PiBowl: Rasperry Pi Secure (SIPS/SRTP) Asterisk Autoconfig Script

Introduction

This is directly related to my last post Create your own Fishbowl: an NSA Approved Telecommunication Network. That tutorial is dedicated to setting up both OpenVPN and Asterisk in order to provide secure end to end VoIP communications. This is part of a new project to make it as easily deployable as possible.

PiBowl Server

PiBowl server is the first part of the puzzle. Its specifically designed to be a one stop shop for installing and configuring Asterisk on a Raspberry Pi. For the demonstration, I am assuming that the user has a fresh installation of Raspbian on their SD Card. The installation script has also been tested on Debian Wheezy, and works just the same.

Getting the Script

PiBowl is hosted on github. You can either clone the repository, or if you don't feel like installing additional packages, access it directly using the following wget request.

$ wget https://github.com/chokepoint/PiBowl/archive/master.zip
$ unzip master.zip

Now that you have the script, you really only need to edit two variables defined in pibowl.sh.

  • AST_IP
  • ALLOW_CONTACT
AST_IP is the IP address of the interface that you want TLS to bind to. This prevents external users from probing or accessing Asterisk. The only traffic coming in or out should be through the VPN. ALLOW_CONTACT is the range of IPs that are able to make or receive calls. This is redundant, but ensures that we don't have any unencrypted or unwanted calls taking place.

Running the Script

You need to run PiBowl as sudo in order for the install to complete.

$ sudo ./pibowl.sh
If you're compiling on a Rapsberry Pi, go ahead and make a pot of coffee, bake a pizza, mow the lawn, take a shower, and then come back to see if it's done with the build yet. Interaction is minimal and requires your input while creating the Certificate Authority password used for certificate signing, and when it comes time to build client keys. You can build as many client keys / SIP users as you want during the configuration. Each user will be assigned a semi random password, as well as a sequential dialing extension. Extensions can be changed by tweaking the EXTEN variable in pibowl.sh. If you need to add users later, simply refer back to the original article for how to do it manually.

Going Beyond

Plans are to build similar configs for a client based Raspberry Pi as well. If you'd like to help with the client side, feel free to send pull requests to the github, and I'll merge them in as appropriate. This will hopefully show people that the concept is relatively simple and easy to deploy. As this becomes more user friendly, I hope that it can be used to connect friends and families in a secure manner.