[
https://issues.apache.org/jira/browse/CASSANDRA-21232?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Cyl updated CASSANDRA-21232:
----------------------------
Description:
h2. 2. Vulnerability Description
*Name*: Authenticated DoS via {{ALTER ROLE ... WITH HASHED PASSWORD}}
*Overview*:
The {{ALTER ROLE}} and {{CREATE ROLE}} statements support a {{HASHED PASSWORD}}
option, which allows setting a password by providing its bcrypt hash directly.
To validate the provided hash, Cassandra calls {{BCrypt.checkpw("dummy",
hash)}} in {{org.apache.cassandra.auth.RoleOptions.validate()}}. This
validation occurs synchronously on the main request executor thread
({{Dispatcher.requestExecutor}}).
An attacker can provide a bcrypt hash with an extremely high cost factor (e.g.,
{{$2a$30$...}}). {{BCrypt.checkpw}} will attempt to hash the string "dummy"
using the provided salt and cost factor. A cost factor of 30 means $2^{30}$
iterations, which takes an impractical amount of time to complete. Even a cost
factor of 24 (16 million iterations) can block a thread for minutes. By sending
multiple such requests concurrently, an authenticated attacker can exhaust the
request executor thread pool, causing a complete denial of service.
*Affected Configurations*:
* Clusters running {{PasswordAuthenticator}}.
* Any authenticated account that can {{ALTER}} a role (including their own) or
{{CREATE}} a role.
*Impact*:
* Complete denial of service.
* The server becomes unresponsive to all CQL requests.
* CPU usage spikes to 100% on all cores if enough requests are sent.
h2. 2. Proof-of-Concept
The file {{poc_hashed_dos.py}} demonstrates the attack:
# Start a Cassandra instance.
# Launch 200 concurrent threads that run {{ALTER ROLE target_role WITH HASHED
PASSWORD '<high_cost_hash>'}}.
# The hash used has a cost factor of 24 ({{$2a$24$...}}), which causes
{{BCrypt.checkpw}} to run for a very long time.
# Monitor the latency of a simple {{SELECT now()}} query.
*Observed Output*:
{code}
[Victim] Query latency: 0.0599s
[Victim] Query latency: 0.1278s
[Victim] Query latency: 1.2976s
[Victim] Query failed/timed out: ...
{code}
The server quickly becomes unresponsive.
h2. 3. Problematic Code Reference
In {{src/java/org/apache/cassandra/auth/RoleOptions.java}}:
{code:java}
case HASHED_PASSWORD:
// ...
try
{
// This runs on the request thread
BCrypt.checkpw("dummy", (String) option.getValue());
}
catch (Exception e)
{
throw new InvalidRequestException("Invalid hashed
password value. Please use jBcrypt.");
}
break;
{code}
In {{src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java}}:
{code:java}
public void validate(ClientState state) throws RequestValidationException
{
opts.validate(); // Calls RoleOptions.validate()
// ...
}
{code}
h2. 4. Recommended Fixes
# *Limit Cost Factor*: Enforce a maximum allowed cost factor for
{{HASHED_PASSWORD}} (e.g., 12 or matches the server configuration). Reject
hashes with higher cost factors immediately without calling {{BCrypt.checkpw}}.
# *Offload Validation*: Perform the validation on a separate thread pool (like
{{authExecutor}} introduced in CASSANDRA-17812) or asynchronously.
# *Rate Limiting*: Apply rate limiting to {{ALTER ROLE}} and {{CREATE ROLE}}
statements.
h2. 5. Comparison with Previous Vulnerability
This is related to the vulnerability described in {{README.md}} (DoS via
{{ALTER ROLE ... WITH PASSWORD}}), but it is more severe because:
# The attacker controls the cost factor via the hash string. In the
{{PASSWORD}} case, the cost factor is determined by the server configuration
({{auth_bcrypt_gensalt_log2_rounds}}), which is typically low (default 4-10).
# A single request with a high cost factor (e.g., 30) can block a thread
effectively forever, whereas the {{PASSWORD}} attack requires many requests to
saturate the CPU with lower-cost hashes.
was:
# Authenticated DoS via `ALTER ROLE ... WITH HASHED PASSWORD`
## 1. Vulnerability Description
**Name**: Authenticated DoS via `ALTER ROLE ... WITH HASHED PASSWORD`
**Overview**:
The `ALTER ROLE` and `CREATE ROLE` statements support a `HASHED PASSWORD`
option, which allows setting a password by providing its bcrypt hash directly.
To validate the provided hash, Cassandra calls `BCrypt.checkpw("dummy", hash)`
in `org.apache.cassandra.auth.RoleOptions.validate()`. This validation occurs
synchronously on the main request executor thread
(`Dispatcher.requestExecutor`).
An attacker can provide a bcrypt hash with an extremely high cost factor (e.g.,
`$2a$30$...`). `BCrypt.checkpw` will attempt to hash the string "dummy" using
the provided salt and cost factor. A cost factor of 30 means $2^{30}$
iterations, which takes an impractical amount of time to complete. Even a cost
factor of 24 (16 million iterations) can block a thread for minutes. By sending
multiple such requests concurrently, an authenticated attacker can exhaust the
request executor thread pool, causing a complete denial of service.
**Affected Configurations**:
- Clusters running `PasswordAuthenticator`.
- Any authenticated account that can `ALTER` a role (including their own) or
`CREATE` a role.
**Impact**:
- Complete denial of service.
- The server becomes unresponsive to all CQL requests.
- CPU usage spikes to 100% on all cores if enough requests are sent.
## 2. Proof-of-Concept
The file `poc_hashed_dos.py` demonstrates the attack:
1. Start a Cassandra instance.
2. Launch 200 concurrent threads that run `ALTER ROLE target_role WITH HASHED
PASSWORD '<high_cost_hash>'`.
3. The hash used has a cost factor of 24 (`$2a$24$...`), which causes
`BCrypt.checkpw` to run for a very long time.
4. Monitor the latency of a simple `SELECT now()` query.
**Observed Output**:
```
[Victim] Query latency: 0.0599s
[Victim] Query latency: 0.1278s
[Victim] Query latency: 1.2976s
[Victim] Query failed/timed out: ...
```
The server quickly becomes unresponsive.
## 3. Problematic Code Reference
In `src/java/org/apache/cassandra/auth/RoleOptions.java`:
```java
case HASHED_PASSWORD:
// ...
try
{
// This runs on the request thread
BCrypt.checkpw("dummy", (String) option.getValue());
}
catch (Exception e)
{
throw new InvalidRequestException("Invalid hashed
password value. Please use jBcrypt.");
}
break;
```
In `src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java`:
```java
public void validate(ClientState state) throws RequestValidationException
{
opts.validate(); // Calls RoleOptions.validate()
// ...
}
```
## 4. Recommended Fixes
1. **Limit Cost Factor**: Enforce a maximum allowed cost factor for
`HASHED_PASSWORD` (e.g., 12 or matches the server configuration). Reject hashes
with higher cost factors immediately without calling `BCrypt.checkpw`.
2. **Offload Validation**: Perform the validation on a separate thread pool
(like `authExecutor` introduced in CASSANDRA-17812) or asynchronously.
3. **Rate Limiting**: Apply rate limiting to `ALTER ROLE` and `CREATE ROLE`
statements.
## 5. Comparison with Previous Vulnerability
This is related to the vulnerability described in `README.md` (DoS via `ALTER
ROLE ... WITH PASSWORD`), but it is more severe because:
1. The attacker controls the cost factor via the hash string. In the
`PASSWORD` case, the cost factor is determined by the server configuration
(`auth_bcrypt_gensalt_log2_rounds`), which is typically low (default 4-10).
2. A single request with a high cost factor (e.g., 30) can block a thread
effectively forever, whereas the `PASSWORD` attack requires many requests to
saturate the CPU with lower-cost hashes.
> Authenticated DoS via `ALTER ROLE ... WITH HASHED PASSWORD`
> -----------------------------------------------------------
>
> Key: CASSANDRA-21232
> URL: https://issues.apache.org/jira/browse/CASSANDRA-21232
> Project: Apache Cassandra
> Issue Type: Bug
> Components: Feature/Authorization, Feature/Rate Limiting
> Reporter: Cyl
> Priority: Normal
> Labels: dos, performance, security
>
> h2. 2. Vulnerability Description
> *Name*: Authenticated DoS via {{ALTER ROLE ... WITH HASHED PASSWORD}}
> *Overview*:
> The {{ALTER ROLE}} and {{CREATE ROLE}} statements support a {{HASHED
> PASSWORD}} option, which allows setting a password by providing its bcrypt
> hash directly. To validate the provided hash, Cassandra calls
> {{BCrypt.checkpw("dummy", hash)}} in
> {{org.apache.cassandra.auth.RoleOptions.validate()}}. This validation occurs
> synchronously on the main request executor thread
> ({{Dispatcher.requestExecutor}}).
> An attacker can provide a bcrypt hash with an extremely high cost factor
> (e.g., {{$2a$30$...}}). {{BCrypt.checkpw}} will attempt to hash the string
> "dummy" using the provided salt and cost factor. A cost factor of 30 means
> $2^{30}$ iterations, which takes an impractical amount of time to complete.
> Even a cost factor of 24 (16 million iterations) can block a thread for
> minutes. By sending multiple such requests concurrently, an authenticated
> attacker can exhaust the request executor thread pool, causing a complete
> denial of service.
> *Affected Configurations*:
> * Clusters running {{PasswordAuthenticator}}.
> * Any authenticated account that can {{ALTER}} a role (including their own)
> or {{CREATE}} a role.
> *Impact*:
> * Complete denial of service.
> * The server becomes unresponsive to all CQL requests.
> * CPU usage spikes to 100% on all cores if enough requests are sent.
> h2. 2. Proof-of-Concept
> The file {{poc_hashed_dos.py}} demonstrates the attack:
> # Start a Cassandra instance.
> # Launch 200 concurrent threads that run {{ALTER ROLE target_role WITH HASHED
> PASSWORD '<high_cost_hash>'}}.
> # The hash used has a cost factor of 24 ({{$2a$24$...}}), which causes
> {{BCrypt.checkpw}} to run for a very long time.
> # Monitor the latency of a simple {{SELECT now()}} query.
> *Observed Output*:
> {code}
> [Victim] Query latency: 0.0599s
> [Victim] Query latency: 0.1278s
> [Victim] Query latency: 1.2976s
> [Victim] Query failed/timed out: ...
> {code}
> The server quickly becomes unresponsive.
> h2. 3. Problematic Code Reference
> In {{src/java/org/apache/cassandra/auth/RoleOptions.java}}:
> {code:java}
> case HASHED_PASSWORD:
> // ...
> try
> {
> // This runs on the request thread
> BCrypt.checkpw("dummy", (String) option.getValue());
> }
> catch (Exception e)
> {
> throw new InvalidRequestException("Invalid hashed
> password value. Please use jBcrypt.");
> }
> break;
> {code}
> In {{src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java}}:
> {code:java}
> public void validate(ClientState state) throws RequestValidationException
> {
> opts.validate(); // Calls RoleOptions.validate()
> // ...
> }
> {code}
> h2. 4. Recommended Fixes
> # *Limit Cost Factor*: Enforce a maximum allowed cost factor for
> {{HASHED_PASSWORD}} (e.g., 12 or matches the server configuration). Reject
> hashes with higher cost factors immediately without calling
> {{BCrypt.checkpw}}.
> # *Offload Validation*: Perform the validation on a separate thread pool
> (like {{authExecutor}} introduced in CASSANDRA-17812) or asynchronously.
> # *Rate Limiting*: Apply rate limiting to {{ALTER ROLE}} and {{CREATE ROLE}}
> statements.
> h2. 5. Comparison with Previous Vulnerability
> This is related to the vulnerability described in {{README.md}} (DoS via
> {{ALTER ROLE ... WITH PASSWORD}}), but it is more severe because:
> # The attacker controls the cost factor via the hash string. In the
> {{PASSWORD}} case, the cost factor is determined by the server configuration
> ({{auth_bcrypt_gensalt_log2_rounds}}), which is typically low (default 4-10).
> # A single request with a high cost factor (e.g., 30) can block a thread
> effectively forever, whereas the {{PASSWORD}} attack requires many requests
> to saturate the CPU with lower-cost hashes.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]