Skip to content

Commit

Permalink
security: fix CVE-2024-47070 (cherry-pick #11536) (#11540)
Browse files Browse the repository at this point in the history
security: fix CVE-2024-47070 (#11536)

* security: fix CVE-2024-47070



* Update website/docs/security/CVE-2024-47070.md




---------

Signed-off-by: Jens Langhammer <[email protected]>
Signed-off-by: Jens L. <[email protected]>
Co-authored-by: Jens L. <[email protected]>
Co-authored-by: Tana M Berry <[email protected]>
  • Loading branch information
3 people authored Sep 27, 2024
1 parent 22e586b commit 78f7b04
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 7 deletions.
16 changes: 16 additions & 0 deletions authentik/lib/tests/test_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ def test_forward_for(self):
request = self.factory.get("/", HTTP_X_FORWARDED_FOR="127.0.0.2")
self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.2")

def test_forward_for_invalid(self):
"""Test invalid forward for"""
request = self.factory.get("/", HTTP_X_FORWARDED_FOR="foobar")
self.assertEqual(ClientIPMiddleware.get_client_ip(request), ClientIPMiddleware.default_ip)

def test_fake_outpost(self):
"""Test faked IP which is overridden by an outpost"""
token = Token.objects.create(
Expand All @@ -53,6 +58,17 @@ def test_fake_outpost(self):
},
)
self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1")
# Invalid, not a real IP
self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT
self.user.save()
request = self.factory.get(
"/",
**{
ClientIPMiddleware.outpost_remote_ip_header: "foobar",
ClientIPMiddleware.outpost_token_header: token.key,
},
)
self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1")
# Valid
self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT
self.user.save()
Expand Down
23 changes: 17 additions & 6 deletions authentik/root/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from collections.abc import Callable
from hashlib import sha512
from ipaddress import ip_address
from time import perf_counter, time
from typing import Any

Expand Down Expand Up @@ -174,6 +175,7 @@ class ClientIPMiddleware:

def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
self.get_response = get_response
self.logger = get_logger().bind()

def _get_client_ip_from_meta(self, meta: dict[str, Any]) -> str:
"""Attempt to get the client's IP by checking common HTTP Headers.
Expand All @@ -185,11 +187,16 @@ def _get_client_ip_from_meta(self, meta: dict[str, Any]) -> str:
"HTTP_X_FORWARDED_FOR",
"REMOTE_ADDR",
)
for _header in headers:
if _header in meta:
ips: list[str] = meta.get(_header).split(",")
return ips[0].strip()
return self.default_ip
try:
for _header in headers:
if _header in meta:
ips: list[str] = meta.get(_header).split(",")
# Ensure the IP parses as a valid IP
return str(ip_address(ips[0].strip()))
return self.default_ip
except ValueError as exc:
self.logger.debug("Invalid remote IP", exc=exc)
return self.default_ip

# FIXME: this should probably not be in `root` but rather in a middleware in `outposts`
# but for now it's fine
Expand Down Expand Up @@ -228,7 +235,11 @@ def _get_outpost_override_ip(self, request: HttpRequest) -> str | None:
Hub.current.scope.set_user(user)
# Set the outpost service account on the request
setattr(request, self.request_attr_outpost_user, user)
return delegated_ip
try:
return str(ip_address(delegated_ip))
except ValueError as exc:
self.logger.debug("Invalid remote IP from Outpost", exc=exc)
return None

def _get_client_ip(self, request: HttpRequest | None) -> str:
"""Attempt to get the client's IP by checking common HTTP Headers.
Expand Down
2 changes: 2 additions & 0 deletions blueprints/default/flow-default-authentication-flow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,5 @@ entries:
order: 10
target: !KeyOf default-authentication-flow-password-binding
policy: !KeyOf default-authentication-flow-password-optional
attrs:
failure_result: true
2 changes: 1 addition & 1 deletion website/docs/security/CVE-2024-42490.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

_Reported by [@m2a2](https://github.com/m2a2)_

## Improper Authorization for Token modification
## Insufficient Authorization for several API endpoints

### Summary

Expand Down
35 changes: 35 additions & 0 deletions website/docs/security/CVE-2024-47070.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# CVE-2024-47070

_Reported by [@efpi-bot](https://github.com/efpi-bot) from [LogicalTrust](https://logicaltrust.net/en/)_

## Password authentication bypass via X-Forwarded-For HTTP header

### Summary

The vulnerability allows bypassing policies by adding X-Forwarded-For header with unparsable IP address, e.g. "a". This results in a possibility to authenticate/authorize to any account with known login or email address.

Since the default authentication flow uses a policy to enable the password stage only when there is no password stage selected on the Identification stage, this vulnerability can be used to skip this policy and continue without the password stage.

### Am I affected

This can be exploited for the following configurations:

- An attacker can access authentik without a reverse proxy (and `AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS` is not configured properly)
- The reverse proxy configuration does not correctly overwrite X-Forwarded-For
- Policies (User and group bindings do _not_ apply) are bound to authentication/authorization flows

### Patches

authentik 2024.6.5 and 2024.8.3 fix this issue.

### Workarounds

Ensure the X-Forwarded-For header is always set by the reverse proxy, and is always set to a correct IP.

In addition you can manually change the _Failure result_ option on policy bindings to _Pass_, which will prevent any stages from being skipped if a malicious request is received.

### For more information

If you have any questions or comments about this advisory:

- Email us at [[email protected]](mailto:[email protected])
1 change: 1 addition & 0 deletions website/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ const docsSidebar = {
"security/security-hardening",
"security/policy",
"security/CVE-2024-47077",
"security/CVE-2024-47070",
"security/CVE-2024-42490",
"security/CVE-2024-38371",
"security/CVE-2024-37905",
Expand Down

0 comments on commit 78f7b04

Please sign in to comment.