HOWTO: Crafting arbitrary network packets with socat

FROM: NETWORKSHOP
SKILL LEVEL: AGILE

Introduction

socat is a powerful UNIX command-line tool for crafting, sending and receiving network packets. Once understood it can be used to prototype client-server designs, probing and fuzzing remote machines, data-transfer and even proxy traffic from one host to another.

NOTE: the below examples use socat to move data around networks in the open, with no encryption in place. With this in mind you should only use socat to move data of a volatile nature over a trusted VPN or using socat’s SSL options. To move data around securely on networks you don’t control you are better to use ssh and scp (section coming soon).

Installing socat

Installing socat on Linux systems

Most Linux distributions provide socat in their repositories.

To install it on a Debian-based Linux system (most distributions, including Ubuntu, CrunchBang and Debian itself) do the following:

sudo apt-get install socat

To install socat on a RedHat system, do as follows:

sudo yum -y install socat

Installing socat on OS X

Mac OS X users should download the latest version of socat from http://www.dest-unreach.org/socat/ and compile it as follows (here we use socat-1.7.2.4.tar.gz as an example).

Unpack the archive:

 tar xvzf socat-1.7.2.4.tar.gz

Change to the newly created directory and configure the source for compilation:

 cd socat-1.7.2.4
 ./configure

Compile the source:

make

Install it:

sudo make install

Examples

Send a UDP packet to a remote host

Here we send a UDP packet with a string in its payload to port 2001 on remote host 20.21.22.23.

We can pass socat our string with echo over a UNIX pipe:

echo "SO MANY BEDS, WITH PHONES NEXT TO HEADS" | socat - UDP4-DATAGRAM:20.21.22.23:2001

Send data to a remote host, logging to a file

In this example we start socat on the remote host, telling it to listen for connections on port 3333. Each time it receives a connection it will execute cat, redirecting and appending (‘>>’) received input as output into the file /tmp/log.txt:

REMOTE HOST

socat tcp-l:3333,reuseaddr,fork system:'cat >> /tmp/log.txt',nofork

Now on our client machine we echo a string over a UNIX pipe to socat, which then sends it within a TCP packet to the remote host example.net on port 3333:
 
LOCAL HOST

echo "I CAN SEE INTO YOUR KITCHEN FROM HERE" | socat - TCP4:example.net:3333

Send a UDP packet to a remote host, hitting every port (packet protest)

Here we use a range in bash, the most popular UNIX shell, to send to ports incrementing from 1001 to 65535 on the remote domain nsa.gov, sleeping for 1/10th of a second in between. Please note this is very network-noisy.

for PORT in {1001..65535}; do echo "READ YOUR CONSTITUTION, NOT OUR EMAIL." | socat - UDP4-DATAGRAM:nsa.gov:$PORT; sleep .1; done

Execute commands on a remote host, viewing command output locally

socat can be used to trigger system calls and shell scripts on the remote host. Used this way socat effectively replaces netcat and remote command execution with ssh (albeit without encryption) and affords the user great flexibility.

In the following example we execute the command ls -lt on the remote host, outputting standard output to our shell on the local machine. This can be very useful if you want to monitor the contents of a directory on a server or other remote machine. Importantly, the commands executed will not appear in the remote user’s shell history.

First we start socat on the remote server (example.net) on an arbitrary port (3333), executing the specified command each time a packet is received:

REMOTE HOST

socat tcp-l:3333,reuseaddr,fork system:'ls -lt',nofork

Note that the reuseaddr option keeps socat in a listening state rather than exiting after each call, while fork will spawn a new child-process each time it’s called.

LOCAL HOST

Now on the client we send our packet to example.net:

socat - TCP4:example.net:3333

Output from the remotely executed ls -lt command will appear in the local shell.

Naturally the output from the remote command can be logged to a local file, like so:

socat - TCP4:example.net:3333 >> log.txt

Monitoring the display of a remote computer

In this example we’ll use socat and command line tools to take a screen-grab on a remote machine that has a graphical display, retrieving the file to a local directory. This can be a useful way of monitoring remote machines with desktop environments.

REMOTE HOST

Linux and OS X have different command line tools for screencapture. If the remote machine runs Linux we’d use scrot. If OS X, screencapture. For this example we’ll use Linux as it’s the OS most used on embedded computers (like the BeagleBone Black and Raspberry Pi) and servers.

CAP=scrot # Linux
# CAP=screencapture # OS X

On the remote machine (on a LAN or Internet), we start our capture command.

socat tcp-l:3333,reuseaddr,fork system:'s=cap.png; $CAP $s; cat $s'

The above command can be left running, a server that will take a screen-grab whenever we ask for it.

LOCAL (‘MONITORING’) HOST

Now on our local monitoring machine we’ll create a folder for our screen grabs:

mkdir Screengrabs

Now we tell socat to send a TCP packet to trigger and retrieve the capture on our local monitoring machine.

socat - TCP4:example.net:3333 > Screengrabs/$(date +%Y-%m-%d_%H-%M-%S).png

This will produce a PNG file whose file name inherits a date/time form (eg.2014-05-08_21-49-51.png) in the Screengrabs directory.

AUTOMATION

The capture trigger and retrieval command can be easily automated to ask for a screen-grab every few seconds:

#!/bin/bash

# remote-grab.sh - Remote screengrab trigger and retrieval script. 
# Use with *socat* command on a Linux or OS X remote host with graphical display:
# CAP=scrot # For Linux
# CAP=screencapture # For OS X
# PORT=3333
# socat tcp-l:$PORT,reuseaddr,fork system:'s=cap.png; $CAP $s; cat $s'

# Vars
REMOTE='example.net' # A variable for the remote host we're monitoring
PORT=3333 # Define a port (be sure it matches that of the server)
DIR=~/Screengrabs # A variable for a directory that will hold our screen-grabs
POLL=10 # A variable for our poll interval, in seconds

# Check the directory for our screen-grabs exists. If not, create it.
if [ ! -d $DIR ]
then
mkdir $DIR
fi

# Simple loop
while true
             do
                 # A variable for our file name that calls *date*
                 FN=$(date +%Y-%m-%d_%H-%M-%S).png
                 # Send a TCP packet on port 3333 to trigger capture and retrieval
                 socat - TCP4:$REMOTE:$PORT > $DIR/$FN
                 echo "Retrieved $FN and wrote it to $DIR"
                 # Get some rest
                 sleep $POLL
done

Copy out the file to remote-grab.sh and set it to executable:

chmod +x remote-grab.sh

Run it like so:

./remote-grab.sh