Welcome to Dark Area

Explore, Secure, Evolve – IT, Cybersecurity & Ethical Hacking

ATTENTION! Due to account issues, our mails are going into spam. Please, do not forget to check the spam folder for confirmation mails.

Register…

[CVE-2024-12741] - NI DAQExpress < 5.1 - Remote Code Execution

  • Thread starter Dark
  • Start date
  • Replies 0
  • Views 35
  • Important Notice

    This site provides security information, including vulnerabilities and exploits, exclusively for educational purposes. Users are responsible for ensuring their activities comply with all applicable laws and regulations. The site owner disclaims any liability for misuse of the content.

Dark

Owner

Joined
Mar 21, 2024
Messages
41

[CVE-2024-12741] - NI DAQExpress - Remote Code Execution

P.S> This content's original source: https://exploit7.tr/posts/daqexpress/

Product: NI DAQExpress < 5.1

Severity:
CVSS3 - 7.8
CVSS4 - 8.4


Explanation:


While reviewing the Daqexpress product, multiple deserialization vulnerabilities (XamlReader, BinaryFormatter) were discovered. Today, the focus will be on analyzing the BinaryFormatter vulnerability.

The application operates with multiple features, and the part of interest is the one that takes a project file from the user and processes it.



Deserialize:
20cnwux.png


1. It defines the BinaryFormatter class.
2. It base64 decodes the serializedValue string.
3. The DataValueSerializer class checks the CompressionMethod enum to determine whether the compression is "none" or "gzip". If the compression is "gzip", it decompresses it and then deserializes.
4. If the compression is None, it directly deserializes.


DataItem:
Parse
method will break down the arrays within the provided XML and send each part to the RecursiveParse method.


C#:
public bool Parse(XElement serializedArray, Array deserializedArray, long[] dimensionLengths, DataValueSerializer.CompressionMethod compression)
    {
        long[] array = new long[dimensionLengths.Length];
        this._elementGroups = serializedArray.Elements().ToArray<XElement>();
        this._groupIndex = 0;
        return this.RecursiveParse(array, dimensionLengths, 0, deserializedArray, compression);
    }

DataItem class takes specific data from us, including properties like AdaptToDiagramType,DataType,Compression, and IsBinary. The Compression section refers to the data we saw in the ParseElement class, which indicates what the compression type is, such as gzip. Also, the DataItem class is the class we will exploit.


C#:
public sealed class DataItem : DfirElement, ISortableDataItem
    {
        ...
        // Token: 0x17000320 RID: 800
        // (get) Token: 0x06000A3B RID: 2619 RVA: 0x00019E1B File Offset: 0x0001801B
        // (set) Token: 0x06000A3C RID: 2620 RVA: 0x00019E23 File Offset: 0x00018023
        public bool AdaptToDiagramType { get; set; }

        // Token: 0x17000321 RID: 801
        // (get) Token: 0x06000A3D RID: 2621 RVA: 0x00019E2C File Offset: 0x0001802C
        // (set) Token: 0x06000A3E RID: 2622 RVA: 0x00019E34 File Offset: 0x00018034
        public TryGetAcceptableAccessorTypeFunction AdaptToDiagramTypeBehavior { get; set; }

        // Token: 0x17000322 RID: 802
        // (get) Token: 0x06000A3F RID: 2623 RVA: 0x00019E3D File Offset: 0x0001803D
        // (set) Token: 0x06000A40 RID: 2624 RVA: 0x00019E45 File Offset: 0x00018045
        public IList<DataItemBindingInfo> BindingInfo { get; private set; }

        // Token: 0x17000323 RID: 803
        // (get) Token: 0x06000A41 RID: 2625 RVA: 0x00019E4E File Offset: 0x0001804E
        // (set) Token: 0x06000A42 RID: 2626 RVA: 0x00019E56 File Offset: 0x00018056
        public int BufferSize { get; set; }

        // Token: 0x17000324 RID: 804
        // (get) Token: 0x06000A43 RID: 2627 RVA: 0x00019E5F File Offset: 0x0001805F
        // (set) Token: 0x06000A44 RID: 2628 RVA: 0x00019E67 File Offset: 0x00018067
        public bool IsLatched { get; private set; }

        // Token: 0x17000325 RID: 805
        // (get) Token: 0x06000A45 RID: 2629 RVA: 0x00019E70 File Offset: 0x00018070
        // (set) Token: 0x06000A46 RID: 2630 RVA: 0x00019E78 File Offset: 0x00018078
        public string CompiledName { get; set; }

        // Token: 0x17000326 RID: 806
        // (get) Token: 0x06000A47 RID: 2631 RVA: 0x00019E81 File Offset: 0x00018081
        // (set) Token: 0x06000A48 RID: 2632 RVA: 0x00019E89 File Offset: 0x00018089
        public string ConnectorPaneName { get; private set; }

        // Token: 0x17000327 RID: 807
        // (get) Token: 0x06000A49 RID: 2633 RVA: 0x00019E92 File Offset: 0x00018092
        // (set) Token: 0x06000A4A RID: 2634 RVA: 0x00019E9A File Offset: 0x0001809A
        public IList<DataAccessor> DataAccessors { get; private set; }

        // Token: 0x17000328 RID: 808
        // (get) Token: 0x06000A4B RID: 2635 RVA: 0x00019EA3 File Offset: 0x000180A3
        public IList<Node> DependentNodes { get; }
 
        ...
 
        // Token: 0x040002CC RID: 716
        private NIType _dataType;

        // Token: 0x040002CD RID: 717
        private object _defaultValue;

        // Token: 0x040002CF RID: 719
        private DfirRoot _dfirRoot;
    }
}


Stack Trace:
C#:
NationalInstruments.SourceModel.Persistence.DataValueSerializer.BinaryArrayParser.ParseElement(string, DataValueSerializer.CompressionMethod) : IList @0600D896
        NationalInstruments.SourceModel.Persistence.DataValueSerializer.BinaryArrayParser.RecursiveParse(long[], long[], int, Array, DataValueSerializer.CompressionMethod) : bool @0600D895
                NationalInstruments.SourceModel.Persistence.DataValueSerializer.BinaryArrayParser.Parse(XElement, Array, long[], DataValueSerializer.CompressionMethod) : bool @0600D894
                        NationalInstruments.SourceModel.Persistence.DataValueSerializer.ParseDataValueAsXmlHierarchy(Element, DataTypeReferenceTable, NIType, XElement, out object) : bool @060056CB
                                NationalInstruments.SourceModel.Persistence.DataValueSerializer.ParseDataValue(Element, DataTypeReferenceTable, NIType, XElement, out object) : bool @060056C4
                                        NationalInstruments.SourceModel.Persistence.DataValueParserContext.ParseDataValue(out object) : bool @0600555A
                                        NationalInstruments.SourceModel.Persistence.DataValueSerializer.FixupDataValue(Element, DataTypeReferenceTable, SerializablePropertySymbol, XDocument, ICompositionHost) : void @060056C2
                                                NationalInstruments.SourceModel.Persistence.DataValueSerializer.TryParse(SerializablePropertySymbol, IElementPropertyParser, out object) : bool @060056C0


Important Part:
C#:
private void FixupDataValue(Element owner, DataTypeReferenceTable typeTable, SerializablePropertySymbol propertySymbol, XDocument xDoc, ICompositionHost host)
        {
            IDataTypeReferenceOwner dataTypeReferenceOwner = owner as IDataTypeReferenceOwner;
            if (dataTypeReferenceOwner == null)
            {
                throw new InvalidOperationException("The owner must implement the IDataTypeReferenceOwner interface");
            }
            NIType dataType = this.GetDataType(dataTypeReferenceOwner, propertySymbol);
            object obj = null;
            XAttribute xattribute = xDoc.Root.Attribute("CookieReference");
            if (xattribute != null)
            {
                string value = xattribute.Value;
                if (value != "null")
                {
                    ICookieJar sharedExportedValue = host.GetSharedExportedValue<ICookieJar>();
                    XAttribute xattribute2 = xDoc.Root.Attribute("CookieJar");
                    if (xattribute2 != null && Guid.Parse(xattribute2.Value) != sharedExportedValue.CookieJarId)
                    {
                        throw new InvalidParseException("Copying clipboard contents with cookie references isn't supported between different processes.");
                    }
                    Cookie cookie = sharedExportedValue.GetCookie(value);
                    if (cookie != null)
                    {
                        obj = DataCopyHelper.DeepCopy<object>(cookie.Thing);
                    }
                }
            }
            else
            {
                DataValueSerializer.ParseDataValue(owner, typeTable, dataType, xDoc.Root, out obj);
            }
            owner.SetPropertyValue(propertySymbol, obj);
        }

The key part to pay attention to is the CookieReference block. If we leave this section empty, it will redirect us to the ParseDataValue method, and the remaining trace operations will continue from there.


C#:
internal static bool ParseDataValue(Element owner, DataTypeReferenceTable typeTable, NIType currentType, XElement currentElement, out object dataValue)
        {
            XText xtext = currentElement.Nodes().OfType<XText>().FirstOrDefault<XText>();
            string text = ((xtext != null) ? xtext.Value : null);
            if (DataValueSerializer.ParseSimpleDataValue(currentType, text, out dataValue))
            {
                return true;
            }
            XElement xelement = currentElement.Elements().FirstOrDefault<XElement>();
            if (xelement != null && DataValueSerializer.ParseDataValueAsXmlHierarchy(owner, typeTable, currentType, xelement, out dataValue))
            {
                return true;
            }
            throw new InvalidParseException(string.Format(CultureInfo.InvariantCulture, "Failed to parse data value {0} for data type {1}.", currentElement, currentType.AsFormattedString));
        }


Exploit Part:
XML:
<DataItem AdaptToDiagramType="True" DataType="Boolean[]" Id="1" Name="" xmlns="http://www.ni.com/MocCommon">
        <p.DefaultValue>
            <Array Lengths="2" IsBinary="" Compression="GZip/None">
                <Exploit7>[base64 (none) or Gzip data]</Exploit7>
            </Array>
        </p.DefaultValue>
</DataItem>


Exploit Video:
 
Top