Exploiting the Xamarin.Android DLL hijack vulnerability

Introduction

Last week a security advisory was posted to the Full-Disclosure mailing list concerning a vulnerability in Xamarin.Android. Xamarin.Android allows the creation of Android apps in C#. This vulnerability allows any Android app with write access to external storage to create a malicious DLL file that will be executed by an affected app. This issue is addressed in Xamarin 5.1; vulnerable apps need to be recompiled with Xamarin version 5.1 or newer in order to resolve this vulnerability.

This article explains how this issue can be exploited in order to execute arbitrary code. A vulnerable Android app needs to be found in order to test this issue. This is left as a reader's exercise.

Popping calc

The ultimate goal for exploit writers is of course starting calculator. Naturally, the proof of concept from this article will also try to start calculator. For convenience it is assumed that Calculator 2 (com.android.calculator2) is installed on the test device. The proof of concept will run the following C# code:

Android.Content.Intent intent = new Android.Content.Intent("android.intent.action.MAIN");
intent.SetComponent(new Android.Content.ComponentName("com.android.calculator2", 
	"com.android.calculator2.Calculator"));
StartActivity(intent);

In order to execute this code, a modified version of the Mono.Android.dll Assembly is created containing the above code. This version is copied to the test device targeting the vulnerable app. Read on for the details how such a modified Assembly can be created.

Modifying Mono.Android.dll

To modify Xamarin Assemblies Reflexil can be used. Reflexil is an assembly editor and runs as a plug-in for Reflector, ILSpy and JustDecompile. JustDecompile is used in this article.

First extract all DLLs from the vulnerable app's APK. Open both Mono.Android.dll and System.dll. Make sure the Reflexil plug-in is loaded.

Reflexil allows us to add, change or delete individual CIL instructions, but it can also compile C# code. This latter option is convenient, but it also has some limitations. To overcome some of these limitations, a new class is created that is used to compile the C# code. This new class is instantiated from the location where this code needs to be injected. To create this class follow these steps:

Right click on Mono.Android, from the Reflexil menu choose "Inject class". Pick an Item name and make sure that the Base type is Object.

The new class is not immediately visible, save the changes and reload the Assembly: right click on Mono.Android and choose "Save and reload" from the Reflexil menu.

Next locate the new class in the Mono.Android Assembly. Right click on this class and choose "Inject constructor" from the Reflexil menu. Click Ok & Save and reload again.

Since StartActivity() is called in the calculator payload, an Activity instance is required. The Activity can be passed as parameter to the constructor method of the injected class. Add this parameter to the constructor method. Locate the newly created constructor and go to the Variables tab.

Create a new parameter by right clicking in the Variables tab and choosing "Create new...". Set the Name to "target", Type Scope to "-> Type Reference" and Type to "Android.App.Activity" that can be found in Mono.Android. Click on Append, Save and reload.

Now add the C# code. Locate the constructor again and open the Instructions tab. Right click on this tab and choose "Replace all with code...". Copy & paste the following code in the constructor method.

Android.Content.Intent intent = new Android.Content.Intent("android.intent.action.MAIN");
intent.SetComponent(new Android.Content.ComponentName("com.android.calculator2", 
	"com.android.calculator2.Calculator"));
target.StartActivity(intent);

Click the Compile button, if all goes well the compiled CIL instructions will show up in the instructions tab. Click on Ok to commit the changes, Save and reload.

The class containing the payload is done. It needs to be instantiated and passed an Activity instance. A good place to do this is within an Activity. Find the class Android.App.Activity in Mono.Android and click on the OnResume() method. Unfortunately the Compiler option can't be used for this method as this will throw a number of errors. Instead add the CIL instructions manually using the Instructions tab. Right click on the Instructions tab and choose "Create...". Add the following instructions & Save and reload (replace Securify.Payload with your class name):

ldarg.0	
newobj	System.Void Securify.Payload::.ctor(Android.App.Activity)
pop

Testing the code

The modified Mono.Android.dll Assembly is ready for testing. The DLL can be copied using ADB (make sure to replace package with that of the vulnerable app):

adb push Mono.Android.Patched.dll \
	/storage/sdcard0/Android/data/**package**/files/.__override__/Mono.Android.dll

Start the app, if all goes well the app will start first and a couple of moments later calculator will be started. If calculator does not start for some reason, check whether an error is written to the device log.

adb logcat | grep mono

Questions or feedback?