Share
## https://sploitus.com/exploit?id=6CB253C4-7817-5996-A810-E36A42734CA6
# CVE-2026-45185 Nuclei Template Validation Lab

This repository is not a general-purpose exploit PoC repository. It is a local
validation lab for reproducing and reviewing the behavior of a
`CVE-2026-45185` template intended for contribution to
`projectdiscovery/nuclei-templates`.

```text
The nuclei code template is not a version-only detector.
It directly controls STARTTLS, BDAT, TLS close_notify, and a following
SMTP plaintext byte on the same TCP connection.

This sequence matches in the local vulnerable Exim 4.99.2 GnuTLS lab and does
not match in the patched Exim 4.99.3 GnuTLS lab under the same conditions.
```

The current validation signal is a remote SMTP response oracle, not a direct
observation of the UAF write itself. Internally, this CVE is a use-after-free
where newline bytes (`\r`/`\n`) can be written into a freed GnuTLS transfer
buffer after TLS shutdown. In practice, a client cannot realistically observe
that freed-buffer write directly through SMTP responses. Therefore, this README
and the template do not claim to directly prove the
`bdat_ungetc -> tls_ungetc` UAF write or RCE. Instead, the template detects a
receive stack/state recovery difference that appears during the trigger flow.

While tracing the vulnerability mechanism, I observed that after TLS
`close_notify` during STARTTLS + BDAT handling, stale `tls_*` function pointers
can remain in the lower layer of the BDAT receive stack instead of being
properly restored to `smtp_*` function pointers. That state becomes visible in
how the server handles the next SMTP command. After the split BDAT reaches first
completion, sending `NOOP` on the same session makes the vulnerable Exim 4.99.2
GnuTLS lab return `421 lost input connection`, while the patched Exim 4.99.3
GnuTLS lab handles it normally with `250 OK`. This clear vulnerable/patched
response difference is used as the matcher for the local, authorized nuclei code
template.

For a deeper vulnerability flow walkthrough, see
`CVE-2026-45185-Technical-Analysis.md`.

## Validation Matrix

| Target | Version | TLS backend | STARTTLS | CHUNKING | Port | Expected nuclei result |
| --- | --- | --- | --- | --- | --- | --- |
| vulnerable | Exim 4.99.2 | GnuTLS | yes | yes | `127.0.0.1:2525` | match |
| patched | Exim 4.99.3 | GnuTLS | yes | yes | `127.0.0.1:2526` | no match |

Common SMTP envelope recipient (`RCPT TO`):

```text
victim@lab.local
```

The Docker lab's `lab_rcpt` ACL accepts this envelope recipient. On a general
SMTP target, if `RCPT TO` is rejected, the sequence may not reach the BDAT body
parser, so the template needs an accepted recipient.

This value is distinct from the `To:` header inside the BDAT body. The
`RCPT TO` recipient is an SMTP envelope address that must pass the server's
recipient checks. The `To:` value in the BDAT body is only message header text;
it does not need to exist or be accepted as a mailbox by the server.

## Template Location

```text
templates/CVE-2026-45185.yaml
```

Template name:

```text
Exim 4.97-4.99.2 GnuTLS STARTTLS BDAT - Same-Session Response Check
```

The template is written with `metadata.verified: true` and has the `code` and
`intrusive` tags.

## Quick Validation

Run the following commands from the `POC_2026_45185/` directory.

```bash
git submodule update --init --recursive
docker compose build
docker compose up -d
```

Validate the template syntax:

```bash
nuclei -validate -t templates/CVE-2026-45185.yaml
```

Run against the vulnerable lab:

```bash
nuclei -code \
  -t templates/CVE-2026-45185.yaml \
  -u 127.0.0.1:2525 \
  -var recipient=victim@lab.local \
  -debug
```

Expected result:

```text
CVE-2026-45185: vulnerable response oracle matched
```

Run against the patched lab:

```bash
nuclei -code \
  -t templates/CVE-2026-45185.yaml \
  -u 127.0.0.1:2526 \
  -var recipient=victim@lab.local \
  -debug
```

Expected result:

```text
no match
NO-MATCH: patched-like response: NOOP succeeded after split trigger
```

Note that the nuclei `code` protocol is not executed by default, so `-code` is
required. A local code template that has not been merged upstream may also be
treated as unsigned depending on the nuclei version and configuration.

## Why Code Protocol?

The core of this CVE is not an SMTP banner or version check. The template needs
to create the following transport-state transition on the same TCP connection:

```text
plaintext SMTP EHLO
-> STARTTLS
-> TLS handshake on the same TCP connection
-> TLS EHLO / MAIL FROM / RCPT TO / BDAT 70 LAST
-> first 69 bytes of the BDAT body as TLS application data
-> TLS close_notify without closing the TCP socket
-> final body byte as plaintext on the same TCP connection
-> same-session plaintext NOOP response check
```

## What The Template Checks

The Python code inside the YAML template prints the fixed marker only after all
of the following conditions pass. The nuclei matcher only matches that marker.

```text
Exim identity is found
AND STARTTLS is advertised in plaintext EHLO
AND CHUNKING is advertised in plaintext EHLO
AND STARTTLS is accepted
AND CHUNKING is advertised in TLS EHLO
AND MAIL FROM is accepted
AND RCPT TO is accepted
AND the split close_notify BDAT reaches first completion
AND first completion contains "250 OK id="
AND the same-session plaintext NOOP response contains "421"
AND the same-session plaintext NOOP response contains "lost input connection"
```

The template does not match on any of the following signals alone:

```text
version-only
timeout-only
connection-drop-only
empty-response-only
recipient rejection
STARTTLS/CHUNKING advertisement only
```

## Response Oracle

Both labs process the split BDAT message through first completion.

```text
250- 70 byte chunk, total 72
250 OK id=...
```

The difference appears when the next SMTP plaintext command is sent on the same
SMTP session.

Vulnerable 4.99.2:

```text
NOOP -> 421 exim-lab.local lost input connection
QUIT -> 421 exim-lab.local lost input connection
RSET -> 421 exim-lab.local lost input connection
```

Patched 4.99.3:

```text
NOOP -> 250 OK
QUIT -> 221 exim-lab.local closing connection
RSET -> 250 Reset OK
```

Interpretation:

```text
Observation:
  Both labs reach split BDAT message completion.
  Only the vulnerable lab fails to return cleanly to the next plaintext SMTP
  command loop in the same session.

Evidence:
  The vulnerable follow-up response is 421 lost input connection.
  The patched follow-up response is 250 OK or 221 closing connection.

Inference:
  This difference is consistent with the receive stack/state recovery difference
  after STARTTLS close_notify.
```

## Payload Shape

The template uses the following 70-byte message as the BDAT body.

```text
From: sender@example.com\r\n
To: victim@example.com\r\n
Subject: poc\r\n
\r\n
body
```

The SMTP envelope recipient is passed separately through the template variable
`recipient`. The `To:` header in the body is text and is unrelated to whether
SMTP `RCPT TO` is accepted, so it does not need to exist or be accepted by the
server.

Split shape:

```text
BDAT 70 LAST
TLS body:   first 69 bytes, ending with "bod"
TLS event:  close_notify
Plaintext:  final byte "y"
Follow-up:  NOOP
```

## Local Sanity Check

You can manually verify that both labs advertise Exim, STARTTLS, and CHUNKING.

```bash
printf 'EHLO lab-client.local\r\nQUIT\r\n' | nc -w 3 127.0.0.1 2525
printf 'EHLO lab-client.local\r\nQUIT\r\n' | nc -w 3 127.0.0.1 2526
```

Expected signals:

```text
Exim
STARTTLS
CHUNKING
```

You can also check the normal STARTTLS path:

```bash
openssl s_client -starttls smtp -connect 127.0.0.1:2525 -crlf
openssl s_client -starttls smtp -connect 127.0.0.1:2526 -crlf
```

## Scope And Safety

- Use this only against the local Docker lab or explicitly authorized SMTP
  targets.
- Do not scan or send the trigger to third-party Exim servers.
- This repository does not provide an RCE exploit chain, persistence, or
  post-exploitation.
- The default Docker images are debug builds, not ASAN builds.
- Follow-up gdb/ASAN work for internal call-path confirmation is tracked
  separately under `debugging/` and `notes/source-walkthrough-progress.md`.

## Repository Layout

```text
POC_2026_45185/
  compose.yaml
  vulnerable/        Exim 4.99.2 + GnuTLS debug build
  patched/           Exim 4.99.3 + GnuTLS debug build
  nuclei-templates/  submodule: local nuclei template workspace
```

## References

- XBOW write-up: https://xbow.com/blog/dead-letter-cve-2026-45185-xbow-found-rce-exim
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-45185
- Exim advisory: https://exim.org/static/doc/security/EXIM-Security-2026-05-01.1/EXIM-Security-2026-05-01.1.txt
- oss-security announcement: https://www.openwall.com/lists/oss-security/2026/05/12/4
- Upstream Exim patch: https://code.exim.org/exim/exim/commit/040c1ce6889f435206677ed532c9a4185cf0bcaf