Quick-and-Dirty Remote Access using netcat and Virtual Files

Have you ever wanted quick remote access to a machine, but didn’t have time or permissions to set up an SSH server? Using this quick-and-dirty hack, you can set up (albeit insecure) remote access in under a minute.

netcat

First, let’s talk about netcat. netcat is a command which allows you to make a raw TCP connection and send/receive arbitrary data using stdin/stdout. For example:

nc -l -p 1234

This command listens on the port 1234. [1] When a client connects to this port, a two-way connection is formed between server and the client. What the client types on his/her stdin is printed out on the server’s stdout, and what the server types on its stdin is printed out on the client’s stdout. In order to connect to the server, the client types:

nc server-address 1234

Piping to Send/Receive Input/Output

So what comprises remote access? At its most basic, remote access requires the ability to send commands and receive output. Achieving either of these things on its own is quite simple using netcat and Unix pipes. For example, to send commands without being able to see output, the server runs:

nc -l -p 1234 | bash

Similarly, for the client to be able to see the output of commands typed by the server, but not be able to send commands him/herself, the server runs:

bash | nc -l -p 1234

However, combining these is a problem. One very hacky way of accomplishing this would be for the server to listen on two ports, one for receiving commands, and one for sending outputs:

nc -l -p 1234 | bash | nc -l 5678

However, this would require the client to simultaneously run two commands at once in order to fully interact with the server:

nc server-ip-address 1234    # Terminal A; send commands
nc server-ip-address 5678    # Terminal B; receive output

The reason for the necessity of this hack is that standard Unix shell pipes are one-way. That is, they receive the stdout of one command and pipe it to the stdin of another, but they cannot simultaneously pipe the stdout of the second command into the stdin of the first. Luckily, the Unix principle of every device as a file comes to the rescue.

Device Files and Named Pipes

If you’ve ever written terminal-compatible code in C or some equivalent language, you may have noticed that stdin and stdout are treated like normal files. This is because, as far as the user is concerned, they are just normal files. In Unix speak, they are called virtual files. They appear to the user as normal files, and can be read from and written to like normal files. However, under the hood, they do not actually exist on the filesystem. They are simulated by the kernel, and are what allow programs to easily read user input and print output.

Luckily for us, users are allowed to create their own virtual files. On standard Linux systems, the command for doing this is called mknod. The usage may vary from system to system, so I’ll give the Linux usage here (just run man mknod to see the usage for your system). What’s special about mknod is that, unlike standard Unix shell pipes, mknod allows us to create pipes which live in the standard file system, which means that we can refer to them by name. For example:

mknod /tmp/pipe p

This creates a virtual file, “/tmp/pipe” (sometimes called a named pipe), which can be both written to and read from (the second argument, “p”, specifies that the file is to be a normal pipe. Read the man page for more on different types of virtual files). Now that we have this second pipe, we can use it to more cleanly run remote access on our server:

nc -l -p 1234 < /tmp/pipe | bash > /tmp/pipe

Then all the client has to do is:

nc server-address 1234

…and he/she can issue commands and see the response!

But that command that we ran on the server was a bit complex, so let’s investigate what’s going on here. First, the server listens on port 1234. When a connection is made to that port, the data which is received over the network is piped into bash, which executes the commands. The output of bash (ie, the output of the executed commands) gets piped into the file, /tmp/pipe. However, the netcat command is also taking its input from /tmp/pipe. So when bash dumps its output into /tmp/pipe, that output just gets piped right into netcat, which gets sent back over the network to the client!

WARNING

As you may have noticed, there’s absolutely no security in this method, so be very careful using it. In my personal experience, netcat doesn’t accept more than one connection at a time, so once you connect, others should be unable to connect as well. However, that still doesn’t mean that you’re in the clear. TCP session hijacking, for example, would allow an attacker to take over and issue his/her own commands. If you want security, use SSH.


[1] On some systems such as Ubuntu, the -p flag may not be necessary. Thus, nc -l -p 1234 may be called instead by doing nc -l 1234.