Showing posts with label privacy. Show all posts
Showing posts with label privacy. Show all posts

Tuesday, July 22, 2014

Defuse.ca's Encrypted Pastebin as a TOR Hidden Service

Introduction

The following is all based on the original code from defuse.ca who was gracious enough to release the code via Github. The released repository is mostly intact, but requires some quick fixes to get it running. I forked the original repository, and created an easy to deploy standalone package, also available from Github

The code is obviously available for review, but this article will focus on deploying PIEBin as a TOR hidden service. Testing was done under vanilla Debian install on a minimal VPS setup.

Dependencies

Before we dig in, you'll need to install the following packages onto your VPS.
  • MySQL
  • Nginx
  • PHP
  • Tor
$ sudo apt-get install mysql-server php5-mysql nginx php5-fpm tor

Download Pastebin Files

For minimal configuration, install the files into /usr/share/nginx/www/pastebin via the following commands. Please note that if you are setting up your own TOR service, you should take precautions while downloading the software that you intend to run as the hidden service. Timing analysis / timeline reconstruction could point a finger at you if you're using either your server or home IP address to acquire the software from third party sites. Download using your tor browser or setup proxy chains.

 $ cd /usr/share/nginx/www
 $ git clone git@github.com:chokepoint/pastebin.git

Initialize the Database

Now that we have mysql installed, we need to create the database and table structure for the pastebin application. Using the password you created during installation, open up the MySQL client.

mysql -u 'root' -p
Password: *****
> CREATE DATABASE pastebin;
> CREATE TABLE pastes (token VARCHAR(70), data TEXT, time INTEGER, jscrypt TEXT);

Preparing TOR

Configuring a server as a TOR hidden service is relatively straight forward, but care must be taken in order to not leak information about the actual host of the service. We'll configure both port 80 and 443. HTTP requests will simply be redirected to the HTTPS service for security reasons. To do this, we'll add the following three lines to /etc/tor/torrc

HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 443 127.0.0.1:443
HiddenServicePort 80 127.0.0.1:80

Now, simply restart tor in order to reveal your new .onion address.

$ sudo service tor restart
$ sudo cat /var/lib/tor/hidden_service/hostname
sldfjadlkjfalieta.onion

Generate Self Signed SSL Certificates

In order to support encrypted HTTPS connections, we must generate a self signed certificate. The following sequence will set up a 2048 bit key for use with nginx which we'll configure next.

 $ sudo mkdir /etc/nginx/ssl && cd /etc/nginx/ssl
 $ sudo openssl genrsa -des3 -out server.key 2048
 $ sudo openssl req -new -key server.key -out server.csr
 $ sudo cp server.key server.key.org
 $ sudo openssl rsa -in server.key.org -out server.key
 $ sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Configure nginx

As I mentioned earlier, you need to take steps to ensure information is not leaked about the actual server hosting these hidden services. The following section will configure nginx to listen on localhost only so that our service can only be accessed through the TOR network. Be sure to change server_name to the .onion you generated during the first step. You may also need to tweak the root directory depending upon where you originally installed the pastebin source files.

# /etc/nginx/sites-available/default
 server {
  listen 127.0.0.1:80; ## listen for ipv4; this line is default and implied
  listen 127.0.0.1:443 ssl;
 
  ssl_certificate /etc/nginx/ssl/server.crt;
  ssl_certificate_key /etc/nginx/ssl/server.key;
 
  root /usr/share/nginx/www/pastebin; # Change to your directory
  index index.php index.html index.htm;
 
  # Change this to the onion address we created earlier.
  server_name sldfjadlkjfalieta.onion;
 
  location / {
   try_files $uri $uri/ /index.html;
  }
 
  location ~ \.php$ {
               try_files $uri =404;
               fastcgi_pass 127.0.0.1:9000;
               fastcgi_index index.php;
               fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
               include fastcgi_params;
               
       }
 
  #error_page 404 /404.html;
  #error_page 405 = $uri;
 }

Next we'll disable logging by modifying /etc/nginx/nginx.conf.

access_log /dev/null
error_log /dev/null

Now restart nginx so that the changes take effect.

Testing

If you completed the above steps you should now be running your own TOR hidden, encrypted pastebin. Open up your browser and navigate to the .onion address we generated earlier.

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.

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]