当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2013-022356

漏洞标题:TUNet的拒绝服务漏洞

相关厂商:清华大学

漏洞作者: cssembly

提交时间:2013-04-23 11:08

修复时间:2013-07-22 11:09

公开时间:2013-07-22 11:09

漏洞类型:拒绝服务

危害等级:中

自评Rank:10

漏洞状态:已交由第三方合作机构(cncert国家互联网应急中心)处理

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2013-04-23: 细节已通知厂商并且等待厂商处理中
2013-04-27: 厂商已经确认,细节仅向厂商公开
2013-04-30: 细节向第三方安全合作伙伴开放
2013-06-21: 细节向核心白帽子及相关领域专家公开
2013-07-01: 细节向普通白帽子公开
2013-07-11: 细节向实习白帽子公开
2013-07-22: 细节向公众公开

简要描述:

TUNet存在拒绝服务漏洞

详细说明:

size_t __thiscall sub_4015C0(void *this, int a2, char a3, int a4)
{
void *v4; // esi@1
SOCKET v5; // ebx@2
const char *v6; // eax@4
unsigned __int32 v7; // eax@4
u_short v8; // dx@4
size_t v9; // ebp@6
char *v11; // eax@9
char *v12; // esi@10
const char v13; // al@13
int *v14; // ecx@14
const char *v15; // esi@18
unsigned int v16; // kr18_4@18
struct sockaddr name; // [sp+10h] [bp-9BCh]@4
int v18; // [sp+20h] [bp-9ACh]@13
int v19; // [sp+24h] [bp-9A8h]@13
int v20; // [sp+28h] [bp-9A4h]@13
int v21; // [sp+2Ch] [bp-9A0h]@13
char Str[1024]; // [sp+30h] [bp-99Ch]@6
char Src; // [sp+430h] [bp-59Ch]@6
struct WSAData WSAData; // [sp+830h] [bp-19Ch]@1
int v25; // [sp+9C8h] [bp-4h]@1
v4 = this;
v25 = 1;
if ( WSAStartup(0x202u, &WSAData) )
goto LABEL_8;
v5 = socket(2, 1, 0);
if ( (v5 & 0x80000000u) != 0 )
{
CString::operator_("创建SOCKET失败");
LABEL_8:
WSACleanup();
LOBYTE(v25) = 0;
sub_515C81(&a2);
v25 = -1;
sub_515C81(&a3);
return 0;
}
v6 = (const char *)*((_DWORD *)v4 + 4);
*(_DWORD *)&name.sa_family = 0;
*(_DWORD *)&name.sa_data[2] = 0;
name.sa_family = 2;
*(_DWORD *)&name.sa_data[6] = 0;
*(_DWORD *)&name.sa_data[10] = 0;
v7 = inet_addr(v6);
v8 = *((_WORD *)v4 + 2);
*(_DWORD *)&name.sa_data[2] = v7;
*(_WORD *)&name.sa_data[0] = htons(v8);
if ( connect(v5, &name, 16) < 0 )
{
CString::operator_((LPCSTR)&unk_571438);
goto LABEL_8;
}
memset(Str, 0, sizeof(Str));
sprintf(Str, "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: Close\r\n\r\n", a2, *((_DWORD *)v4 + 4));
send(v5, Str, strlen(Str) + 1, 0);
memset(Str, 0, sizeof(Str));
memset(&Src, 0, 0x400u);
v9 = recv(v5, Str, 0x3FFu, 0);
Str[v9] = 0;
if ( (v9 & 0x80000000u) != 0 )
{
CString::operator_("无数据");
goto LABEL_8;
}
v11 = strstr(Str, "\r\n\r\n");
if ( v11 )
{
v12 = v11 + 4;
v9 = strlen(v11 + 4);
}
else
{
v12 = Str;
}
if ( strstr(Str, "Transfer-Encoding: chunked") )
{
v13 = *v12;
v18 = 0;
v19 = 0;
v20 = 0;
v21 = 0;
if ( v13 )
{
v14 = &v18;
do
{
if ( v13 == '\r' )
break;
if ( v13 == '\n' )
break;
*(_BYTE *)v14 = v13;
v13 = v12[1];
v14 = (int *)((char *)v14 + 1);
++v12;
}
while ( v13 );
}
v15 = v12 + 2;
v9 = strtol((const char *)&v18, 0, 0x10u);
v16 = strlen(v15) + 1;
if ( (signed int)v9 > (signed int)(v16 - 1) )
v9 = v16 - 1;
strncpy(&Src, v15, v9);
}
else
{
strcpy(&Src, v12);
}
CString::operator_(&Src);
closesocket(v5);
WSACleanup();
LOBYTE(v25) = 0;
sub_515C81(&a2);
v25 = -1;
sub_515C81(&a3);
return v9;
}


可以看到在接受到数据后,查找strstr(Str, "Transfer-Encoding: chunked"),然后根据数据格式,查找长度字段,调用v9 = strtol((const char *)&v18, 0, 0x10u)获取长度,并未校验,如果长度字符串为-1,最终if ( (signed int)v9 > (signed int)(v16 - 1) )条件不成立,因此strncpy(&Src, v15, v9)拷贝的字节数为0xFFFFFFFF,最终导致拒绝服务。
同时还发现一个小bug。

signed int __cdecl sub_406810(int a1)
{
SOCKET v1; // esi@4
signed int v3; // edx@10
signed int i; // esi@10
char v5; // al@11
char *v6; // edx@17
const char *v7; // edi@17
int fromlen; // [sp+4h] [bp-11BCh]@8
SOCKET s; // [sp+8h] [bp-11B8h]@4
int v10; // [sp+Ch] [bp-11B4h]@10
struct sockaddr name; // [sp+10h] [bp-11B0h]@4
struct sockaddr from; // [sp+20h] [bp-11A0h]@9
char lParam[2048]; // [sp+30h] [bp-1190h]@9
struct WSAData WSAData; // [sp+830h] [bp-990h]@1
char v15[2048]; // [sp+9C0h] [bp-800h]@10
if ( WSAStartup(0x202u, &WSAData)
|| (_BYTE)WSAData.wVersion != 2
|| HIBYTE(WSAData.wVersion) != (_BYTE)WSAData.wVersion )
{
sub_5138E0((void *)a1, "监听初始化失败", 0, 0);
goto LABEL_37;
}
v1 = socket(2, 2, 0);
s = v1;
*(_DWORD *)&name.sa_data[2] = 0;
name.sa_family = 2;
*(_WORD *)&name.sa_data[0] = ntohs(10333u);
if ( v1 != -1 )
{
if ( bind(v1, &name, 16) )
{
sub_5138E0((void *)a1, "SOCKET 绑定失败", 0, 0);
WSACleanup();
return -1;
}
fromlen = 16;
while ( 1 )
{
do
{
memset(lParam, 0, sizeof(lParam));
memset(&from, 0, fromlen);
recvfrom(s, lParam, 2048, 0, &from, &fromlen);
}
while ( strcmp(cp, inet_ntoa(*(struct in_addr *)&from.sa_data[2])) );
memset(v15, 0, sizeof(v15));
sscanf(lParam, "%d&%s", &v10, v15);
memset(lParam, 0, sizeof(lParam));
v3 = 0;
for ( i = 0; i < (signed int)strlen(v15); ++i )
{
v5 = v15[i];
if ( v5 == '`' )
{
lParam[v3++] = '\r';
lParam[v3] = '\n';
}
else
{
lParam[v3] = v5;
}
++v3;
if ( v3 >= 2048 )
break;
}
if ( strcmp(lParam, "timeout_error") )
{
if ( strcmp(lParam, "time_policy_error") )
{
if ( strcmp(lParam, "max_flux_error") )
{
if ( strcmp(lParam, "max_hours_error") )
{
if ( strcmp(lParam, "remain_seconds_error") )
{
if ( strcmp(lParam, "remain_flux_error") )
{
if ( strcmp(lParam, "flux_switch_error") )
{
if ( strcmp(lParam, "timelong_switch_error") )
goto LABEL_33;
v6 = lParam;
v7 = "额定时长用尽,计费组已切换。";
}
else
{
v6 = lParam;
v7 = "额定流量用尽,计费组已切换。";
}
}
else
{
v6 = lParam;
v7 = (const char *)&unk_571FB0;
}
}
else
{
v6 = lParam;
v7 = (const char *)&unk_571FEC;
}
}
else
{
v6 = lParam;
v7 = (const char *)&unk_57202C;
}
}
else
{
v6 = lParam;
v7 = (const char *)&unk_57206C;
}
}
else
{
v6 = lParam;
v7 = (const char *)&unk_5720AC;
}
}
else
{
v6 = lParam;
v7 = (const char *)&unk_5720FC;
}
strcpy(v6, v7);
LABEL_33:
if ( !v10 )
{
SendMessageA(*(HWND *)(a1 + 28), 0x465u, 5u, 0);
SendMessageA(*(HWND *)(*(_DWORD *)(a1 + 596) + 28), 0x465u, 5u, 0);
}
SendMessageA(*(HWND *)(a1 + 28), 0x465u, 3u, (LPARAM)lParam);
}
}
sub_5138E0((void *)a1, "SOCKET创建失败", 0, 0);
LABEL_37:
WSACleanup();
return -1;
}


其中for循环处理过程存在bug,能够覆盖返回地址的一个字节。当v15的数据为'\x60' * 1023 + 'A' + '\x60'时就能触发此bug

for ( i = 0; i < (signed int)strlen(v15); ++i )
{
v5 = v15[i];
if ( v5 == 0x60 )
{
lParam[v3++] = '\r';
lParam[v3] = '\n';
}
else
{
lParam[v3] = v5;
}
++v3;
if ( v3 >= 2048 )
break;
}

漏洞证明:

依旧没有POC

修复方案:

版权声明:转载请注明来源 cssembly@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:11

确认时间:2013-04-27 22:37

厂商回复:

最新状态:

暂无