Cyl created CASSANDRA-21232:
-------------------------------

             Summary: 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
            Reporter: Cyl


# 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.




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to