If you’ve ever used SSH keys to manage multiple machines, then chances are you’ve used SSH-agent. This tool is designed to keep a SSH key in memory so that the user doesn’t have to type their passphrase in every time. However, this can create some security risk. A user running as root may have the ability to pull the decrypted SSH key from memory and reconstruct it.
Due to needing root access, this attack may seem useless. For example, an attacker may be able to install a keylogger and use that to obtain the passphrase for the SSH key. However, this causes the attacker to have to wait for the target to type in their passphrase. This might be hours, days, or weeks, depending on how often the target logs out. This is why obtaining the SSH key from memory is vital to pivoting to other machines in a speedy fashion.
A common method of using SSH-agent is running “SSH-agent bash” and then “SSH-add” to add the key to the agent. Once added, the key will stay in the SSH-agent’s stack until the process ends, another key is added, or the user uses the -d or -D option with SSH-add. Most people will run this once and then forget about it until they need to reboot.
Pulling a SSH Key From Memory
There are a few ways to create a copy of the SSH-agents memory. The easiest way is through the use of gdb. Gdb uses the ptrace call to attach to the SSH-agent. This provides gdb with the privileges necessary to create a memory dump of the running process. The grabagentmem.sh script provides a way of automating the dumping of this memory. By default, when it runs it will create a memory dump of the stack for each SSH-agent process. These files are named SSHagent-PID.stack.
root@test:/tmp# grabagentmem.sh Created /tmp/SSHagent-17019.stack
If gdb is not available on the system, then it might be feasible to take a memory dump of the entire machine and use volatility to extract the stack of the SSH-agent processes. However, this process is currently out of the scope for this document.
Parsing SSH Keys From the Memory Dump
Once we have a copy of the stack it becomes possible to extract the key from this file. However, the key is kept in the stack in a different format then the one that was generated by SSH-keygen. This is where the parse_mem.py script comes in handy. This script requires the installation of the pyasn1 python module. Once that is installed the script can be run against the memory file. If that memory file contains a valid RSA SSH key then it will save it to disk. Future versions of the tool may support additional key formats, such as DSA, ECDSA, ED25519, and RSA1.
root@test:/tmp# parse_mem.py /tmp/SSHagent-17019.stack /tmp/key Found rsa key Creating rsa key: /tmp/key.rsa
This key.rsa file can then be used as an argument to the -i switch in SSH. This will act like the original user’s key, only without requiring a pass phrase to unlock it.
Obtaining valid, usable SSH keys can help a penetration tester gain further access into a client’s network. It’s common for keys to be used on both the user’s account, as well as the root account on servers. It is also possible that a server is configured to only allow key access. Having access to an unencrypted key can make moving around the environment much easier.