IIS文件名解析漏洞扼要分析
概括: 从技术角度分析IIS6文件名解析漏洞的原理与IIS7的相关情况。
a.IIS6错误解析文件类型现象
1、当WEB目录下,文件名以 xxx.asp;xxx.xxx 来进行命名的时候,此文件将送交asp.dll解析(也就是执行脚本)
2、当WEB目录下,在访问以 xxx.asp 命名的目录下的任意文件时,此文件将送交asp.dll解析(也就是执行脚本)
通过对IIS6的核心文件类型解析相关文件的逆向后,整理出下面的核心处理代码。
1 //reverse code by golds7n with ida 2 int __thiscall Url(void *this, char *UrlStruct) 3 { 4 void *pW3_URL_INFO; // esi@1 5 int bSuccess; // eax@1 6 const wchar_t *i; // eax@2 7 wchar_t *wcsSlashTemp; // ebx@6 8 int wcsTemp; // eax@6 9 int wcs_Exten; // eax@6 10 int v8; // esi@9 11 int v10; // eax@11 12 int v11; // ST04_4@13 13 int v12; // eax@13 14 int ExtenDll; // eax@19 15 int Extenisa; // eax@20 16 int ExtenExe; // eax@21 17 int ExtenCgi; // eax@22 18 int ExtenCom; // eax@23 19 int ExtenMap; // eax@24 20 int Entry; // [sp+Ch] [bp-148h]@6 21 wchar_t *wcsMaohaoTemp; // [sp+10h] [bp-144h]@6 22 unsigned int dotCount; // [sp+14h] [bp-140h]@1 23 wchar_t *Str; // [sp+18h] [bp-13Ch]@3 24 char *url_FileName; // [sp+1Ch] [bp-138h]@1 25 char Url_FileExtenName; // [sp+20h] [bp-134h]@1 26 char v25; // [sp+50h] [bp-104h]@1 27 28 dotCount = 0; 29 pW3_URL_INFO = this; 30 STRU::STRU(&Url_FileExtenName, &v25, 0x100u); 31 url_FileName = (char *)pW3_URL_INFO + 228; 32 bSuccess = STRU::Copy((char *)pW3_URL_INFO + 228, UrlStruct); 33 if ( bSuccess < 0 ) 34 goto SubEnd; 35 for ( i = (const wchar_t *)STRU::QueryStr((char *)pW3_URL_INFO + 228); ; i = Str + 1 ) 36 { 37 Str = _wcschr(i, '.'); ***********N1************ 38 if ( !Str ) 39 break; 40 ++dotCount; 41 if ( dotCount > W3_URL_INFO::sm_cMaxDots ) 42 break; 43 bSuccess = STRU::Copy(&Url_FileExtenName, Str); 44 if ( bSuccess < 0 ) 45 goto SubEnd; 46 wcsSlashTemp = _wcschr(Str, '/'); ***********N2************ 47 JUMPOUT(wcsSlashTemp, 0, loc_5A63FD37); 48 wcsTemp = STRU::QueryStr(&Url_FileExtenName); 49 wcsMaohaoTemp = _wcschr((const wchar_t *)wcsTemp, ':'); ***********N3************ 50 JUMPOUT(wcsMaohaoTemp, 0, loc_5A63FD51); 51 wcs_Exten = STRU::QueryStr(&Url_FileExtenName); 52 __wcslwr((wchar_t *)wcs_Exten); 53 if ( META_SCRIPT_MAP::FindEntry(&Url_FileExtenName, &Entry) ) 54 { 55 *((_DWORD *)pW3_URL_INFO + 201) = Entry; 56 JUMPOUT(wcsSlashTemp, 0, loc_5A63FDAD); 57 STRU::Reset((char *)pW3_URL_INFO + 404); 58 break; 59 } 60 if ( STRU::QueryCCH(&Url_FileExtenName) == 4 ) 61 { 62 ExtenDll = STRU::QueryStr(&Url_FileExtenName); 63 if ( !_wcscmp(L".dll", (const wchar_t *)ExtenDll) 64 || (Extenisa = STRU::QueryStr(&Url_FileExtenName), !_wcscmp(L".isa", (const wchar_t *)Extenisa)) ) 65 JUMPOUT(loc_5A63FD89); 66 ExtenExe = STRU::QueryStr(&Url_FileExtenName); 67 if ( !_wcscmp(L".exe", (const wchar_t *)ExtenExe) 68 || (ExtenCgi = STRU::QueryStr(&Url_FileExtenName), !_wcscmp(L".cgi", (const wchar_t *)ExtenCgi)) 69 || (ExtenCom = STRU::QueryStr(&Url_FileExtenName), !_wcscmp(L".com", (const wchar_t *)ExtenCom)) ) 70 JUMPOUT(loc_5A63FD89); 71 ExtenMap = STRU::QueryStr(&Url_FileExtenName); 72 JUMPOUT(_wcscmp(L".map", (const wchar_t *)ExtenMap), 0, loc_5A63FD7B); 73 } 74 } 75 if ( *((_DWORD *)pW3_URL_INFO + 201) 76 || (v10 = *((_DWORD *)pW3_URL_INFO + 202), v10 == 3) 77 || v10 == 2 78 || (v11 = *(_DWORD *)(*((_DWORD *)pW3_URL_INFO + 204) + 0xC4C), 79 v12 = STRU::QueryStr(url_FileName), 80 bSuccess = SelectMimeMappingForFileExt(v12, v11, (char *)pW3_URL_INFO + 756, (char *)pW3_URL_INFO + 1012), 81 bSuccess >= 0) ) 82 v8 = 0; 83 else 84 SubEnd: 85 v8 = bSuccess; 86 STRU::_STRU(&Url_FileExtenName); 87 return v8; 88 }
上述代码中,作星号标记的是N1,N2,N3,分别检测点号,反斜杠和分号。
大概流程为:
请求 /aaa.asp;xxxx.jpg
N1:从头部查找查找 "."号,获得 .asp;xxxx.jpg
N2:查找";"号,如果有则内存截断
N3:查找"/",如果有则内存截断
最终,将保留下来 .asp 字符串,从META_SCRIPT_MAP脚本映射表里与扩展名匹配对比,并反馈给了asp.dll处理
b.IIS7是否延续了漏洞
IIS7的核心处理代码:
1 //reverse code by golds7n with ida 2 const unsigned __int16 *__stdcall MatchPathInUrl(const unsigned __int16 *url_User, unsigned __int32 url_Length, const unsigned __int16 *IIS_MAP_Wizard) 3 { 4 const unsigned __int16 *p; // ebx@1 5 const unsigned __int16 *pUrl; // ecx@4 6 const wchar_t *i; // edi@6 7 signed int isXingHao; // edx@8 8 const unsigned __int16 cWizard; // ax@10 9 const unsigned __int16 *pWizard; // esi@11 10 int cTemp; // eax@17 11 int pCharTemp; // esi@23 12 const unsigned __int16 *pCharUser; // eax@43 13 const unsigned __int16 byteChar; // cx@44 14 const wchar_t cSlash; // ax@50 15 const unsigned __int16 *Str2; // [sp+8h] [bp-8h]@11 16 signed int bFound; // [sp+Ch] [bp-4h]@3 17 18 p = IIS_MAP_Wizard; 19 if ( *IIS_MAP_Wizard != '*' || IIS_MAP_Wizard[1] ) 20 { 21 bFound = 1; 22 if ( *IIS_MAP_Wizard == '/' ) 23 { 24 p = IIS_MAP_Wizard + 1; 25 bFound = 0; 26 ++IIS_MAP_Wizard; 27 } 28 pUrl = url_User; 29 if ( *url_User == '/' ) 30 { 31 pUrl = url_User + 1; 32 ++url_User; 33 } 34 LABEL_6: 35 for ( i = pUrl; ; i += pCharTemp ) 36 { 37 while ( *p == '?' ) 38 { 39 if ( !*i ) 40 return 0; 41 if ( *i == '/' ) 42 goto LABEL_30; 43 ++p; 44 ++i; 45 } 46 isXingHao = 0; 47 if ( *p == '*' ) 48 { 49 ++p; 50 isXingHao = 1; 51 } 52 cWizard = *p; 53 if ( !*p ) 54 break; 55 pWizard = p; 56 Str2 = p; 57 if ( cWizard != '*' ) 58 { 59 do 60 { 61 if ( cWizard == '?' ) 62 break; 63 if ( !cWizard ) 64 break; 65 ++pWizard; 66 cWizard = *pWizard; 67 Str2 = pWizard; 68 } 69 while ( *pWizard != '*' ); 70 } 71 if ( isXingHao ) 72 { 73 if ( !*pWizard ) 74 { 75 cTemp = (int)&i[pWizard - p]; 76 if ( cTemp > (unsigned int)&pUrl[url_Length] ) 77 return 0; 78 while ( *(_WORD *)cTemp != '/' && *(_WORD *)cTemp && *i != '/' && *i ) 79 { 80 ++i; 81 cTemp += 2; 82 } 83 } 84 pCharTemp = pWizard - p; 85 while ( _wcsncmp(i, p, pCharTemp) ) 86 { 87 if ( !*i ) 88 return 0; 89 if ( *i == '/' ) 90 goto LABEL_29; 91 ++i; 92 } 93 } 94 else 95 { 96 pCharTemp = pWizard - p; 97 if ( _wcsncmp(i, p, pCharTemp) ) 98 { 99 LABEL_29: 100 pUrl = url_User; 101 LABEL_30: 102 if ( !bFound ) 103 return 0; 104 while ( *pUrl != '/' ) 105 { 106 if ( !*pUrl ) 107 return 0; 108 ++pUrl; 109 } 110 if ( !*pUrl ) 111 return 0; 112 p = IIS_MAP_Wizard; 113 ++pUrl; 114 url_User = pUrl; 115 goto LABEL_6; 116 } 117 } 118 p = Str2; 119 pUrl = url_User; 120 } 121 if ( isXingHao ) 122 { 123 cSlash = *i; 124 if ( *i == '/' ) 125 return i; 126 do 127 { 128 if ( !cSlash ) 129 break; 130 ++i; 131 cSlash = *i; 132 } 133 while ( *i != '/' ); 134 } 135 if ( *i != '/' && *i ) 136 goto LABEL_30; 137 return i; 138 } 139 pCharUser = url_User; 140 do 141 { 142 byteChar = *pCharUser; 143 ++pCharUser; 144 } 145 while ( byteChar ); 146 return &url_User[pCharUser - (url_User + 1)]; 147 } 148 MatchPathInUrl(const unsigned __int16 *url_User, unsigned __int32 url_Length, const unsigned __int16 *IIS_MAP_Wizard)
参数url_User是用户提交的路径参数,类似PHOST/DEFAULT WEB SITE/aa.asp;xxx.jpg,由 服务/站点名称/请求路径 构成,IIS_MAP_Wizard是在管理器文件映射里的每个表项,譬如*.ASP
比较的结果就是,拿aa.asp;xxx.jpg与*.ASP进行匹配,显然结果是不匹配的(/xxx.asp/xxx.jpg,是拿xxx.jpg和*.ASP进行匹配)
c.总结
IIS6文件映射配置图
IIS7文件映射配置图
从上面的关键分析和图中,可以看出,IIS6存在解析漏洞是由于其设计上的问题导致,IIS6只简单地根据扩展名来识别,而IIS7是进行通配符匹配来定夺请求文件是否是某脚本类型,可见IIS7纠正了错误机制,更加科学、健壮。