Join 3,497 readers in helping fund MetaFilter (Hide)


SSH with telnet -e as a ForceCommand: secure?
March 21, 2012 7:40 AM   Subscribe

I want a secure way for people to log into a server on my Windows machine from the internet. I have an idea; is it good?

I'd like to set up a TradeWars 2002 server for strangers (in particular, Mefites - that is, people I don't know personally) to play on. The game server is Windows only, and runs a telnet server that people log into.

On my home network, I have exactly two ports forwarded on my router's firewall - one for VPN and one for SSH. These ports forward to a little ARM server running debian, with updated security patches, etc. Both ports are nonstandard port numbers, and SSH logins are restricted to public-key only. I also have a Windows 7 Home-Premium machine, on which I'd like to run the server. But I don't want to open any ports directly to the Windows machine.

My idea is this: create a special user on the Linux machine. Create a different SSH private key for every player (so I can tell who's logging in). In my sshd_config on the server, I turn off port-forwarding, etc (anything nonessential) and set ForceCommand as

telnet -e '' host port

so that shell access is disabled for the user. Also, I set the users shell to rbash, just in case. The user will have no password set, so login via anything other than the keys will be impossible. The ForceCommand, of course, will connect to the Windows machine on the proper port. (I could even chroot the user, if I wanted, as long as telnet had everything it needed to run in the chroot)

So from the players' perspective, they are just logging into the server with via publickey, and immediately getting the game (using PuTTY, or whatever). Is this secure? Are there any better ideas out there?
posted by Philosopher Dirtbike to Computers & Internet (13 answers total) 1 user marked this as a favorite
 
It sounds like you've covered it pretty well. Ensure you're using an up-to-date version of SSHD, of course. If your friends are coming from known IP addresses you could further restrict it at the iptables layer to only permit their source addresses.

I usually add some kind of rate limiting or blacklisting to drop brute-force attempts. Even though they wouldn't get anywhere since you're using public-key only, it's annoying to read through attempts in your logs.
posted by odinsdream at 8:13 AM on March 21, 2012


odinsdream: I also use fail2ban.
posted by Philosopher Dirtbike at 8:23 AM on March 21, 2012


You can simplify things a bit by just setting your dedicated user's shell to telnet -e '' HOST PORT and using sudo -u when you actually need a local shell for it.

On the ssh server I use to implement secure tunnels for VNC on my customers' machines, the support account's shell is cat. Works fine, and AFAIK cat has no sploits.
posted by flabdablet at 8:27 AM on March 21, 2012


Having just tried that, I find that the shell name you put in /etc/passwd can't include parameters. But if you create /usr/local/bin/tradewars containing just

#!/bin/sh
exec /usr/bin/telnet -e '' HOST PORT

and then make it executable, you can indeed use /usr/local/bin/tradewars as the shell for your tradewars user, and anybody who logs in as that user by any means - ssh or otherwise - will see your TradeWars server's telnet instead of a command shell.

You wouldn't need to use ForceCommand to stop ssh passing -c COMMAND arguments to the tradewars user's shell, because /usr/local/bin/tradewars completely ignores all its arguments anyway.
posted by flabdablet at 9:00 AM on March 21, 2012


flabdablet, would that be more secure than my setup, same security but simpler, or less secure?
posted by Philosopher Dirtbike at 9:18 AM on March 21, 2012


Bad idea. The user can ^] and type ! to spawn a subshell.
posted by TheNewWazoo at 12:29 PM on March 21, 2012


Oh doh, totally missed -e.
posted by TheNewWazoo at 12:29 PM on March 21, 2012


I don't think there would be any exploitability difference from the user's point of view. It just guards you against mistakes next time you're fiddling with (or forgetting to fiddle with) sshd_config.

It also means that if you ever need to do something more complicated than simply opening a telnet session in order to launch your TradeWars server, like logging or imposing usage caps or availability times or whatever, then you have an easily editable and commentable script file to put all that stuff in rather than needing to wedge it all into a ForceCommand argument in a sshd config file.

Bad idea. The user can ^] and type ! to spawn a subshell.

Even without -e '' (or the equivalent -E) the telnet that came with my Debian Wheezy installation doesn't recognize the ! command, so I wasn't able to test whether having the login shell set to /usr/local/bin/nonstandard changes that command's behavior. I suspect it would, but I also suspect that altering the SHELL environment variable with environ define SHELL /path/to/arbitrary/executable would let you make ! do anything you liked. I personally would not rely on telnet having been built without support for it and would indeed use -e or -E to suppress the escape character altogether.
posted by flabdablet at 5:34 PM on March 21, 2012


Another thing: if you add some stuff to /usr/local/bin/tradewars to parse for and process a -c option, this would allow your users to pass it an arbitrary string by invoking ssh with a command argument. Exactly what you would do with those strings is totally up to you (extract TradeWars login credentials, perhaps?)
posted by flabdablet at 5:49 PM on March 21, 2012


Another thing: if you add some stuff to /usr/local/bin/tradewars to parse for and process a -c option, this would allow your users to pass it an arbitrary string by invoking ssh with a command argument. Exactly what you would do with those strings is totally up to you (extract TradeWars login credentials, perhaps?)

That's an interesting idea, I'll have to think about that.
posted by Philosopher Dirtbike at 6:08 AM on March 22, 2012


One interesting way to use it would be to combine it with command= directives inside authorized_keys. That way, the value of the next argument supplied to /usr/local/bin/tradewars after -c could be tied to the public key used to log in via ssh (if you use a command= directive, ssh will ignore the command string supplied by the user).

You're handing out unique ssh identities to your users anyway; tying the login credentials for your TradeWars server to these inside your ssh gateway instead of allowing users to supply those after connection means that you maintain solid control of those identities all the way into the game server.

The only way your users would be able to spoof each other is by acquiring copies of each other's id_rsa files. You can hand these out without passphrases and encourage your users to add their own using ssh-keygen -p which completely relieves you of password maintenance at your end.
posted by flabdablet at 8:13 AM on March 22, 2012


Looks like you have things up and running but you might check out using `nc` instead of `telnet` in authorized_keys or /usr/local/bin/tradewars script. Depends on whether telnet is doing any line/character conversion work.

# .ssh/authorized_keys
command="/bin/nc localhost smtp" ssh-rsa AAAAB3NzaC...

#!/bin/sh
# /usr/local/bin/tradewars
exec /bin/nc $HOST $PORT
It's more totally transparent compared to telnet.
posted by zengargoyle at 2:35 AM on April 12, 2012


It also does signal processing differently. Try both and see which works better for you.

One thing that telnet -E handles differently from nc is signal processing; send SIGINT to nc and it will quit, while doing the same thing with telnet sends a bunch of gibberish characters to the other end; I presume a telnet server would interpret these and generate a server-side SIGINT.
posted by flabdablet at 5:34 AM on April 12, 2012


« Older My department chair thinks I d...   |  Help me negotiate a better sal... Newer »
This thread is closed to new comments.