|
Hi
One question - is it impossible to safe guard an application hosting third party dll?
See this thread, even if third party dll loaded into separate AppDomain, it can still access AppDomain.Current.Get/SetData[^]
In addition to AppDomain.Current.Get/SetData, can third party examine application memory. For example, hosting application may contain a secret/private key in some application context, which is used to decrypt communications or licensing file. Even if private key is not placed in AppDomain.Current.Get/SetData, is it possible for third party dll to ... perhaps "reflect" on the process memory foot print and extract the private key?
If the answer is yes - then it follows really the moment you load a third party dll into your own process, you cannot be sure if your process has been compromised?
I think security is even more important than say process isolation safe guarding against crashes in third party dll.
Thanks
NOTE: This is NOT a question on CAS[^] as setting permissions/evidence doesn't has anything to do with access to AppDomain from third party dll[^]
Also, this is not a question on serializing access to a singleton instance object[^]
dev
modified on Thursday, March 3, 2011 5:41 AM
|
|
|
|
|
devvvy wrote: In addition to AppDomain.Current.Get/SetData, can third party examine application memory.
Yes. Wouldn't be worth the effort though. I'm running Linux, Windows-applications are executed under Wine, .NET applications are run under Mono - and I can access the source-code of the VM if need be.
devvvy wrote: If the answer is yes - then it follows really the moment you load a third party dll into your own process, you cannot be sure if your process has been compromised?
You cannot even be sure if you don't load any external code; only if you have complete control over the environment.
I are Troll
|
|
|
|
|
"can third party examine application memory."
> I know reflection can enumerate types of assemblies. I also know if you pass in any object (For example, a LicenseController sitting in AppDomain.Current.Get/Set), reflection can basically enumerage types/properties (set/get any "private" members and methods!). So basically anything sitting in AppDomain.Current.Get/Set is UNSECURED.
One further question out of curiosity - can third party dll can a raw byte[] image of process memory...?
"and I can access the source-code of the VM if need be."
> Access source code? Even if I use an obfuscator..!?
So all this jazz about AppDomain are *practically useless* from security stand point. I've also tried to throw an exception from code from another appDomain, it crashes the whole app (see below).
Sounds like all theories surrounding appDomain completely b*llsh*t!
<br />
using System;<br />
using System.Collections.Generic;<br />
using System.Linq;<br />
using System.Text;<br />
<br />
using System.Threading;<br />
using System.Reflection;<br />
using System.Security.Policy;<br />
<br />
using UserUtil;<br />
using SimpleUtil;<br />
<br />
namespace SimpleTest<br />
{<br />
class Program<br />
{<br />
public const string KEY1 = "KEY1";<br />
public static AppDomain UserDomain = null;<br />
public static SimpleUtil.IServiceProvider UserProvider = null;<br />
<br />
static void Main(string[] args)<br />
{<br />
Assembly UserAssembly = null;<br />
Object oProvider = null;<br />
Thread t = null;<br />
<br />
try<br />
{<br />
AppDomain.CurrentDomain.SetData(KEY1, "PrivateKey");<br />
<br />
UserDomain = AppDomain.CreateDomain("UserDomain");<br />
UserDomain.SetData(KEY1, "Sh*t!");<br />
<br />
UserAssembly = Assembly.LoadFrom("UserUtil.dll");<br />
<br />
oProvider = UserDomain.CreateInstanceFrom("UserUtil.dll", "UserUtil.ServiceProvider").Unwrap();<br />
<br />
if (oProvider != null)<br />
{<br />
if (oProvider is SimpleUtil.IServiceProvider)<br />
{<br />
UserProvider = (SimpleUtil.IServiceProvider)oProvider;<br />
<br />
t = new Thread(new ParameterizedThreadStart(Program.AsyncDoWork));<br />
t.Start("Calling UserProvider.DoWork");<br />
}<br />
}<br />
<br />
while (true)<br />
{<br />
Console.Write(".");<br />
Thread.Sleep(1000 * 5);<br />
}<br />
}<br />
catch (Exception Ex)<br />
{<br />
Console.WriteLine(Ex.Message);<br />
}<br />
<br />
return;<br />
}<br />
<br />
public static void AsyncDoWork(object Arg)<br />
{<br />
string Message = null;<br />
Message = (string)Arg;<br />
UserProvider.DoWork(Message); << If inside third party "DoWork" throws an exception, it'd crash the hosting app even it's instantiated from different AppDomain! Also it can access AppDomain.Current.GetData("SomeSecret"). On these two reasons - all this talk about AppDomain isolation are quite pointless.<br />
return;<br />
}<br />
}<br />
}<br />
dev
|
|
|
|
|
devvvy wrote: can third party dll can a raw byte[] image of process memory
Yes/No. Most games that were created before the .NET era were cracked, despite some huge investments in copy-protection. It's not doable to reverse-engineer the entire code, but that's rarely done at all - bypassing the protection or getting the password to the database is often enough.
devvvy wrote: So all this jazz about AppDomain are *practically useless* from security stand point. I've also tried to throw an exception from code from another appDomain, it crashes the whole app (see below).
Sounds like all theories surrounding appDomain completely b*llsh*t!
Again, yes and no. An AppDomain isn't a new security-feature, it's an isolationlevel for applications. One that can be unloaded, if desired. It also means that I can execute (potentially malicious) code in a sandboxed environment[^], increasing my overall security. The code in that sandbox is restricted in what it can and cannot do.
I'm running Linux, and I have the source-code to the Operating System, as well as the Mono source-code. It'd be some work, but it could be used to backtrack what API's you're calling - even the paramaters that you pass aren't safe from prying eyes.
devvvy wrote: all this talk about AppDomain isolation are quite pointless
Depends on what you wants it for, and how secure you need to be. Do you need to prevent an ordinary user from making modifications? Prevent someone from seeing the users' data? Or are you creating an application for a nuclear plant?
In the first case, encryption would suffice. In the second case, obfuscation would suffice. In the last case, you simply need total control over the machine - then you'd only be vulnerable for stuxnet
I are Troll
|
|
|
|
|
Hello I tried out your advice - MSDN article on sand boxing third party dll [^]
The following code created new AppDomain for third party dll, invoke it and found out that AppDomain.Current.GetData[KEY1] refers to that of the "New Domain" (not old AppDomain of hosting app)
But again, two problems still remains:
a. third party can still access all AppDomain - see this.[^]
(But if MSDN is correct, GetCallingAssembly requires ReflectionPermission as well - so DENY ReflectionPermission is very key)[^]
b. third party library can simply retrieves hosting types by GetCallingAssembly
<br />
public void DoWork(string Message)<br />
{<br />
<br />
Type[] Types = Assembly.GetCallingAssembly().GetTypes();<br />
if (Types != null)<br />
{<br />
foreach (Type t in Types)<br />
{<br />
Console.WriteLine("Detected type: " + t.FullName);<br />
}<br />
}<br />
c. Am I doing it right below on how to DENY ReflectionPermission? (By setting PermissionState.None)
Anyway here's my full test code.
<br />
***** Program.cs *****<br />
using System;<br />
using System.IO;<br />
using System.Collections.Generic;<br />
using System.Linq;<br />
using System.Text;<br />
<br />
using System.Threading;<br />
<br />
using System.Reflection;<br />
using System.Security;<br />
using System.Security.Policy;<br />
using System.Security.Permissions;<br />
<br />
using UserUtil;<br />
using SimpleUtil;<br />
<br />
namespace TestAppDomain<br />
{<br />
class Program <br />
{<br />
public const string KEY1 = "KEY1";<br />
public static AppDomain UserDomain = null;<br />
<br />
static void Main(string[] args)<br />
{<br />
string UntrustedThirdPartyDir = @"..\..\UserUtil\UserUtil\bin\Debug";<br />
string ThirdPartyDll = "UserUtil.dll";<br />
string ThirdPartyServiceFullyQualifiedName = "UserUtil.ServiceProvider";<br />
<br />
Assembly UserAssembly = null;<br />
<br />
Object oProvider = null;<br />
SimpleUtil.IServiceProvider UserProvider = null;<br />
<br />
try<br />
{<br />
#region Sandbox preparation<br />
AppDomainSetup AdSetup = new AppDomainSetup();<br />
AdSetup.ApplicationBase = Path.GetFullPath(UntrustedThirdPartyDir);<br />
<br />
PermissionSet PermSet = new PermissionSet(PermissionState.None);<br />
PermSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));<br />
<br />
<br />
ReflectionPermission RefPerm = new ReflectionPermission(PermissionState.None);<br />
PermSet.AddPermission(RefPerm);<br />
<br />
StrongName FullTrustAssembly = typeof(Program).Assembly.Evidence.GetHostEvidence<StrongName>();<br />
#endregion<br />
<br />
<br />
UserDomain = AppDomain.CreateDomain(<br />
"UserDomain", null, AdSetup, PermSet, FullTrustAssembly<br />
);<br />
<br />
AppDomain.CurrentDomain.SetData(KEY1, "PrivateKey");<br />
UserDomain.SetData(KEY1, "NoProblem!");<br />
<br />
oProvider = Activator.CreateInstanceFrom(<br />
UserDomain, ThirdPartyDll, ThirdPartyServiceFullyQualifiedName<br />
).Unwrap();<br />
<br />
#region No need for this...<br />
#endregion<br />
<br />
#region No need for this either ..<br />
#endregion<br />
<br />
if (oProvider != null)<br />
{<br />
if (oProvider is SimpleUtil.IServiceProvider)<br />
{<br />
UserProvider = (SimpleUtil.IServiceProvider)oProvider;<br />
<br />
Object[] parameters = { "Calling UserProvider.DoWork" };<br />
<br />
while (true)<br />
{<br />
#region OPTION 1: prints out "UserUtil.DoWork - secret=NoProblem!"<br />
#endregion<br />
<br />
#region OPTION 2: prints out "UserUtil.DoWork - secret=NoProblem!"<br />
UserProvider.GetType().GetMethod("DoWork").Invoke(UserProvider, parameters);<br />
#endregion<br />
}<br />
}<br />
}<br />
}<br />
catch (Exception Ex)<br />
{<br />
Console.WriteLine(Ex.Message);<br />
}<br />
<br />
return;<br />
}<br />
}<br />
}<br />
<br />
*** SimpleUtil.ServiceProvider ***<br />
using System;<br />
using System.Collections.Generic;<br />
using System.Linq;<br />
using System.Text;<br />
<br />
using System.Runtime.Serialization;<br />
<br />
namespace SimpleUtil<br />
{<br />
[Serializable()]<br />
class ServiceProvider : SimpleUtil.IServiceProvider<br />
{<br />
public void DoWork(string Message)<br />
{<br />
Console.WriteLine("SimpleUtil.DoWork");<br />
return;<br />
}<br />
<br />
public ServiceProvider()<br />
{<br />
return;<br />
}<br />
<br />
public ServiceProvider(SerializationInfo info, StreamingContext context)<br />
{<br />
return;<br />
}<br />
<br />
public void GetObjectData(<br />
SerializationInfo info,<br />
StreamingContext context<br />
)<br />
{<br />
return;<br />
}<br />
<br />
}<br />
}<br />
<br />
using System;<br />
using System.Collections.Generic;<br />
using System.Linq;<br />
using System.Text;<br />
<br />
using System.Runtime.Serialization;<br />
<br />
namespace SimpleUtil<br />
{<br />
public interface IServiceProvider : ISerializable<br />
{<br />
void DoWork(string Message);<br />
}<br />
}<br />
<br />
<br />
***** UserUtil.ServiceProvider *****<br />
using System;<br />
using System.Collections.Generic;<br />
using System.Linq;<br />
using System.Text;<br />
<br />
#region "Inheritance security rules violated while overriding member" runtime error<br />
<br />
#endregion<br />
<br />
using System.Security;<br />
using System.Security.Policy;<br />
using System.Security.Permissions;<br />
<br />
using System.Runtime.Serialization;<br />
<br />
using SimpleUtil;<br />
<br />
namespace UserUtil<br />
{<br />
[Serializable()]<br />
public class ServiceProvider : MarshalByRefObject, SimpleUtil.IServiceProvider<br />
<br />
{<br />
public void DoWork(string Message)<br />
{<br />
<br />
object oSecret = null;<br />
string secret = null;<br />
<br />
oSecret = AppDomain.CurrentDomain.GetData("KEY1");<br />
if (oSecret != null)<br />
{<br />
secret = (string)oSecret;<br />
Console.WriteLine("UserUtil.DoWork - secret=" + secret);
}<br />
else<br />
{<br />
Console.WriteLine("UserUtil.DoWork - secret=NULL!");<br />
}<br />
return;<br />
}<br />
<br />
public ServiceProvider()<br />
{<br />
return;<br />
}<br />
<br />
public ServiceProvider(SerializationInfo info, StreamingContext context)<br />
{<br />
return;<br />
}<br />
<br />
[SecurityCriticalAttribute()]<br />
public void GetObjectData(<br />
SerializationInfo info,<br />
StreamingContext context<br />
)<br />
{<br />
return;<br />
}<br />
}<br />
}<br />
dev
modified on Saturday, March 5, 2011 6:47 AM
|
|
|
|
|
devvvy wrote: a. third party can still access all AppDomain - see this.[^][^]
It's not designed to be a security-feature where you prevent others from looking at your public properties;
Controls access to non-public types and members through the System.Reflection APIs The weakest link would be the .NET-environment itself. Again, what are you securing here? If it's your business-logic, then you might want to consider webservices - that way the other person doesn't have physical access to your code.
I are Troll
|
|
|
|
|
|
I believe the sandbox is meant to prevent other people's code from doing stupid things, not to keep the user out. It might be more efficient to buy an existing system to protect your software.
I are Troll
|
|
|
|
|
Thanks
I think I will not host third party dll in my apps - instead our app will kick start a separate win32 console exe acting as sandbox, send the request to this sandbox which will then load the third party dll. The core app will not send anything sensitive to the sandbox, permission of which will be governed by service account under which it impersonates (i.e. runas)
Screw CAS if even Microsoft is discarding it.
dev
|
|
|
|
|