Skip to content

nnathan/monopiped

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

67 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Monopiped

Monopiped is a pastiche of Colin Percival's spiped.

Motivation

The idea of Monopiped started when working on sobfs which was in turn inspired by this write up by George Murdocca on how IDS middleboxes can be defeated using rot-13 encryption. These are all ideas for testing and improving the security of IDS middleboxes.

After writing sobfs I learned about spiped which was a better solution than sobfs/rot-13 for defeating IDS middleboxes.

Originally Monopiped was intended to modify spiped and replace crypto primitives by those available in Monocypher (e.g. X25519 instead of finite field Diffie-Hellman, ChaCha20Poly1305 instead of AES-CTR+HMAC, etc.).

However since inception there was no progress on this front.

The idea pivoted from being a modification of spiped to instead a reinterpretation in Rust, primarily as a technical exercise for the author to learn Rust and dabble in cryptography and sockets.

Build

First fetch the monocypher submodule: git submodule update --init --recursive.

Install Rust and run cargo build -r. (You want -r for release version which is at least an order of magnitude faster than debug build.)

Operation

There are two "modes" that monopiped can be run as:

  • client or encrypt mode: this is when monopiped listens for unencrypted connections on a socket, and sends encrypted connections to the server
  • server or decrypt mode: this is when monopiped listens for encrypted connections, and sends/proxy unencrypted connections to a target socket

Tunneling over TCP

The usual way to run monopiped is by tunneling a TCP application like ssh encrypted over TCP.

This is a depiction of how a client and server would run:

┌────────────────────────────────────────────────────┐                                   ┌──────────────────────────────────────────────────┐
│ client                                             │                                   │  server                                          │
│                                                    │                                   │                                                  │
│ ┌────────────────────────┐        ┌───────────┐    │        (encrypted over tcp)       │   ┌───────────┐       ┌────────────────────────┐ │
│ │ application (e.g. ssh) │◀──────▶│ monopiped │◀───┼───────────────────────────────────┼──▶│ monopiped │◀─────▶│   target (e.g. sshd)   │ │
│ └────────────────────────┘        └───────────┘    │                                   │   └───────────┘       └────────────────────────┘ │
│                                                    │                                   │                                                  │
└────────────────────────────────────────────────────┘                                   └──────────────────────────────────────────────────┘

As an example of tunneling SSH, you would:

  • generate a shared key: dd if=/dev/urandom bs=32 count=1 of=key.bin
  • run on the client: monopiped -l 127.0.0.1:3000 -t server.example.com:2222 -e -k key.bin
  • run on the server: monopiped -l 0.0.0.0:2222 -t 127.0.0.1:22 -d -k key.bin

Then on the client you can connect to the SSH server by running: ssh -p3000 127.0.0.1.

Tunneling over Websockets

monopiped also supports tunneling TCP application encrypted over WebSockets.

This is a depiction of how a client and server would run:

┌────────────────────────────────────────────────────┐                                   ┌────────────────────────────────────────────────────────────────────────────────────────┐
│ client                                             │                                   │  server                                                                                │
│                                                    │           [encrypted over         │                                                                                        │
│ ┌────────────────────────┐        ┌───────────┐    │       WebSockets via HTTP(S)]     │   ┌────────────────────────────┐       ┌───────────┐        ┌────────────────────────┐ │
│ │ application (e.g. ssh) │◀──────▶│ monopiped │◀───┼───────────────────────────────────┼──▶│nginx/caddy/websocket proxy │◀─────▶│ monopiped │◀──────▶│   target (e.g. sshd)   │ │
│ └────────────────────────┘        └───────────┘    │                                   │   └────────────────────────────┘       └───────────┘        └────────────────────────┘ │
│                                                    │                                   │                                                                                        │
└────────────────────────────────────────────────────┘                                   └────────────────────────────────────────────────────────────────────────────────────────┘

What's different to TCP is the inclusion of a webserver that will front the monopiped on the server side.

As an example of tunneling SSH, you would:

  • generate a shared key: dd if=/dev/urandom bs=32 count=1 of=key.bin
  • run on the client: monopiped -l 127.0.0.1:3000 -t wss://server.example.com/ssh -e -k key.bin
  • run a websocket proxy server on the server: (see below for an example Caddy v2 example)
  • run on the server: monopiped -l 127.0.0.1:3000 -t 127.0.0.1:22 -d -k key.bin -w

Then on the client you can connect to the SSH server by running: ssh -p3000 127.0.0.1.

Here is a sample Caddyfile to use with the Caddy v2 webserver to setup a route to a websocket backend, where the backend will be monopiped listening in websocket mode on port 3000:

server.example.com:80 server.example.com:443 {
        root * /var/www/html
        file_server
        reverse_proxy /ssh 127.0.0.1:3000
}

The above Caddyfile listens on both HTTP and HTTPS. Since the transport is end-to-end encrypted between client and server over WebSockets or TCP, it is perfectly fine to use HTTP and still maintain confidentiality and integrity. Packet captures of traffic over HTTP would just show WebSocket binary payloads and little else.

Acknowledgements

Thanks to George Murdocca for inspiring this idea (see above for link to his writeup).

Thanks to Gak for patiently helping me understand Rust and providing direction on how to implement Monopiped.

Thanks to Colin Percival for providing a reference to work from including specifying a design document to understand how the cryptography was implemented.