Infosec guys are lazy people. At least in my case! There is nothing much boring that typing long shell commands or to perform recurrent tasks. After all, computers are made to make our life easier. Let them work for us!
UNIX is a wonderful environment. There are plenty ways to automate tasks: Shell scripts, Perl, Python, etc. When you need to interact with remote devices or servers, classic tools are: Netcat or Expect. Netcat is best known as the “Swiss army knife” of network administrators. Unfortunately, it cannot interact with the remote server. Expect is a powerful scripting tool based on scenarios like “If I receive this information, I do this action or send this information” but it has no network capabilities. During hack.lu last week, a friend explained how to solve a problem using another tool called “Socat“. The name comes from the concatenation of “SOcket” and “cat” (The UNIX command to display files). This tool exists since a few years but I never eared of it. Basically, Socat is a tool to manipulate sockets, one input and one output. But the idea of sockets is too restrictive. The documentation speaks about “data channels” which can be combinations of:
- a file
- a pipe
- a device (ex: a serial line)
- a socket (IPv4, IPv6, raw, TCP, UDP, SSL)
- a FD (STDIN, STDOUT)
- a program or script
For each data channel, parameters can be added (port, speed, permissions, owners, etc). For those who use Netcat, the default features remain the same.
Example #1: To exchange data via a TCP session across two hosts:
hosta$ socat TCP4-LISTEN:31337 OPEN:inputfile,creat,append hostb$ cat datafile | socat - TCP4:hosta:31337
Example #2: To use a local serial line (to configure a network device or access a modem) without a terminal emulator
$ socat READLINE,history:/tmp/serial.cmds \
OPEN:/dev/ttyS0,ispeed=9600,ospeed=9600,crnl,raw,sane,echo=false
The “READLINE” data channel uses GNU readline to allow editing and reusing input lines like a classic shell.
Example #3: To grab some HTTP content without a browser
$ cat <<EOF | socat - TCP4:blog.rootshell.be:80 GET / HTTP/1.1 Host: blog.rootshell.be EOF
Example #4: To use Socat to collect Syslog messages
# socat -u UDP4-LISTEN:5140,reuseaddr,fork OPEN:/tmp/syslog.msg,creat,append
Any UDP packet sent to the port 514 will be logged in /tmp/syslog.msg.
Those examples are nice but how to interact with the flows received from the data channel? The “EXEC” channel allow us to specify an external program or script. Using the “fdin=” and “fdout=” parameters, it is easy to parse the information received from the input channel and to send back information.
$ socat TCP4:12.34.56.78:31337 EXEC:parse.sh,fdin=3,fdout=4
The following Bash script simulates a web server and can look for suspicious content. If none is found, the visitor is redirected to another site. Note that, for security reasons, “EXEC” does not allow a relative path for the executable. It must be present in your $PATH.
#!/bin/bash # # Simple example of honeypot running on HTTP # Usage: socat TCP4-LISTEN:80,reuseaddr,fork EXEC:honeypot.sh,fdin=3,fdout=4 # FD 3 = incoming traffic # FD 4 = traffic sent back to the client # # Define the patterns for bad traffic here BADTRAFFIC1="../../.." BADTRAFFIC2="foobar" # Process the received HTTP headers while read -u 3 BUFFER do [ "$BUFFER" = "^M" ] && break echo $BUFFER | egrep -q -o "($BADTRAFFIC1|$BADTRAFFIC2)" if [ "$?" = "0" ]; then echo "ALERT: Suspicous HTTP: $BUFFER" >>http.log cat <END0 >&4 <html> <body> <h1>This incident has been logged...</h1> </body> </html> END0 exit 0 fi done cat <<END1 >&4 <html> <meta http-equiv="refresh" content="0; url=https://blog.rootshell.be"> <body You will be redirected soon... </body> </html> END1
By using the file descriptors 3 and 4, we can easily read what’s sent by the client and send data into the TCP session.
As seen in the examples above, Socat can be used to setup small servers to serve specific content or catch users. It can parse data and react based on the content. It can be used to redirect ports, bypass proxies, firewalls and much more! Commands like Socat have plenty of options and connect be reviewed here. Have a look to the man page for a good overview of all the features. Socat runs on almost all UNIX flavors (MacOS too) and a Cygwin version is available for Windows environment. It’s a must-have in the personal toolbox of all pentesters or security guy…
Hi Xavier,
I’d advise anybody interested in the tool to look at the examples of the manpage, some are really crazy 🙂
And for more craziness, make sure you try Socat v2.0!
Here is one example I use to bypass proxies with ssh, when on my server there is a proxy (with auth) behind the SSL server:
ProxyCommand socat - 'PROXY:%h:%p,proxyauth=user:pass|SSL,verify=0|PROXY:my.server:443,proxyauth=user:pass|TCP:big.brother.proxy:8080'
So yes you can guess it (read from right to left): it connects to the big bad proxy, authenticates to it and ask to be connected to my server on HTTPS port, then does the SSL stuff (here without cert verif for clarity), then connects to my hidden proxy, with auth and ask it to connect to whatever ssh server I want, as usual for a ProxyCommand.
And if big bad proxy admin tries manually to connect to my HTTPS server he’ll simply find… my HTTPS website 🙂
For those who are interested to reproduce the setup on the server side, see here.
With Socat v1.x, it requires 3 socat commands and intermediate sockets while here with v2.0 one single command is enough.
Ho and a quick one for sniffing a serial link:
socat -v -x PTY,link=/tmp/myttyUSB0,raw,echo=0,isig=0 /dev/ttyUSB0,raw,echo=0,isig=0
Now use /tmp/myttyUSB0 in place of /dev/ttyUSB0
Hey Tom,
Could you give more details? What are you trying to achieve?
Something like this?
socat OPEN:/dev/ttyS0 EXEC:script.sh,fdin=3,fdout=4 | socat – UDP:ip:port
/x
I’m a little confused on how you might interact in the situation below.
I would like to be able to open a connection to a serial device, probe it on occasion, and then take the response, parse it, and send it out UDP.
So far I have tried
socat fileread… serial device | script.sh | socat fileread UDP:ip:port
It seems like being able to name fdin/fout might be able to help me achive this. Any advice on how I might make this work.