SSH

From Helpful

(Redirected from SSH tunneling)
This article/section is a stub.
It is here because it was planned, created to drop some preliminary notes. Statements may be wrong, and the style and structure may suck. Feel free to add further notes or suggestions, rewrite sections or the whole into something understandable.
This article primarily contains notes
They may address very specific things, may be messy, and are not useful as introduction, or necessarily as reference. It may be something of a stub, in that notes are rarely particularly complete.


Contents

Some loose notes

An incomplete list of SSH servers and clients


Servers

Windows SFTP / SSH servers:


Notes:

SFTP is served by most SSH servers, and is mostly just file transfer built on the same base as Secure Shell, so inherits the connection methods from it.

Most *nix and various windows ssh/sftp servers will require some hook into system accounts, which makes for a bunch of setup, and may make it (sometimes a little too) easy to be lazy and use a setup with overly permissive access.

Clients

This article/section is a stub.
It is here because it was planned, created to drop some preliminary notes. Statements may be wrong, and the style and structure may suck. Feel free to add further notes or suggestions, rewrite sections or the whole into something understandable.

Linux SSH clients:

  • OpenSSH's ssh

Windows SSH clients:

  • PuTTY is rather common.
  • PortaPuTTY is a variation that allows you to store connection profiles and host keys alongside (...for USB sticks and such).


Windows SFTP/SCP clients:

Mac SFTP clients:

Unsorted

See other alternatives here, as well as this list.

Services

SSH seems designed to allow a connection to:

  • execute a single command. Stdin to the ssh command piped to stdin on the remote command, so you can e.g. transfer data using something like cat file | ssh remote.com 'cat - >copy_of_file', back up with tar, etc.
  • run an interactive shell
  • run an scp/sftp file server


Check whether you're being bruteforced

To see the brute force attempts, look at your sshd logs. Example summaries:

Amount per source IP:

cat /var/log/sshd/* | grep 'Invalid'|rev|cut -d ' ' -f 1 | rev | sort | uniq -c | sort -n

Amount per day:

cat /var/log/sshd/* | grep 'Invalid' | tr -s ' ' | cut -d ' ' -f 1-2 | sort | uniq -c

The usernames they try:

cat /var/log/sshd/* | grep 'Invalid'|rev|cut -d ' ' -f 3| rev | sort | uniq -c | sort -r -n | less


The source IPs of accepted logins, to see if there are any that may not be you:

egrep 'Accepted (keyboard|publi)[^\ ]+ for' /var/log/sshd/* | \
   sed -r 's/(.*from[\ ])([0-9.]+)([\ ]port.*)/\2'/ | sort | uniq -c | sort -n

The same IPs, without count, but with hostnames:

egrep 'Accepted (keyboard|publi)[^\ ]+ for' /var/log/sshd/* | \
   sed -r 's/(.*from[\ ])([0-9.]+)([\ ]port.*)/\2'/ | sort | uniq | xargs -n 1 host

Preventive policies

You can try a firewall with supports simple state, such as iptables with recent. Can be used to create an automatic blacklist for those that open many new connections to a port in a short period of time.


Policy lockdown:

Whitelist users with AllowUsers in sshd_config to avoid some random guest account you didn't create or really know to be a valid login - although system accounts tend to not have passwords or homedirs so tend not to be valid logins, but on servers it can be easy on admins to create accounts for specific people and/or services.


Whitelist hosts with a firewall. Some people do this, though I find it rather paranoid and way too impractical.


Don't allow root logins via SSH (often the default); use a regular account and sudo or sudo su when you want something superuser-done.


(Advanced): allow only keypair logins key-based logins.

Problems

Immediate session close

I saw:

session closed for user username

I was I was logging in successfully, but was immediately disconnected, and client verbosity has nothing interesting to say.

The problem was that the account I was logging into has /bin/false for a shell
(/bin/false was the default for newly adduser'd accounts)
, which ssh ran perfectly well but of course terminated immediately.



See also



SSH tunnels

This article/section is a stub.
It is here because it was planned, created to drop some preliminary notes. Statements may be wrong, and the style and structure may suck. Feel free to add further notes or suggestions, rewrite sections or the whole into something understandable.

In a sentence, the idea is to use a ssh client or server to start and/or receive connections that are forwarded (tunnelled) through the secure connection.

The Shortish Version

What

Besides the SSH shell, a SSH daemon usually provides other services.

As any other progam could, a SSH daemon can listen on a particular network port and make a connection elsewhere. This backs SSH's ability to make TCP connections and tunnel them through the secure connection you have made.

You can do this in both directions, though the most useful applications tend to come from sending conenctions from the client-side through to the SSH daemon.

(Some SSH daemons will additionally be able to act like a HTTP proxy based on this feature.)


Why

The upshot is that you get some VPN/port-forwarding-like features without having to set up VPN, and over a secure connection to boot. Assuming that traffic is only vunerable to sniffing on the client-server path this allows you to securely communicate insecure network protocols, require user authentication on (otherwise firewalled, private-IP-based) services, work around NAT on a per-port basis, and other things.

Note that you can often avoid make it keep the connection open without running a remote shell. This is probably not the most user-friendly solution for tunneling, but for quick, dirty, and/or personal ends it can be quite powerful.

(Note that, if client and server are unices, there may be another way to tunnel via SSH, namely via tun devices.)

Examples (command line)

Forward

Say you have a workstation and a (ssh) server, and decide that

  • on top of a SSH connection from the workstation to the SSH server
  • when someone connects to the workstation's port 8000
    • on the loopback interface (localhost) if only
    • ...or even 0.0.0.0 if you want other hosts to be able to use this too
  • this should be sent to the SSH server/daemon you have made the SSH connection to,
  • which should, on its end, start a (non-secured(!)) connection to some host:port combination
    • which could be localhost if you want some service on the SSH daemon's host,
    • ...or another host, say, google.com:80


From the workstation, and for the case of google.com:80, you would do:

ssh -L localhost:8000:google.com:80 server.example.com

At this point, running a browser and pointing it to the client's port 8000 (e.g. http://localhost:8000 on the client end itself) it would show google.


The syntax is:

ssh -L clientBindAddress:clientListenPort:toHost:toPort securehost
The client bind address defaults to
(the configured networks on)
all interfaces, so unless you want to avoid this, you can use the shorter form that omits this:
ssh -L clientListenPort:toHost:toPort securehost


A practical situation: A student server runs postgresql, which only accepts connections from localhost for security reasons. You are expected to use the text shell on that server, but you wish for a GUI on your workstation. You could use something like:

ssh -L 5432:localhost:5432 studentserver.example.com

To the GUI, localhost:5432 seems open and usable. If it connects to it, the sshd connects it to the database server.

As far as the GUI is concerned, it is connecting to something on localhost.

As far as the database server is concerned, the connection comes from localhost, which in this case is possible (only) because the sshd server runs on the same server as the database server.

Reverse

The same thing in the opposite direction is also possible - to let the sshd side of things listen to a port
(>1024 for non-root users)
and have connections to that port trigger a connection new connection from the client end - you.

I don't see as many uses for this.

I suppose it can be useful to eg. pretend you have a service on the server you connect to when it actually runs elsewhere. For example:

  ssh -R 3306:actualdbserver.example.com:3306 db.example.com

When someone connects to db.example.com:3306, it actually makes a connection to whatever client has currently set up a tunnel like this, to (what to it' is') actualdbserver.example.com:3306.

The point here could be to forward connections. This is however a rather heavyweight way to do port forwarding (if the encryption is not necessary, you'll want (D)NAT since it does the job more efficiently, and if you want it, you can set up a secure VPN) and limited in that the SSH daemon can only tunnel one connection on the listening side (again, a VPN is more useful)


The syntax (again with optional bind address):

ssh -R serverListenPort:toHost:toPort securehost


Proxy

To complete the list: A SSH server can often also imitate a SOCKS5 proxy server, which is most like the first example above: on the client side, a port is listened to, which just happens to connect to a proxy server on the server side -- that is, the sshd server acting as one. It can, for example, be used to let applications pretend they are on another network. The syntax:

  ssh -D localListenPort securehost

For example:

  ssh -D 1234 university.example.com


A browser set configured to use localhost as a proxy on that port will then be able to connect to anything, while the actual connections will come from the ssh server. I briefly used this this to go to some research pages that bother you less when you come from an educational IP range.


Examples (configuration)

This article/section is a stub.
It is here because it was planned, created to drop some preliminary notes. Statements may be wrong, and the style and structure may suck. Feel free to add further notes or suggestions, rewrite sections or the whole into something understandable.

Command line examples are nice to explore the options, but setting up tunnels up in configuration is easier in the end.


Basically, RemoteForward is equivalent to -R and LocalForward to -L (with a slightly different syntax in that there is only one colon).

It is relatively likely that you would want these in Host alias definitions, so that you can have these applies automatically to specific connections.


The Longer Explanation

Background

Usually, when you access a remote service, you connect simply to the relevant port.

That does, however, require you opening it up on the server (listening) side. That exposes the fact (or rather probability) that you are running some software, and that software to possible exploits.


SSH connection and a regular connection

This is of course not horrible, as a well set-up host has only the ports it needs to listen to open to the public internet, or possibly just a network. When you want to provide a service to only a few people, you would often use iptables tricks -- dropping traffic to a port unless it comes from known hosts. This has a few downsides - it focuses on hosts instead of users: log in from an unusual computer or dial in while travelling and you're locked out, and fixing that becomes constant management bother.

For simple services, the SSH tunnel can be a useful connection medium, and it is an easy way to wrap a secure connection around a nonsecured one.

Symbolically, you could represent a regular connection (and an unrelated, optional secure connection) like in the figure on the right.

The tunneling concept

Tunneling is a term indicating the wrapping of one protocol, service or connection in another. SSH tunneling means wrapping a TCP/IP connection, or UDP/IP route. Secure shell servers can actually provide a wide variety of secure applications: aside from secure shell also secure file transfer (sftp) and port forwarding (used here), but it has also been used to transparently load and save on another computer (see the fish/sftp kio_slave in KDE) and even used to mount a filesystem though it (see shfs.sourceforge.net

Secure tunneling adds some functionality more than regular tunnelling (other than being encrypted):

For one, if you're security-conscious, you probably have a firewall, in which you would rather open as few ports as necessary. My home workstation only has port 22 (SSH) open, which is generally pretty darn safe. Secure tunneling only needs this port 22 as all data goes through the SSH connection.

The other reason is inherent from the application of SSH - any tunneled access is subject to SSH's authentication, so you can restrict who gets actual access to the services behind your ports, and because SSH usually uses PAM for access, there's no extra setup other than (possibly) adding users to let people connect. (You could set up people with keypairs to make the process even less bothersome).

SSH Static port tunneling

Connection tunneled through a SSH connection (8000:localhost:80)

SSH tunneling works because SSH acts as a server and client on both sides of the secure connection. This means that with some extra SSH convention, a connection to the local SSH process can be forwarded to the server SSH process. In short, this is exactly what it is: An extra local port is allocated and logically linked with a connection to be made from the server SSH process.

In the figure on the right, the gray bars symbolize a firewall (on both sides), the area between them the internet on which only the ssh connection or port is apparent, the yellow bar the ssh connection (containing the tunnel), and the side areas the computers. The area between the firewall and the computer represent local connections. Note that SSH ports listen only on loopback, while its new connections can be meaning public IP, a private IP, or loopback.


The figure's situation describes one in which a web server shielded from public access is connected to through a tunnel. This sort of use suggests other uses: under most conditions, you can allow authorized users to bypass firewalling, and NAT's implicit firewalling. To give a more exact example, 'listen to local port 8000, and connect to 127.0.0.1 port 80' means:

  • Once the SSH connection is established, start listening to an extra port on the client side, here 8000.
  • When a program connects to this port (here 8000) the two SSH programs talk and the other end (the sshd server) connects to what to it is '127.0.0.1, port 80', and attaches it to the client's connection.

The result is that what to the client looks like local port 8000 is in fact a remote computer. It doesn't even have to be the sshd server itself; it can be anything reachable by that server, including things on private nets.


The above describes the 'local' variant; the same thing in the other direction ('remote ' variation) is also possible (listening on the server side, causing a connection to yourself), but would mostly be interesting to forward things like X -- and that's already a built in option anyway:)

Drawbacks

There are a few details (possible drawbacks) that should be mentioned:

For one, you cannot host on ports <1024 unless you are not an administrator. This is a problem when a program does not allow you to connect to a non-standard port. Similarly, when programs will want to make more connections on arbitrary or semi-standardized ports, this will generally not work
(some use a limited number of ports in a specific range, such as MSN, which uses 6891-6900, which you can all forward if you're so inclined)
.


SSH tunneling adds encryption, which can be an upside if you wanted to add it, but also slower, and unnecessary on things that are already secured. For shell access this isn't a noticable problem, but for eg. long-range VNC access you may notice a little extra lag.


The extra connection is not a SSH connection but a regular, unsecured one one. If the destination is not routed to loopback (via 127.0.0.1) and you connect elsewhere -- presumably to make the eventual end server think your IP is actually that of the mediating SSH server -- this connection is not secure.

Sorta-advanced features

SSH Dynamic port / SOCKS-style tunneling

SSH servers can usually act as secure proxies with a structure similar to how normal SSH tunneling works. On the client side, a single port is listened to on localhost, like with -L before. This is routed to the server, which imitates a SOCKS4 and/or SOCKS4 proxy, so can make connections as it wants to. The result is that you essentially have a secure proxy server running on localhost at a specified port, while it is actually elsewhere.

This again allows security centralisation, the earlier mentioned firewall bypassing, and VPN-like tricks besides. The handy thing is that you don't need to preconfigure ports now, but can let applications ask for connections themselves - as long as they support SOCKS proxies.

X11 forwarding

This is separate from the above, but worth knowing. Ssh clients such as the linux one have X forwarding (X as in the X windowing system) as an option, eg. in the form ssh -X otherhost.com (the linux ssh, -X enables, -x disables, the default is disabled). This is not only a port forwarding shortcut, but it also does things for you like setting DISPLAY - and I've seen it said that you shouldn't change this yourself on such a connection, or you may disable encryption or break the ability to actually tunnel X.

Also note that for this to work, the ssh server (and client) must have X support compiled in, and both sides must be configured to allow X11 forwarding. The easiest way to do this (Assuming unices) is to add

AllowX11Forwarding        yes

...to the server configuration, probably at /etc/ssh2/sshd_config (possibly /etc/ssh2/sshd2_config) (don't forget to restart sshd), and to add

ForwardX11     yes

to /etc/ssh2/ssh_config (possibly /etc/ssh2/ssh2_config) on the client side.

Windows clients (...when you have an X client for it, of course...) don't need this. Incidentally, for windows use, a guide for using PuTTY as a proxy sits here.



Keypair logins

The short description

Given a generated SSH key pair, you can the public key to an account on a SSH server to imply "trust those clients that handshake with the according private key of the pair."


You could carry the private key on a USB stick, or just stick it in your account (...if you trust the hosts's security).

Why and when this is interesting

That I've thought of, this is open to suggestions.

Replace interactive login

Particularly with an empty passphrase is it easy to create transparent no-interruption SSH actions (logins, SCP/SFTP transfers, and even tunnels) between accounts on trusted computers.

Passphraselessness is not suggested. To make you only type the passphrase once every so often, you can have it kept in memory with an agent.

Hinder brute forcing

If you already run a SSH server that is internet-reachable, take a look at your logs and you'll see plenty of lines like Invalid user [...] from [...]"; these are breakin attempts looking for very simple-'n'-dumb user/password combinations. Since the server has to respond to everone with at least some regularity, and because few people actively watch their sshd logs, this type of brute forcing isn't particularly hindered, and sometimes even works.

An alternative layer of protection against this are utilities like fail2ban, which searches your logs for repeats of bad things and firewalls the origin IPs.


SSH key logins can change this when you require logins to use keypairs. This means you could really only guess keyprases, but you would need the private key in the first place, and you can't just guess it. This makes casual scanning pointless.

Share accounts

One from practice.

A simple way to share an account is to share a password, but with SSH keypairs it is fairly simple just to make a specific account trust whomever it should.

This has a number of administration upsides:

  • You don't have to worry about the user/group permissions for all users that you allow login for, just for the accounts you allow login into.
  • you can avoid unix-specific group admin, which is a little peculiar
  • you can easily remove access for specific people (which is just annoying when sharing a password)


Minimal instructions

This example assumes a *nix server and client. The rsa type is a choice.


Create a keypair

ssh-keygen -f my_new_identity -t rsa

This generates my_new_identity.pub (the public key) and my_new_identity (the private key). For organization, you can move (or create) these to ~/.ssh/.


Add the public key to some host's trust

Copy the public key to an account on your server, then make an account trust it.

Trust is added (to *nix hosts) by adding the public key to its own line in an account's ~/.ssh/authorized_keys. The easiest way is probably to concatenate it, using:

cat ~/.ssh/my_new_identity.pub >> ~/.ssh/authorized_keys


When you want a remote server to trust a key, you can do this in one step using something like the following (you would of course still have to enter the password this time, since you're not actually using the keypair yet):

cat ~/.ssh/my_new_identity.pub | ssh user@server.example.com 'cat - >> ~/.ssh/authorized_keys'


Tell the client to use the private key when logging in

Copy the private key to your client
(securely, if you're doing this for security, and/or are paranoid)
, and tell your client to use it (when logging in to the server that trusts it).


When your client is a *nix shell, a simple option is to add a line to your ~/.ssh/config referencing your private key:

IdentityFile ~/.ssh/my_new_identity

(...which, mind you, tries it on all servers. You can let it be smarter about that, but this is simple)


Types of setup

As I understand, you have four possible setups for logins


interactive only (brute forceable)

As described. The default on most systems.


interactive + keypair

This brings you the ability to use keypair features, but you remain brute-forceable.


keypair only

This is secure, but too annoying for systems you may want to log in to on the fly, because your require every user to always carry their private key with them - and preferably never have it conveniently stored it on said multi-user system.

Having it passphraseless means a lot of implicit trust, to a sort of scary degree. Since you trust a specific user implicitly, based on their key and nothing else (no passphrase), you're immediately screwed if that key is copied. On public systems or on systems where you don't trust the security or don't trust root, this is a no-no.

That 'this' refers to putting the private key on there, as a client to something else. And note that you can make a keypair for every login, meaning the private key has to be nothing more than a token of 'free to log in to this specific other account,' which in turn need not be critical if it's a proxy account you'd sudo/su from.


Much more annoyance for little more security, and it's annoyance that will be hard to explain. It is probably actually easier to explain why you use a whitelisting firewall scheme for the ssh port.


This means you have to disable interactive logins per account if you want the brute force blocking. There seems to be no overriding administrative way of doing this, but presumaly you can set the account itself to be passwordless.(verify)


Implications, notes and thoughts

The security warnings above are for public, multi-user setups. If you are the only one on your server and your workstation, having them blindly trust each other can just be pretty darn useful.


The trust will work for one user at a time, because a key will be linked to a user.

I am currently making an account with the same name as my university login so that I can use scp very simply - that is, so that I don't have to specify a user.


You can create mutual trust (e.g. root on one system trusting root on another, but be careful - this means if one system is hacked, they're both hacked.

It is a very bad idea to allow root logins over SSH this way. It is probably a good idea to make an 'incoming' account.


Since all your clients have to store the private key and people may ever get to it, you should probably make a specific keypair for specific purposes instead of using one general identity keypair everywhere.

The "your key is unsafe if you're hacked" argument can be countered with that that's only directly true for escalations up to root. And of course it's only true for the client that has the public key stored; the server only has the public key, which is called that for a reason:)

For the same reasons you should probably not make it passphraseless.

How, in more detail

Making a new keypair

(This refers to the *nix commandline key generation utility. Other applications, such as putty's, work analogously once you know what you and it are actually doing.)


The basic generation command is
ssh-keygen -t rsa
.
(or -t dsa. Some versions will require you to specify a -t, others will default to SSH1-and-SSH2-compatible RSA.)

It will create two files:

  • the private key: id_rsa or id_dsa (or identity, for rsa1)
  • the public key: same filename with .pub appended
By default it puts these in your ~/.ssh/. If you don't want to overwrite your general identity you may have created before, give it a different base filename when it asks, or with the
-f
option.


Setting up the server account, and adding trust to it

If the account has never used ssh before, it doesn't have a .ssh directory yet. Either have it be created by using something ssh-related, or create it yourself (when you are logged in as this specific user):

mkdir ~/.ssh
chmod u=rwx,go-rwx ~/.ssh                   #u=rwx,go-rwx also known as 700


Then, to add the trust, edit your ~/.ssh/authorized_keys and add a public key (the contents of the .pub file you created earlier) per line, like:

ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3NTn2kSSati0EpM6/eyUpPF/andSoOn==


Note you can usually easily append the key from the shell using:

cat ~/.ssh/my_identity.pub >> ~/.ssh/authorized_keys

Or, to do add to another host in an account you can log into, in a single step:

cat ~/.ssh/my_identity.pub | ssh you@example.com "cat - >> ~/.ssh/authorized_keys"

Just be sure to use >> (append), not a > (overwrite).


If authorized_keys didn't exist yet, you may want to check its permissions, specifically that it isn't world-writable. World-readable doesn't matter hugely since public keys are, well, public anyway, but you may as well not:

touch ~/.ssh/authorized_keys
chmod u=rw,go-rwx ~/.ssh/authorized_keys    #u=rw,go-rwx also known as 600


Making the client use the private key

If you indeed use multiple identities, you should manage the configuration to use the right one for the right host.


command line ssh

Assuming you don't want to manuall specify the right identity all the time with ssh -i, you would change your ~/.ssh/config

You can either add all your identity files, which means they will be tried in sequence, with lines like:

IdentityFile ~/.ssh/webhost_rsaidentity
IdentityFile ~/.ssh/groupware_rsaidentity
IdentityFile ~/.ssh/uniaccounts_rsaidentity


This is the lazy way; it'll try each key on each host it connects to. You can specify the right one for each host by using the Host keyword.

This is actually part of a wider concept in that Each Host entry refers to configuration of treatment for that host or a set of hosts, which can also e.g. be used to create aliases.

For example, the following sets ~/.ssh/home_rsaidentity to be used whenever we connect to home.example.com, then defines two aliases (to the same host, in this case) that imply certain settings:

#global details first (effectively   Host *)
Host         home.example.com
IdentityFile ~/.ssh/home_rsaidentity
#Other Host+IdentityFile can be added.
# Alias definitions 
Host         home
HostName     home.example.com
User         me
ForwardX11   no

Host         homex
HostName     home.example.com
User         me
ForwardX11   yes 

See also the ssh_config man page.


PuTTY

Each connection template can have a reference to a private key (file), under Connection → SSH → Auth.


PuTTY wants key in the format specified by RFC 4716, which one of various formats. If you created the keypair using OpenSSH, you need to convert it. One way of doing so:

  • downloading PuTTYgen [1]
  • load in a key
    (note it's a little stupid, looking only for its own .ppk format; you need to change that to select *.* instead)
  • save it (private key is the one you'll want for remote login)


Remembering keys: agents

SSH agents keep private keys in memory, meaning you can get automatic log in.

ssh-agent works by being the parent of processes that use it so that only the child process can get and use the key. It's fairly common to have it wrapped around interactive shells, so that any aware client (ssh, scp, etc) will notice the environment variables that have been set, and ask ssh-agent for keys when it needs them. You add keys to this agent with ssh-add.

This has a few upsides, like:

  • private keys may come from the disk or network, but their passphrase-decoded form is only ever stored in memory, even on flat clients
  • gives you 'remember passphrase for some set time' feature

See ssh-agent man page and such for details.


Pageant is PuTTY/Windows specific. It's similar, but instead is a background process that stores keys, which PuTTY (Other things as well?(verify)) will notice and use. (What about access control?(verify))

See pageant documentation for details.

See also