安全研究
安全漏洞
ytnef缓冲区溢出和目录遍历漏洞
发布日期:2009-09-06
更新日期:2009-09-08
受影响系统:
GNOME Evolution 2.62.2描述:
ytnef ytnef 2.6
BUGTRAQ ID: 36294
yTNEF是用于解码TNEF邮件附件的开源过滤器程序。
传输中立封装格式(TNEF)是Microsoft Outlook和Microsoft Exchange Server所使用的私有邮件附件格式。Evolution的一个插件可提供对TNEF编码邮件的基本支持,而这个插件使用了ytnef库(libytnef)处理TNEF消息,借用了ytnef程序的代码。
------------------------------------------------------------------------
Evolution TNEF附件解码器插件
------------------------------------------------------------------------
如果邮件附件的MIME类型为application/vnd.ms-tnef或application/ms-tnef就会启动这个插件,在~/.evolution/cache/tmp下创建tnef-attachment-XXXXXX格式的临时目录,TNEF附件保存为.evo-attachment.tnef。
void
org_gnome_format_tnef(void *ep, EMFormatHookTarget *t)
{
[...]
tmpdir = e_mkdtemp("tnef-attachment-XXXXXX");
if (tmpdir == NULL)
return;
filepath = tmpdir;
name = g_build_filename(tmpdir, ".evo-attachment.tnef",
NULL);
out = camel_stream_fs_new_with_name(name, O_RDWR|O_CREAT, 0666);
所保存的文件由TNEFParseFile()解析,结果保存在TNEFStruct类型的struct中,然后将这个结构传送给processTnef()函数。这个函数尝试从TNEF流获得所有相关的数据和附件,TNEF流的每个相关部分都存储到了之前所创建的临时目录中。
/* Extracting the winmail.dat */
TNEFInitialize(tnef);
tnef->Debug = verbose;
if (TNEFParseFile(name, tnef) == -1) {
printf("ERROR processing file\n");
}
processTnef(tnef);
TNEFFree(tnef);
/* Extraction done */
------------------------------------------------------------------------
yTNEF
------------------------------------------------------------------------
yTNEF以类似的方式处理TNEF文件,从命令行接收文件名,调用创建TNEFStruct结构体的TNEFParseFile(),然后调用ProcessTNEF()。如果ProcessTNEF()找到了可处理的附件,会本地保存这些附件。ProcessTNEF()函数与上文Evolution插件的processTnef()函数基本类似。
int main(int argc, char ** argv) {
[...]
for(i=1; i<argc; i++) {
[...]
TNEFInitialize(&TNEF);
TNEF.Debug = verbose;
if (TNEFParseFile(argv[ i], &TNEF) == -1) {
printf("ERROR processing file\n");
continue;
}
ProcessTNEF(TNEF);
TNEFFree(&TNEF);
}
}
------------------------------------------------------------------------
目录遍历
------------------------------------------------------------------------
在处理TNEF文件时,yTNEF和Evolution插件都会保存某些类型的TNEF结构。联系人、任务和约会可使用一些特殊的处理功能,如果将Message Class设置为特定值就会调用这些功能。
void processTnef(TNEFStruct *tnef) {
[...]
/* First see if this requires special processing. */
/* ie: it's a Contact Card, Task, or Meeting request (vCal/vCard)
*/
if (tnef->messageClass[0] != 0) {
if (strcmp(tnef->messageClass, "IPM.Contact") == 0) {
saveVCard(tnef);
}
if (strcmp(tnef->messageClass, "IPM.Task") == 0) {
saveVTask(tnef);
}
if (strcmp(tnef->messageClass, "IPM.Appointment") == 0) {
saveVCalendar(tnef);
foundCal = 1;
}
}
if ((filename = MAPIFindUserProp(&(tnef->MapiProperties),
PROP_TAG(PT_STRING8,0x24))) != MAPI_UNDEFINED) {
if (strcmp(filename->data, "IPM.Appointment") == 0) {
/* If it's "indicated" twice, we don't want to
save 2 calendar entries. */
if (foundCal == 0) {
saveVCalendar(tnef);
}
}
}
还有一些代码用于处理Message Class设置为IPM.Microsoft Mail.Note的TNEF结构。在Evolution插件中,不会调用这段代码,因为全局变量saveRTF被设置为0,而在yTNEF中这个全局变量是由命令行控制的。
if (strcmp(TNEF.messageClass, "IPM.Microsoft Mail.Note") == 0)
{
if ((saveRTF == 1) && (TNEF.subject.size > 0)) {
// Description
if ((filename=MAPIFindProperty(&(TNEF.MapiProperties),
PROP_TAG(PT_BINARY, PR_RTF_COMPRESSED)))
!= MAPI_UNDEFINED) {
[...]
在处理完上述结构后还会本地保存所有其他的附件,用于保存附件的文件名是从TNEF数据中获得的。在正常附件的情况下,代码首先查看TNEF数据是否包含有MAPI属性,如果是会查找特定的属性;如果存在这些属性,就会从这些属性中获得文件名,而如果不存在就会使用附件的标题(这个标题也是通过TNEF结构设置的);如果这个标题也不可用,就会使用默认的文件名。
if ((RealAttachment == 1) || (saveintermediate == 1)) {
/* Ok, it's not an embedded stream, so now we */
/* process it. */
if ((filename = MAPIFindProperty(&(p->MAPI),
PROP_TAG(30,0x3707)))
== MAPI_UNDEFINED) {
if ((filename = MAPIFindProperty(&(p->MAPI),
PROP_TAG(30,0x3001)))
== MAPI_UNDEFINED) {
filename = &(p->Title);
}
}
if (filename->size == 1) {
filename = (variableLength*)malloc(sizeof(variableLength));
filename->size = 20;
filename->data = (char*)malloc(20);
sprintf(filename->data, "file_%03i.dat", count);
}
if (filepath == NULL) {
sprintf(ifilename, "%s", filename->data);
} else {
sprintf(ifilename, "%s/%s", filepath, filename->data);
}
for(i=0; i<strlen(ifilename); i++)
if (ifilename[ i] == ' ')
ifilename[ i] = '_';
if ((fptr = fopen(ifilename, "wb"))==NULL) {
printf("ERROR: Error writing file to disk!");
} else {
if (object == 1) {
fwrite(filedata->data + 16,
sizeof(BYTE),
filedata->size - 16,
fptr);
} else {
fwrite(filedata->data,
sizeof(BYTE),
filedata->size,
fptr);
}
fclose(fptr);
}
}
在创建新文件之前用下划线替换了文件名中的所有空格。由于没有对文件名执行过滤,攻击者可以遍历出临时目录,以目标用户的权限创建或覆盖任意文件。如果覆盖了~/.bashrc攻击者还可以执行任意指令。
------------------------------------------------------------------------
缓冲区溢出
------------------------------------------------------------------------
由于文件名被拷贝到了256字节的固定大小缓冲区,提供超长的文件名还可以触发溢出。在Evolution插件中触发的是堆溢出,而在yTNEF中触发的是栈溢出。
Evolution插件:
void processTnef(TNEFStruct *tnef) {
[...]
ifilename = (char *) g_malloc(sizeof(char) * 256);
[...]
if (filepath == NULL) {
sprintf(ifilename, "%s", filename->data);
} else {
sprintf(ifilename, "%s/%s", filepath, filename->data);
}
yTNEF:
void ProcessTNEF(TNEFStruct TNEF) {
[...]
char ifilename[256];
[...]
if (filepath == NULL) {
sprintf(ifilename, "%s", filename->data);
} else {
sprintf(ifilename, "%s/%s", filepath, filename->data);
}
<*来源:Yorick Koster
链接:http://secunia.com/advisories/36624/
http://marc.info/?l=full-disclosure&m=125223525804187&w=2
http://www.ocert.org/advisories/ocert-2009-013.html
*>
建议:
厂商补丁:
GNOME
-----
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
http://www.gnome.org/projects/evolution/
ytnef
-----
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
http://sourceforge.net/projects/ytnef/
浏览次数:3325
严重程度:0(网友投票)
绿盟科技给您安全的保障
