diff --git a/impacket/dcerpc/v5/dcom/wmi.py b/impacket/dcerpc/v5/dcom/wmi.py index 0b3cb80fc1..0ec06156d4 100644 --- a/impacket/dcerpc/v5/dcom/wmi.py +++ b/impacket/dcerpc/v5/dcom/wmi.py @@ -2359,9 +2359,9 @@ def setClassName(self, value): else: raise Exception("Cannot set class name for an instance object.") - def addNewAttribute(self, name, type, default_value=None): + def addNewAttribute(self, name, type, default_value=None, qualifiers=None): if not self.encodingUnit['ObjectBlock'].isInstance(): - self.__new_attributes.append((name, type, default_value)) + self.__new_attributes.append((name, type, default_value, qualifiers or [])) setattr(self, name, default_value) else: raise Exception("Cannot add new attribute to an instance object.") @@ -2428,24 +2428,38 @@ def __ndEntry(index, null_default, inherited_default): # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wmio/ed436785-40fc-425e-ad3d-f9200eb1a122 return (bool(null_default) << 1 | bool(inherited_default)) << (2 * index) - def __createCimTypeQualifierSet(self, heap, propertyInfo): + def __createCimTypeQualifierSet(self, heap, propertyInfo, qualifiers=None): propertyInfo['PropertyQualifierSet'] = b'' + # CIMTYPE qualifier (mandatory) qualifierSet = QUALIFIER_SET() - qualifier = QUALIFIER() - qualifier['QualifierName'] = DICTIONARY_REFERENCE_TO_VALUE['CIMTYPE'] | 0x80000000 - qualifier['QualifierFlavor'] = 0 #WBEM_FLAVOR_FLAG_PROPAGATE_O_INSTANCE | WBEM_FLAVOR_FLAG_PROPAGATE_O_DERIVED_CLASS - qualifier['QualifierType'] = CIM_TYPE_ENUM.CIM_TYPE_STRING.value - qualifier.structure = (('QualifierValue', CIM_TYPES_REF[qualifier['QualifierType'] & (~CIM_ARRAY_FLAG)]),) - - qualifierSet['Qualifier'] = qualifier.getData() # for EncodingLength calculation + cimtype_qual = QUALIFIER() + cimtype_qual['QualifierName'] = DICTIONARY_REFERENCE_TO_VALUE['CIMTYPE'] | 0x80000000 + cimtype_qual['QualifierFlavor'] = 0 #WBEM_FLAVOR_FLAG_PROPAGATE_O_INSTANCE | WBEM_FLAVOR_FLAG_PROPAGATE_O_DERIVED_CLASS + cimtype_qual['QualifierType'] = CIM_TYPE_ENUM.CIM_TYPE_STRING.value + cimtype_qual.structure = ( + ('QualifierValue', CIM_TYPES_REF[cimtype_qual['QualifierType'] & (~CIM_ARRAY_FLAG)]), + ) + + # Extra qualifiers + extra_data = b'' + for qname in (qualifiers or []): + q = QUALIFIER() + q['QualifierName'] = DICTIONARY_REFERENCE_TO_VALUE[qname] | 0x80000000 + q['QualifierFlavor'] = 0 + q['QualifierType'] = CIM_TYPE_ENUM.CIM_TYPE_BOOLEAN.value + q.structure = ( + ('QualifierValue', CIM_TYPES_REF[CIM_TYPE_ENUM.CIM_TYPE_BOOLEAN.value & (~CIM_ARRAY_FLAG)]), + ) + q['QualifierValue'] = 0xFFFF + extra_data += q.getData() + + # Assemble QUALIFIER_SET + qualifierSet['Qualifier'] = cimtype_qual.getData() + extra_data qualifierSet['EncodingLength'] = len(qualifierSet.getData()) - # now we set real value for QualifierValue - qualifier['QualifierValue'] = len(heap) + len(propertyInfo) + len(qualifierSet.getData()) - - # set the final qualifier to QUALIFIER_SET - qualifierSet['Qualifier'] = qualifier.getData() + cimtype_qual['QualifierValue'] = len(heap) + len(propertyInfo) + len(qualifierSet.getData()) + qualifierSet['Qualifier'] = cimtype_qual.getData() + extra_data cimTypeString = ENCODED_STRING() cimTypeString['Character'] = CIM_TYPE_TO_NAME[propertyInfo['PropertyType']] @@ -2471,7 +2485,8 @@ def marshalMe(self): propRecord = properties[propName] itemValue = getattr(self, propName) propIsInherited = propRecord['inherited'] - print("PropName %r, Value: %r" % (propName,itemValue)) + if logging.getLogger().level == logging.DEBUG: + LOG.debug(f"PropName {propName!r}, Value: {itemValue!r}") pType = propRecord['type'] & (~(CIM_ARRAY_FLAG|Inherited)) if propRecord['type'] & CIM_ARRAY_FLAG: @@ -2590,7 +2605,7 @@ def marshalMe(self): sorted_attrs = sorted(self.__new_attributes, key=lambda x:x[0]) for i, attr in enumerate(sorted_attrs): - attribute_name, attribute_type, attribute_default_value = attr + attribute_name, attribute_type, attribute_default_value, attribute_qualifiers = attr propIndex = existingPropCount + i # property name @@ -2606,7 +2621,7 @@ def marshalMe(self): propertyInfo['DeclarationOrder'] = propIndex propertyInfo['ValueTableOffset'] = len(valueTable) propertyInfo['ClassOfOrigin'] = 0 # TODO - qualifierSet, cimType = self.__createCimTypeQualifierSet(cHeap, propertyInfo) + qualifierSet, cimType = self.__createCimTypeQualifierSet(cHeap, propertyInfo, attribute_qualifiers) propertyInfo['PropertyQualifierSet'] = qualifierSet cHeap += propertyInfo.getData() cHeap += cimType.getData() diff --git a/tests/SMB_RPC/test_wmi.py b/tests/SMB_RPC/test_wmi.py index af06bb3dd9..421933537d 100644 --- a/tests/SMB_RPC/test_wmi.py +++ b/tests/SMB_RPC/test_wmi.py @@ -226,7 +226,7 @@ def test_IWbemServices_PutClass(self): try: dummyClass, _ = iWbemServices.GetObject('') dummyClass.setClassName(className) - dummyClass.addNewAttribute(attrName, wmi.CIM_TYPE_ENUM.CIM_TYPE_STRING, attrValue) + dummyClass.addNewAttribute(attrName, wmi.CIM_TYPE_ENUM.CIM_TYPE_STRING, attrValue, qualifiers=["key", "read", "write"]) _ = iWbemServices.PutClass(dummyClass.marshalMe(), wmi.WBEM_FLAG_CREATE_ONLY) createdClass,_ = iWbemServices.GetObject(className) @@ -244,11 +244,11 @@ def test_IWbemServices_PutClass_update_adds_property(self): try: dummyClass, _ = iWbemServices.GetObject('') dummyClass.setClassName(className) - dummyClass.addNewAttribute("Code", wmi.CIM_TYPE_ENUM.CIM_TYPE_STRING, "EN") + dummyClass.addNewAttribute("Code", wmi.CIM_TYPE_ENUM.CIM_TYPE_STRING, "EN", qualifiers=["key", "read", "write"]) iWbemServices.PutClass(dummyClass.marshalMe(), wmi.WBEM_FLAG_CREATE_ONLY) fetchedClass, _ = iWbemServices.GetObject(className) - fetchedClass.addNewAttribute("Number", wmi.CIM_TYPE_ENUM.CIM_TYPE_UINT32, 123) + fetchedClass.addNewAttribute("Number", wmi.CIM_TYPE_ENUM.CIM_TYPE_UINT32, 123, qualifiers=["read", "write"]) iWbemServices.PutClass(fetchedClass.marshalMe(), wmi.WBEM_FLAG_UPDATE_ONLY) roundTrip, _ = iWbemServices.GetObject(className)