Summary
By using path hijacking and modification on Unix-like machines, we can achieve pseudo-keylogging functionality by prioritizing malicious middleware binaries to record and transfer standard input/output streams.
Github: https://github.com/djhohnstein/cliProxy
Introduction
Historically speaking, keylogging for Unix-like systems has been a pain point. You compromise a jump box, gain access to some sensitive private keys, but they’re all password protected. You gain access to a developer’s MacBook workstation, see them reading secrets from a server like Hashicorp’s Vault from the command line, but realize you need a user’s plaintext password to pull those secrets. The initial instinct is to log the keystrokes of the user(s) on the compromised machines; however, in the first example, no keyboard device is connected, and to keylog in the latter would require a popup with authorization from the user to allow access to the keyboard.
This was the scenario I was in. I had access to a user’s MacBook, but was unable to keylog their activities stealthily. When I was thinking about this problem, I realized that keylogging was actually overly broad for my specific use-case. Keylogging would help gain access to plaintext credentials when the user interfaces with an application through a browser or otherwise, but if we’re looking to log, say, an SSH session, I don’t necessarily need access to the keyboard device. If I were to restate the problem, what I really want is the full standard input, output, and error streams of the applications the user is interfacing with.
Environmental PATH Variable
If you’re coming from a Windows background, you probably understand the PATH environment variable to be sensitive. Write-access to one or more paths in the variable can lead to opportunities for persistence, DLL hijacking, privilege escalation and otherwise. The PATH variable is also responsible for search order of applications, such that if the binary isn’t found in the first path, the next is searched, and so on until all paths are exhausted. In Unix, many of these same exploitation techniques can be applied, but specifically we’ll focus on the search order of applications.
The .rc File
When a shell is opened in a terminal, a hidden file is sourced on startup before dropping you into an interactive shell (sh uses .rc , bash uses .bashrc , zsh uses .zshrc , etc.). These files are responsible for a myriad of things, such as instantiating environment variables, creating command aliases, and more. It’s not abnormal to see these files modify a user’s PATH to include new directories for newly installed applications so they’re easily accessible from the command line. It’ll take one of two forms in the shell-specific .rc file:
- export PATH=$PATH:/some/new/path
- export PATH=/some/new/path:$PATH
By prepending a path to the PATH variable you’ll change the default search order of shell session. Say your PATH variable was /bin:/usr/sbin , and you prepend a new path such that your PATH is set to/some/new/path:/bin:/usr/sbin after sourcing your .rc file. Now, when you type ssh , the session will first search /some/new/path for the SSH binary, then /bin , where it’ll find the application and launch it.
Armed with this search order knowledge, we can exploit this in one of two ways:
- Place a binary of similar name in a writable path that’ll be searched before the genuine binary.
- Modify the .rc file to prepend a writable directory to the PATH variable and do the previous.
Application Proxy Middleware
With this PATH write primitive, the next natural question is “what do I put there?” A guiding principal I use in a lot of red teaming and tool development is that the deceit must be absolute, be it in C2 communication channels, parent/child process relationships, and in this case, malicious terminal applications. Since we’re hijacking familiar binaries the user launches from the command line, there’s a degree of scrutiny that’ll be applied to our application if it doesn’t function as the hijacked binary would.
Traditionally, attackers have downloaded the target binary’s source, backdoored the application, and recompiled it to get sensitive information from a user’s session. This process is slow, arduous, and not always possible depending on the type of application you’re attempting to hijack. We need a lighter weight, more transferrable way of arbitrary binary hijacking so that we don’t interfere with the user’s regular workflow. This is where the standard I/O streams come into play.
If our hijack binary is called first, we can call the absolute path of the intended binary and spawn a child process. This child process’s standard in can be piped from the parent process’s standard in, and that child’s standard output and error can be piped out to its parent’s standard output streams, such that there should be no visible difference in functionality between the hijack and hijacked binary. Since we sit in the middle of these output streams between the user and the child process, we can in turn log these streams for manual review later. This can be better illustrated by the following diagram:
Thus, we can create a lightweight middleware binary for each application we wish to hijack so long as we know the true path of that application on disk. Moreover, once the user starts the hijack binary, you could send input to the genuine application after a session has been established without communicating the output of that command (think launching a reverse shell on the target server the user is attempting to SSH to). This is left as an exercise to the reader.
The following screenshots show the installation of the middleware in action. We first note the path variable that’s set in the .bashrc file, drop our proxy SSH binary to the user-controlled path, and then launch the fake SSH binary. After executing, we then review the log files generated by the proxy application.
One Step Further: Logon Shells
If you were to be elevated in on a Unix server, you can take this one step further by changing the user’s logon shell. Instead of hijacking individual commands like ssh, aws, etc., we can hijack the entire logon shell they use to interface with the terminal. You can do this by modifying the /etc/passwd file manually, or by using the chsh command as shown below:
This can be particularly useful in AWS environments where you have access as the ec2-user. This user is usually added to the sudoers group by default, and as such could modify any user’s shell on that instance. Moreover, you could still use the path-relative hijacking technique shown previously using a shell application, as many binaries still call the path-relative shell as opposed to the absolute path of the shell (e.g., /bin/bash). An example of this is the source command, which calls the path-relative shell instead of the absolute path of the shell.
Conclusion
As red teamers, we get to practice the art of problem solving every day. The core problem set is often the same (e.g., “how do I get domain admin,”), but the ways in which we solve that problem are solely dependent on how you phrase the problem. By constantly rephrasing and restructuring your problem statement, the solution can often jump out and become apparent. That’s exactly what happened in this instance of attempting to log keystrokes on Linux and Mac machines. Keylogging was an overly broad problem, so we refined it. It’s less “how do I log keystrokes” and more “how do I get this application’s standard input?” The more precise we are with our problem statement, the easier it is to find a solution. Finding new bypasses and techniques don’t always need to be discovered. Sometimes all you need is to combine bits of disparate knowledge in a way you haven’t done before.
Github: https://github.com/djhohnstein/cliProxy
Man in the Terminal was originally published in Posts By SpecterOps Team Members on Medium, where people are continuing the conversation by highlighting and responding to this story.
The post Man in the Terminal appeared first on Malware Devil.
https://malwaredevil.com/2021/04/05/man-in-the-terminal/?utm_source=rss&utm_medium=rss&utm_campaign=man-in-the-terminal
No comments:
Post a Comment