Faking a telnet server with netcat.

25 May 2020

Let's say that you need to be able to access a server somewhere on your network.  This is a pretty common thing to do if you've got a fair amount of infrastructure at home.  But let's say that your computer, for whatever reason, doesn't have the horsepower to run SSH because the crypto used requires math that older systems can't carry out in anything like reasonable time.  This is a not uncommon situation for retrocomputing enthusiasts.  In the days before SSH we used telnet for this, but pretty much the entire Net doesn't anymore because the traffic wasn't encrypted, so anyone with a mind to eavesdrop could grab your login credentials to abuse later.  However, on a home network behind a firewall between systems you own it doesn't hurt to use once in a while.  Good luck finding systems that still package in.telnetd, though.  However, you can fake it with a tool called netcat.

First, you need a FIFO (first in, first out) that, as far as a Linux machine is concerned is a file that multiple processes can open to read and write.  Whenever something writes into a FIFO, everything reading from it gets whatever came in the other end.  As passing data goes the question is "how hard do you really need it to be," and FIFOs answer the question with "Not hard."  Linux boxen come with a tool called mkfifo that create them; uncreating them is as simple as deleting them like any other file.  This is the first step toward faking a telnet server:

{16:43:59 @ Tue May 19}
[drwho @ leandra:(3) ~]$ mkfifo /tmp/not-telnet

Now you need something to listen on the network for connections.  If you have nmap installed on your Linux box it comes with a tool called ncat, which is sort of like a universal network tool.  You can use it as a network client, a network server, a network tunnel... if you need to get data onto or off a network in a nonspecific way without writing any custom code, this is your tool.  I have OpenBSD's version of netcat installed on Leandra for this sort of thing.  The third thing we need is a user shell, which you can't really have a Linux box without so the presence of one is a given.

Before I go into what to do, I want to talk about how and why.

What we're going to do is take whatever comes into the FIFO and run it through a user shell.  The user shell (bash in this case) will be a login shell so it has a full user environment.  It'll also be explicitly run as an interactive shell, to hopefully eliminate any weirdness with missing or mis-set environment variables.  That shell's standard output and standard error channels will be glued together and run through a copy of netcat listening on the local network.  Whatever the netcat server receives off the network gets dumped into FIFO I talked about in the first step.  In this way, input from the user goes into a shell, and the output goes back to the user so they can see what they're doing.

Here's the command:

{17:06:26 @ Tue May 19}
[drwho @ leandra:(3) ~]$ cat /tmp/not-telnet | /bin/bash --login -i 2>&1 |
    nc -l 31337 > /tmp/not-telnet

Now you can telnet to port 31337.

[drwho @ windbringer ~] () $ telnet leandra 31337
Trying 192.168.0.163...
Connected to leandra.
Escape character is '^]'.

{16:12:30 @ Wed May 20}
[drwho @ leandra:(3) ~]$ pwd
pwd
/home/drwho
{16:13:17 @ Wed May 20}
[drwho @ leandra:(3) ~]$ who
who
drwho    pts/7        2020-05-02 16:33 (192.168.0.113:S.7)
drwho    pts/6        2020-05-02 16:33 (192.168.0.113:S.6)
drwho    pts/5        2020-05-02 16:33 (192.168.0.113:S.5)
drwho    pts/4        2020-05-02 16:33 (192.168.0.113:S.4)
drwho    pts/3        2020-05-02 16:33 (192.168.0.113:S.3)
drwho    pts/2        2020-05-02 16:33 (192.168.0.113:S.2)
drwho    pts/1        2020-05-02 16:33 (192.168.0.113:S.1)
drwho    pts/0        2020-05-02 16:33 (192.168.0.113:S.0)
{16:13:41 @ Wed May 20}
[drwho @ leandra:(3) ~]$ exit    
exit
logout

Connection closed by foreign host.

Looking over at the other system, netcat helpfully terminates itself when you log out.

{16:12:20 @ Wed May 20}
[drwho @ leandra:(3) ~]$ mkfifo /tmp/not-telnet
{16:12:26 @ Wed May 20}
[drwho @ leandra:(3) ~]$ cat /tmp/not-telnet | /bin/bash --login -i 2>&1 |
    nc -l 31337 > /tmp/not-telnet 
{16:14:08 @ Wed May 20}
[drwho @ leandra:(3) ~]$

Then delete the FIFO to clean up after ourselves and we're done.

{16:17:47 @ Wed May 20}
[drwho @ leandra:(3) ~]$ rm /tmp/not-telnet