2

スレーブ サンドボックス ドメインの ApplicationBase をホスティング ドメインと同じパスに設定することの正確なセキュリティ上の影響は何ですか?

ApplicationBase はスレーブ ドメインでは異なる必要があると述べている MSDN のガイドラインを見つけました。 (p. 3):

http://msdn.microsoft.com/en-us/library/bb763046.aspx

このエクスプロイトはどのように機能しますか?

私のシナリオでは、ApplicationBase の下にあるすべてのアセンブリを完全に信頼して実行します。そのドメイン内で動的に生成されたアセンブリの権利を制限するために、スレーブ AppDomain を排他的にサンドボックス化しています。ガイドラインに従ってみましたが、ApplicationBase プロパティを変更すると、アセンブリが LoadFrom コンテキストに読み込まれるため、ドメイン間の双方向通信ブリッジが壊れるように見えるので、避けたいと思います。

個別の ApplicationBase 値に関する問題を示すサンプル F# コード:

module Main =

    open System
    open System.Diagnostics
    open System.IO
    open System.Reflection
    open System.Security
    open System.Security.Permissions
    open System.Security.Policy

    /// Change this switch to observe the problem.
    let useSameApplicationBase = true

    let getStrongName (a: Assembly) =
        match a.Evidence.GetHostEvidence<StrongName>() with
        | null -> None
        | sn -> Some sn

    let getAssemblies () =
        [|
            Assembly.GetExecutingAssembly()
        |]

    let buildAppDomain () =
        let fullTrust =
            getAssemblies ()
            |> Array.choose getStrongName
        let evidence = null
        let appBase =
            if useSameApplicationBase then
                AppDomain.CurrentDomain.BaseDirectory
            else
                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Untrusted")
        let setup = AppDomainSetup(ApplicationBase = appBase)
        let perms = PermissionSet(PermissionState.None)
        AppDomain.CreateDomain("SLAVE", null, setup, perms, fullTrust)

    [<Sealed>]
    type Backer() =
        inherit MarshalByRefObject()
        member this.Pong() =
            Console.WriteLine("PONG IN DOMAIN = {0}", AppDomain.CurrentDomain.FriendlyName)

    [<Sealed>]
    type Sandbox() =
        inherit MarshalByRefObject()
        member this.Start(backer: obj) =
            Console.WriteLine("RUN IN SLAVE DOMAIN = {0}", AppDomain.CurrentDomain.FriendlyName)
            (backer :?> Backer).Pong()

    let test () =
        let dom = buildAppDomain ()
        try
            let handle =
                Activator.CreateInstanceFrom(dom,
                    typeof<Sandbox>.Assembly.Location,
                    typeof<Sandbox>.FullName)
            let sandbox = handle.Unwrap() :?> Sandbox
            sandbox.Start(Backer())
        finally
            AppDomain.Unload(dom)

    test ()
4

1 に答える 1

3
module Main =

    open System
    open System.Diagnostics
    open System.IO
    open System.Reflection
    open System.Security
    open System.Security.Permissions
    open System.Security.Policy

    /// Change this switch to observe the problem.
    let useSameApplicationBase = false

    let getStrongName (a: Assembly) =
        match a.Evidence.GetHostEvidence<StrongName>() with
        | null -> None
        | sn -> Some sn

    let getAssemblies () =
        [|
            Assembly.GetExecutingAssembly()
        |]

    let buildAppDomain () =
        let fullTrust =
            getAssemblies ()
            |> Array.choose getStrongName
        let evidence = null
        let appBase =
            if useSameApplicationBase then
                AppDomain.CurrentDomain.BaseDirectory
            else
                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Untrusted")
        let setup = AppDomainSetup(ApplicationBase = appBase)
        let perms = PermissionSet(PermissionState.None)
        AppDomain.CreateDomain("SLAVE", null, setup, perms, fullTrust)

    module AssemblyResolveSetup = 
        let install() = 
            let resolveHandler = 
                    ResolveEventHandler(
                        fun _ args ->
                            // try to find requested assembly in current domain
                            let name = AssemblyName(args.Name)
                            let asmOpt =
                                AppDomain.CurrentDomain.GetAssemblies()
                                |> Array.tryFind(fun asm -> AssemblyName.ReferenceMatchesDefinition(AssemblyName(asm.FullName), name))
                            defaultArg asmOpt null
                    )        
            AppDomain.CurrentDomain.add_AssemblyResolve(resolveHandler)

    [<Sealed>]
    type Backer() =
        inherit MarshalByRefObject()
        member this.Pong() =
            Console.WriteLine("PONG IN DOMAIN = {0}", AppDomain.CurrentDomain.FriendlyName)

    [<Sealed>]
    type Sandbox() =
        inherit MarshalByRefObject()
        do AssemblyResolveSetup.install()
        member this.Start(backer: obj) =
            Console.WriteLine("RUN IN SLAVE DOMAIN = {0}", AppDomain.CurrentDomain.FriendlyName)
            (backer :?> Backer).Pong()

    let test () =
        let dom = buildAppDomain ()
        try
            let handle =
                Activator.CreateInstanceFrom(dom,
                    typeof<Sandbox>.Assembly.Location,
                    typeof<Sandbox>.FullName)
            let sandbox = handle.Unwrap() :?> Sandbox
            sandbox.Start(Backer())
        finally
            AppDomain.Unload(dom)

    test ()

更新 (テスト コードがアセンブリ Sandbox.exe に含まれていると仮定)

Q :解像度が SLAVE (CurrentDomain) を調べて SLAVE のアセンブリを見つける方法、悪循環のように聞こえます

SLAVE ドメインには既に Sandbox.exe が含まれていますが、LoadFrom コンテキストで読み込まれるため、Load コンテキストの依存関係を解決するときに自動的にプローブされません (バインディング コンテキストの選択)。

Q : AssemblyName(asm.FullName) ではなく asm.GetName() で壊れるのはなぜですか

Assembly.GetName には FileIOPermission、Assembly.FullName が必要です。

AssemblyName(asm.FullName)

let name = AssemblyName(args.Name)
let p = new FileIOPermission(PermissionState.Unrestricted)
p.Assert()
try
    let asmOpt =
        AppDomain.CurrentDomain.GetAssemblies()
        |> Array.tryFind(fun asm -> AssemblyName.ReferenceMatchesDefinition(asm.GetName(), name))
    defaultArg asmOpt null
finally
    CodeAccessPermission.RevertAssert()

これも機能するはずです(試していません)

Q : static do AssemblyResolveSetup.install() でブレーキがかかるのはなぜですか

これが唯一の F# 固有の問題です。テスト プロジェクトは、exe にコンパイルされた単一ファイル プロジェクトだと思います。F# 仕様ごと:

暗黙的なエントリ ポイントを持つ実行可能ファイルの場合、コマンド ラインに表示される最後のファイルの静的初期化子は、暗黙的なエントリ ポイント関数の本体です。

したがって、「static do」ブロック内のコードは、静的コンストラクターの本体にコンパイルされるのではなく、暗黙的なエントリ ポイントで「test()」への呼び出しの前に配置されます。修正 - テスト モジュールを別の最後以外のファイルに配置するか、ライブラリに移動します。

于 2012-11-08T06:50:28.127 に答える