SSH escape sequences

January 6, 2019

When you have an active ssh session, you can use ssh escape sequences to modify the session at runtime.

Activating a sequence requires that the last key you entered was <enter>, followed by ~ and lastly the sequence key. If you are unsure which key is for which sequence, use ? for the sequence key (e.g. <enter>~?). This will print out the help menu.

Supported escape sequences:
 ~.   - terminate connection (and any multiplexed sessions)
 ~B   - send a BREAK to the remote system
 ~C   - open a command line
 ~R   - request rekey
 ~V/v - decrease/increase verbosity (LogLevel)
 ~^Z  - suspend ssh
 ~#   - list forwarded connections
 ~&   - background ssh (when waiting for connections to terminate)
 ~?   - this message
 ~~   - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)

Some example use-cases

Terminating a session

$ ssh my-server

# running inside an ssh session
> ./do-stuff

# let's assume that at this point the session hangs and we can either:
# - wait for a timeout
# - close the terminal on our side
# - or better yet, terminate the ssh session using escape sequences
# note the enter we do on the first line, to make sure the sequence will be recognized
> ~.
Connection to closed.

Port forwarding

For a quick reminder on the syntax for each specific forwarding type, you can always enter the shell (with <enter>~C) and type ? to get a list of available options.

ssh> ?
      -L[bind_address:]port:host:hostport    Request local forward
      -R[bind_address:]port:host:hostport    Request remote forward
      -D[bind_address:]port                  Request dynamic forward
      -KL[bind_address:]port                 Cancel local forward
      -KR[bind_address:]port                 Cancel remote forward
      -KD[bind_address:]port                 Cancel dynamic forward

It is important to note that forwarding can be between ports or UNIX sockets, or any combination of the two.

Forwarding local ports

Local forwarding means you want to open a port on your machine, which is tunneled to a remote resource. It is configured using the following parameters:

  ╚═╦═══════════════╝ ╚═╦═════════╝
    ȯ your machine     ȯ ssh server

As we can see, we can omit bind_address, which will default to any interface. For the purposes of this post, we will omit this field.

Access resources running on ssh server

-L 8000:localhost:5432

If we have a Postgres instance running on our ssh server on its default port 5432, and we want to access it on our machine, as if it is running locally, we would use -L 8000:localhost:5432. This would open a port (8000) on our machine, which when accessed would tunnel to the ssh server, where (on localhost) it would forward to Postgres (5432). Postgres in this sense is localhost, from the perspective of the ssh server.

Access resources running on another machine to which ssh server has network access

-L 8000:postgres-server:5432

Following the previous example, if Postgres was on another machine (to which ssh server has network access), we would use -L 8000:postgres-server:5432, where postgres-server is the hostname/IP of the machine running Postgres.

Access arbitrary resources on the internet


If we would like to access any resource on the internet and hide behind our ssh server’s IP, we could use -L, and consume this resource as if is running localhost on our machine on port 8000. There is a much better way to do this, by using dynamic forwarding, explained later in this post.

Forwarding remote ports

Remote forwarding means you want to open a port on remote machine, which is tunneled to your local machine.

  ╚═╦═══════════════╝ ╚═╦═════════╝
    ȯ ssh server       ȯ your machine

There is a setting in /etc/ssh/sshd_config called GatewayPorts that will control who has access to the newly opened port. If this setting is set to no, then only local connections (from the standpoint of the server) can be made. Setting it to yes will allow connections from all reachable hosts. It can also be set to clientspecified, which gives us some control on exactly who can access the resource.

If we have GatewayPorts set to clientspecified, then we can configure remote forwarding this way:

-R my-server

We are allowing to connect to port 2222 on my-server which will be forwarded to port 22 on client (our) machine.

Dynamic port forwarding

Dynamic port forwarding will essentially create a SOCKS5 proxy on the port you specify. With this, you can for instance redirect all your browser traffic through the proxy, allowing you to browse the web through the eyes of your SSH server. Any software that has the ability to route traffic through a SOCKS5 proxy will be able to take advantage of this.

-D 4321

This will open a SOCKS5 proxy on port 4321 on your local machine.

Firefox -> FoxyProxy -> Burp -> SSH SOCKS5 -> Internet

Let’s pretend you can only access certain resources from your SSH server, but you would still like to put BurpSuite between your browser and the resource you are trying to access. To get this working we will need Firefox, FoxyProxy plugin for Firefox and BurpSuite.

Configure FoxyProxy to connect to BurpSuite (by default Burp is listening on 8080). Then configure BurpSuite to connect to SOCKS5 by going to User Options -> Connections under SOCKS5 Proxy.