Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
549 changes: 549 additions & 0 deletions pocs/linux/kernelctf/CVE-2026-23060_lts_cos_mitigation/docs/exploit.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Vulnerability Details

- **Requirements**:
- **Capabilities**: None
- **Kernel configuration**: `CONFIG_CRYPTO=y`, `CONFIG_CRYPTO_USER_API=y`, `CONFIG_CRYPTO_AUTHENC=y`
- **User namespaces required**: No
- **Introduced by**: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=104880a6b470958ddc30e139c41aa4f6ed3a5234
- **Fixed by**: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2397e9264676be7794f8f7f1e9763d90bd3c7335
- **Affected Version**: `4.3 - 6.18`
- **Affected Component**: `crypto/authencesn`
- **Syscall to disable**: -
- **Cause**: Out-of-bounds Access due to lack of minimum length check for `dst` scatterlist.
- **Description**: The authencesn template assumes ESP AAD is at least 8 bytes (SPI+SEQ) but doesn't enforce it, so decrypt can be called with assoclen < 8 and a small RX buffer. In that case `crypto_authenc_esn_decrypt()` still reads 8 bytes from req->dst to swap ESN fields, walking past the end of the dst scatterlist and face end of the list in `scatterwalk_copychunks()`.

# Vulnerability Analysis

`authencesn` assumes the ESP AAD is at least 8 bytes (SPI[4] + Seq[4]) per RFC 4303, but it does not validate this. During decryption it unconditionally swaps ESN-related bytes in the destination scatterlist using three `scatterwalk_map_and_copy()` calls. (`[1]`)

```c
// https://github.com/gregkh/linux/blob/v6.12.52/crypto/authencesn.c#L262-L311
static int crypto_authenc_esn_decrypt(struct aead_request *req)
{
// ...
unsigned int assoclen = req->assoclen;
unsigned int cryptlen = req->cryptlen;
u8 *ihash = ohash + crypto_ahash_digestsize(auth);
struct scatterlist *dst = req->dst;
u32 tmp[2];
int err;

// ...

/* Move high-order bits of sequence number to the end. */
scatterwalk_map_and_copy(tmp, dst, 0, 8, 0); // **[1] swap within 8 bytes without `dst` length validation**
scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);

// ...
}
```

From user space (AF_ALG), AAD or ciphertext can be shorter than 8 bytes or even absent, so the RX scatterlist may cover fewer than 8 bytes. In that case `scatterwalk_map_and_copy()` can walk past the end of the SGL, triggering a NULL dereference in `scatterwalk_copychunks()` and can also result in reads from uninitialized memory.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
all: exploit

prerequisites:
wget -O target_db.kxdb https://storage.googleapis.com/kernelxdk/db/kernelctf.kxdb

exploit: exploit.cpp
g++ -o exploit exploit.cpp -static -lkernelXDK

exploit_debug: exploit.cpp
g++ -o exploit_debug exploit.cpp -g -static -lkernelXDK
Binary file not shown.
Loading