-
Notifications
You must be signed in to change notification settings - Fork 481
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added ObjectDataProvider gadget generation for MessagePack (Typeless) #146
Conversation
Also, I've had to update the ysoserial project to use .NET 4.7.2 as MessagePack isn't supported on v4.5.2. I'm not sure if this causes any other issues in the wider project by breaking other gadgets etc. The lack of unit tests means that this might require some input from somebody with a better understanding of the implications of this upgrade. |
I don't think there is anything against using .NET 4.7.2 but historically we have tried to keep the .NET Framework version as old as possible so it will be compatible with more applications. I haven't looked at the changes yet but is there perhaps a blog post explaining the technique you have used and explained here or do you plan to publish something about it? There is always a good story behind gadgets so I am interested to see what made you to come up with this whether it was a vulnerable target or just pure curiosity. @pwntester , shall we accept the changes as long as they work and perhaps apply any further improvements/structure changes later if required? |
I figured this and from my knowledge of the current set of gadgets I assumed that it wouldn't break anything we currently have.
I'm intending to publish a blog post on the technique I had to use and I can reference it in the additional reading section once I've put it together. There were several options for how to generate a working ObjectDataProvider gadget but most of them had some form of drawback.
I've seen a few examples in the wild of using MessagePack's 'Typeless' mode. My guess is that it's utilized as a more performant, smaller output version of BinaryFormatter. I've also seen several examples of threads where the OP has read the MSDN guidance on BinaryFormatter and people have suggested MessagePack as an alternative. I do have a potentially interesting MessagePack RCE in the works which doesn't use any of the gadgets available in ysoserial.net. I actually had to write a tool to process the assemblies of the application and look for a suitable gadget. I've not had a chance to work on a PoC for it yet and so it's still undisclosed, but it'll use the same approach I've had to use here. |
Just a point on improvements. I'd be interested to see if there's a better approach than the one I've taken. Obviously I'll hash out exactly why I took this approach in the blog post, but realistically I ran through quite a few options.
You get the idea. |
That sounds good to me. I took a quick look and the code looks ok too. @irsdl feel free to merge it after reviewing. |
The gadget works fine for me so all is ok. For improvement, it might be better to set the default encoding to base64 for them as the output contains byte data. This can be simply done by changing the ysoserial.net/ysoserial/Program.cs Line 564 in b236649
Also for the credit part, @NinesPsygnosis's name should be added to the These changes can be applied later so I will just merge the PR for now. |
I forgot to mention that the README also needs updating now. |
I'm actually already listed there (Dane Evans) as I also wrote the initial implementation for SharpSerializer gadget generation. |
Hi! Good job with this commit @NinesPsygnosis! TBH, I wanted to contribute with the MessagePack too, but it seems that I'm late to the party. It's a good thing though, because your code is much nicer than mine. I wanted to add one important thing about the MessagePack. MessagePack tends to strongly change its behaviour. Before version So, protected Dispatcher Dispatcher
{
get
{
return this._dispatcher;
}
set
{
if (this._dispatcher != value)
{
this._dispatcher = value;
}
}
} According to that, older versions of When we use the protected virtual void OnQueryFinished(object newData, Exception error, DispatcherOperationCallback completionWork, object callbackArguments)
{
Invariant.Assert(this.Dispatcher != null); // [1]
if (this.Dispatcher.CheckAccess())
{
this.UpdateWithNewResult(error, newData, completionWork, callbackArguments);
return;
}
... At internal static void Assert(bool condition)
{
if (!condition)
{
Invariant.FailFast(null, null);
}
} According to that, the To sum up, I guess that you should add a note that this gadgets work for Now the very good information - If you want to test the DoS on older versions - just changed the I'm not sure, but maybe you may want to implement a DoS gadget for the Cheers and keep up the good work! |
Hi @chudyPB thanks for the writeup. I've just tested the code I wrote and I can see that versions of MessagePack prior to 2.3.75 will not generate working payloads for the reason you described. I tried 2.2.113 but to no avail. It's cool to see you were also looking at this serializer. I should have a blog post up pretty soon which details my approach for generating the gadget this way, but for those familiar with this work the code should be self explanatory. I'm not sure whether ysoserial.net is intended to generate non-RCE payloads or not. There are some interesting gadgets I've found in the past which don't give you the ability to run arbitrary code, but allow for other interesting behaviours. Given the conventions of the tool (i.e. specifying commands, etc) I'm not sure they'd be included and I figure the same probably goes for denial-of-service payloads. I have an open PR that drastically reduces the necessary code to generate the ODP gadget, so I'll push another change to the README that references which versions this is applicable to. |
@chudyPB I'd like to include the details about the limitations in older versions of MessagePack in my blog post. Are you happy for me to include these? I'll add attribution if you like. |
Sure, you can do that. :) |
MessagePack when in 'Typeless' mode (using the TypelessContractlessStandardResolver) will serialize type information along with the data. It uses property setters to initialize the objects it's deserializing. This allows use of the ObjectDataProvider gadget to achieve code execution.
The approach I've used is somewhat odd, but is due to some limitations of being able to control the properties that are serialized. There doesn't appear to be a mechanism to exclude properties (or even private fields) from serialization when using Typeless mode, so my approach is to create a surrogate object graph of the ObjectDataProvider in a dynamic assembly, then use reflection to modify MessagePack's internal type cache so that the surrogate objects are serialized with the real AssemblyQualifiedNames of ObjectDataProvider, Process and ProcessStartInfo.
When deserializing this object graph it acts on the real ObjectDataProvider gadget and deserializes into a code execution scenario.