
PoC y análisis para Kibana Prototype Pollution RCE (CVE-2019-7609).
Las versiones de Kibana anteriores a 5.6.15 y 6.6.1 contienen una falla de ejecución de código arbitrario en el visualizador Timelion. Un atacante con acceso a la aplicación Timelion podría enviar una solicitud que intente ejecutar código JavaScript. Esto podría permitir que un atacante ejecute comandos arbitrarios con los permisos del proceso de Kibana en el sistema host.
CVSS:

Blog: https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/
Payload: https://github.com/mpgn/CVE-2019-7609
Configuración:
Uso:
Después de analizar la hoja:

Después del preprocesamiento de la hoja, tenemos un objeto queries:

Luego, recorremos el array queries (que se convierte en un array mediante el método values) y pasamos a invoke el query.function y query.arguments para invocar la función.
En la función invoke, primero obtenemos la definición de la función según su nombre (query.function):

Esta definición de función incluye tres tipos de función: fn, originalFn y timelionFn. Luego, recorre los args (que son query.arguments) y resuelve los argumentos:

En este caso, el argumento en args es un objeto con tipo 'literal', por lo que simplemente devuelve el valor literal:

En realidad, el valor está envuelto en una promesa.

El argumento indexado es un argumento con un objeto byName que tiene un array q en su interior:

Después, la función invoke llamará a functionDef.fn, que es una función de la clase Timelion, con todos los argumentos indexados:

La función fn llamará a originalFn, que proviene de config.fn, donde config es tlConfig. Y esa función es fn de la clase Datasource extends Timelion:

Como podemos ver, llama a otro originalFn llamado esFn, que devuelve un objeto seriesList:

Esa función se usa para "extraer datos de una instancia de Elasticsearch" llamando a la función callWithRequest.
El seriesList se ve así en Datasource.fn:

Y se ve así en Timelion.fn:

Después del preprocesamiento de la hoja, la lista de cadenas es:

Y el código llamará a resolveChainList para resolver la lista de cadenas:

Cada cadena se asignará a una Promise que devuelve una función que invoke con 'first' como fnName y la propia cadena como args.
La definición de la función se obtiene nuevamente por el nombre:

Esta vez, resolveArguments recibe args como un array y llama a resolveArguments recursivamente para resolver cada argumento. Pero solo tenemos un argumento con índice 0. Y ese argumento es un objeto con type == chain.
Entonces, en el caso del switch, llamará a la función invokeChain y le pasará el objeto de la cadena:

Dentro de la cadena de invocación, se aplicará shift al array chain. La función shift devolverá el elemento eliminado, por lo que link será el objeto es:

Debido a que el tipo de es no es 'chain' (es 'function') y !result es verdadero, el código llama a la función invoke con 'first' como fnName y el objeto es como args:
Esta vez, el procedimiento es el mismo que el anterior, así que pasamos a la llamada de invokeChain con link como objeto props:

De nuevo, el código llama a la función invoke con 'first' como fnName y el objeto props como args:

El originalFn de props ahora es firstFn en lugar de fn como es, y solo acepta un argumento:

Esa función original eventualmente llamará a la vulnerable función unflatten. En realidad, primero llamará al fn de Timelion. Luego, fn llamará al originalFn de props:

El firstFn de props omitirá las propiedades inputSeries y global en el objeto byName de args:

Por lo tanto, el data pasado a unflatten será:
{
label.__proto__.env.AAA: "a"
}
Prueba:

Usa props(label.__proto__.env.AAA="a"). El data se verá así:
