liang's profile阿斯提亚神殿——梦幻天子's skyPhotosBlogLists Tools Help
    May 10

    The ancient IIS vulnerability(MS01-044)

    It's a famous IIS vulnerability whose Exploit code is called "the red code".  Due to its great reputation, I did a simple analysis with the bug code(between the lines):

    idq!CVariableSet::AddExtensionControlBlock:
    6e90065c mov eax,0x6e906af8
    6e900661 call idq!_EH_prolog (6e905c30)
    6e900666 sub esp,0x1d0
    6e90066c push ebx
    6e90066d xor eax,eax
    6e90066f push esi
    6e900670 push edi
    6e900671 mov [ebp-0x24],ecx
    6e900674 mov [ebp-0x2c],eax
    6e900677 mov [ebp-0x28],eax
    6e90067a mov [ebp-0x4],eax
    6e90067d mov eax,[ebp+0x8]; the parameter "EXTENSION_CONTROL_BLOCK"
    .
    .
    .
    6e9006b7 mov esi,[eax+0x64];offset "lpszQueryString"
    6e9006ba or ecx,0xffffffff
    6e9006bd mov edi,esi
    .
    .
    .
    6e9007b7 push 0x3d;ascii '='
    6e9007b9 push edi
    6e9007ba mov [ebp-0x18],edi
    6e9007bd call dword ptr [idq!_imp__strchr (6e8f111c)]
    6e9007c3 mov esi,eax
    6e9007c5 pop ecx
    6e9007c6 test esi,esi
    6e9007c8 pop ecx
    6e9007c9 je 6e9008d2
    6e9007cf sub eax,edi
    6e9007d1 push 0x26
    6e9007d3 push edi
    6e9007d4 mov [ebp-0x20],eax ;store the address of '='
    6e9007d7 inc esi
    6e9007d8 call dword ptr [idq!_imp__strchr (6e8f111c)]
    6e9007de mov edi,eax
    6e9007e0 pop ecx
    6e9007e1 test edi,edi
    6e9007e3 pop ecx
    6e9007e4 jz 6e9007fa
    6e9007e6 cmp edi,esi
    6e9007e8 jnb 6e9007f0
    6e9007ea inc edi
    6e9007eb jmp 6e9008e4
    6e9007f0 mov eax,edi
    6e9007f2 sub eax,esi
    6e9007f4 inc edi
    6e9007f5 mov [ebp-0x14],eax
    6e9007f8 jmp 6e900804
    6e9007fa mov eax,[ebp-0x10]
    6e9007fd sub eax,esi
    6e9007ff add eax,ebx
    6e900801 mov [ebp-0x14],eax
    6e900804 cmp dword ptr [ebp-0x20],0x190 ; key comparison
    //it shows that the distance between the beginning of lpszQueryString and the address of '=' must not greater than 0x190(400)
    6e90080b jb 6e900828

    /* case greater than 0x190, throw the exception
    6e90080d mov eax,0x80040e14
    6e900812 xor ecx,ecx
    6e900814 mov [ebp-0x3c],eax
    6e900817 lea eax,[ebp-0x3c]
    6e90081a push 0x6e9071b8
    6e90081f push eax
    6e900820 mov [ebp-0x38],ecx
    6e900823 call idq!_CxxThrowException (6e905c36)
    */
    /* case lower than 0x190

    6e900828 mov eax,[ebp+0x8]
    6e90082b push dword ptr [eax+0x8]
    6e90082e lea eax,[ebp-0x1dc];about 476-bytes long from the returning address
    6e900834 push eax
    6e900835 lea eax,[ebp-0x20]
    6e900838 push eax
    6e900839 push dword ptr [ebp-0x18]
    6e90083c call idq!DecodeURLEscapes (6e9060be); this function convert the original ANSI string to the Unicode version and stored in [ebp-0x1dc]
    {
    query!DecodeURLEscapes:
    68cc697e mov eax,0x68d667cc
    68cc6983 call query!_EH_prolog (68d4b250)
    68cc6988 sub esp,0x30
    68cc698b push ebx
    68cc698c push esi
    68cc698d xor eax,eax
    68cc698f push edi
    68cc6990 mov edi,[ebp+0x10]
    68cc6993 mov [ebp-0x3c],eax
    68cc6996 mov [ebp-0x38],eax
    68cc6999 mov ecx,[ebp+0xc]
    68cc699c mov [ebp-0x4],eax
    68cc699f mov [ebp-0x18],eax
    68cc69a2 mov ecx,[ecx];distance
    68cc69a4 cmp ecx,eax
    68cc69a6 mov [ebp-0x10],ecx; store the "distance" varible to the local stack
    68cc69a9 jz query!DecodeURLEscapes+0x99 (68cc6a17)
    68cc69ab mov esi,[ebp+0x8]; the address of lpszQueryString
    68cc69ae mov eax,ecx
    68cc69b0 inc eax
    68cc69b1 mov [ebp-0x14],eax ;distance+1
    68cc69b4 movzx bx,byte ptr [esi]
    68cc69b8 and dword ptr [ebp-0x34],0x0; set 4 bytes of the local stack to 0
    68cc69bc cmp bx,0x2b
    68cc69c0 jne query!DecodeURLEscapes+0xdf (68cc6a5d)
    68cc69c6 push 0x20
    68cc69c8 pop ebx
    68cc69c9 inc esi
    68cc69ca xor eax,eax
    68cc69cc cmp [ebp-0x34],eax
    68cc69cf jnz query!DecodeURLEscapes+0x79 (68cc69f7)
    68cc69d1 cmp bx,0x80
    68cc69d6 jb query!DecodeURLEscapes+0x79 (68cc69f7)
    68cc69d8 cmp [ebp-0x18],eax
    68cc69db jnz query!DecodeURLEscapes+0x79 (68cc69f7)
    68cc69dd cmp [ebp-0x3c],eax
    68cc69e0 jnz query!DecodeURLEscapes+0x73 (68cc69f1)
    68cc69e2 mov eax,[ebp-0x14]
    68cc69e5 push eax
    68cc69e6 mov [ebp-0x38],eax
    68cc69e9 call query!ciNew (68d4a977)
    68cc69ee mov [ebp-0x3c],eax
    68cc69f1 mov eax,[ebp-0x3c]
    68cc69f4 mov [ebp-0x18],eax
    68cc69f7 mov eax,[ebp-0x18]
    68cc69fa test eax,eax
    68cc69fc jz query!DecodeURLEscapes+0x88 (68cc6a06)
    68cc69fe mov [eax],bl
    68cc6a00 inc eax
    68cc6a01 mov [ebp-0x18],eax
    68cc6a04 jmp query!DecodeURLEscapes+0x8d (68cc6a0b)
    68cc6a06 mov [edi],bx
    68cc6a09 inc edi
    68cc6a0a inc edi
    68cc6a0b dec dword ptr [ebp-0x10] ; decrease the length(400 bytes in maximum)
    68cc6a0e dec dword ptr [ebp-0x14]
    68cc6a11 cmp dword ptr [ebp-0x10],0x0 ; loop until [ebp-0x10] is 0
    68cc6a15 jnz query!DecodeURLEscapes+0x36 (68cc69b4)
    68cc6a17 test eax,eax
    68cc6a19 jz query!DecodeURLEscapes+0xb4 (68cc6a32)
    68cc6a1b sub eax,[ebp-0x3c]
    68cc6a1e push eax
    68cc6a1f push edi
    68cc6a20 push eax
    68cc6a21 push dword ptr [ebp-0x3c]
    68cc6a24 push 0x1
    68cc6a26 push dword ptr [ebp+0x14]
    68cc6a29 call dword ptr [query!_imp__MultiByteToWideChar (68c61264)]
    68cc6a2f lea edi,[edi+eax*2]
    68cc6a32 and word ptr [edi],0x0
    68cc6a36 sub edi,[ebp+0x10]
    68cc6a39 mov eax,[ebp+0xc]
    68cc6a3c push dword ptr [ebp-0x3c]
    68cc6a3f or dword ptr [ebp-0x4],0xffffffff
    68cc6a43 sar edi,1
    68cc6a45 mov [eax],edi
    68cc6a47 call query!ciDelete (68d4a9ae)
    68cc6a4c mov ecx,[ebp-0xc]
    68cc6a4f pop edi
    68cc6a50 pop esi
    68cc6a51 mov fs:[00000000],ecx
    68cc6a58 pop ebx
    68cc6a59 leave
    68cc6a5a ret 0x10
    }
    Now, the whole thing comes to light: We could see that DecodeURLEscapes function calculates  the source buffer from the ANSI version string to Unicode version string(also do some filtering work), and then copy the Unicode version to the local stack in AddExtensionControlBlock function, which is 476 bytes faraway from ebp. Unfortunately, in this case DecodeURLEscapes converts at most 400 bytes ANSI chars to Unicode version, which means the output buffer should be as big as 800 bytes, otherwise a buffer overflow attacking could happen.
    An attack could sent an HTTP request in which contains a crafted URL to the IIS Server, the flawed module of IIS then parses it and results in buffer overflow.
    One key problem is: How to build a special shellcode which could be executed successfully after it is converted to unicode version?
    Did you see a shellcode look like this "XX 00 YY 00 ZZ 00", or every byte in it is greate than 0x80?  I have never seen. :(
    However, the man called "yuange" realized this. See his article "widechar的字符串缓冲溢出攻击技术" for reference.