Presentation is loading. Please wait.

Presentation is loading. Please wait.

Software attacks.NET security. Software attacks The problem Buffer owerflow: one silly but very common bug Can allow a determined attacker to obtain control.

Similar presentations


Presentation on theme: "Software attacks.NET security. Software attacks The problem Buffer owerflow: one silly but very common bug Can allow a determined attacker to obtain control."— Presentation transcript:

1 Software attacks.NET security

2 Software attacks The problem Buffer owerflow: one silly but very common bug Can allow a determined attacker to obtain control Components: building an application from third- party DLLs makes the problem even worse: –the attacker has lots of time to discover the various gaps to be exploited in each DLL in use –a bogus/malicious component could be used

3 Software attacks What we want A user that runs a process constructed from components, wants to be sure that he is protected from malicious software. => Prevent buffer overflow with verification of managed code => Prevent execution of malicious software: Code access security (CAS)

4 Software attacks.NET CLR:Common Language Runtime CTS:Common Type System IL:Intermediate Language Metadata:Self info about classes Assembly:Code unit Manifest:Description of assembly

5 Software attacks... C# Common Language Runtime At the heart of the.NET platform is a common language runtime engine and a base framework VB VC++ Common Language Runtime JScript GC JITLoaderVerifier... Native Code Base framework classes Data and XML classes MSIL XML Web Services Web Forms Windows Forms

6 Software attacks MSIL Every.NET language is not compiled to machine code targeted to any specific CPU. Instead, the code generated by the compiler is a Microsoft intermediate language (MSIL) MSIL is much higher level than most CPU machine languages: –It understands object types –Has instructions that create and initialize objects –Calls to virtual methods on objects –Manipulate array elements directly –Instructions that raise and catch exceptions

7 Software attacks JIT Source code Class Libraries (IL & Metadata) EXE/DLL (IL & Metadata) Managed Native Code Compiler Class Loader JIT compiler W/ verification Execution Security checks XML Security policies Stack walk Permission demand Call to an uncompiled method MSIL is not a bytecode: is JITed. The JIT compiler compiles methods on the fly, verifying code in the process

8 Software attacks JIT foo call(…) foo.A foo.B jmp bar call(…) bar.A bar.B jmp call Managed Code Blocks push ebp; mov ebp, esp; … push ebp; … call bar.A push ebp; … call bar.B Universal JIT Thunk JIT compiler W/ verification The stub code directs program execution to the JIT compiler. When a method is called: Once the JIT compiler has compiled the MSIL, the method's stub is replaced with the address of the compiled code. From now, when this method is called, native code will execute

9 Software attacks Metadata The Microsoft.NET platform uses metadata and assemblies to store information about components: –enabling cross-language programming –locate and load class types in the file –resolve method calls and field references –resolving the infamous DLL Hell problem (SxS execution) –easy linking and loading of assemblies –easy versioning –reflection.

10 Software attacks Metadata Assembly ModuleModule listType list Global methods Foo main Methods Fields Properties Events MyFoo Params int a The metadata hierarchy class Foo { public void MyFoo() {... } } public static void Main(string[] args) {... }

11 Software attacks Assembly & Manifest Metadata stored in assembly Think of an assembly as a logical EXE or DLL A manifest is a section of the assembly which makes it self-describing Each assembly has a 4-part name –Friendly name –Version number –Culture setting –Public key (or public key token) The public key forms the so called Strong Name of the assembly MyLibrary, Version=1.0.24.0, Culture=neutral, PublicKeyToken=29989D7A39ACF230 BobsLibrary, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null Metadata IL Assembly Manifest list of dependent assemblies PE File Format 4-part name Resources

12 Software attacks Phase I: Verification and validation Even before checking if an assembly has the necessary permission to access a resource, it has to pass a set of rigorous checks Each related set of checks is called a validation Three major validation are made: –PE file format validation –Metadata validation –IL validation These check ensure that later security checks on assemblies are valid

13 Software attacks PE file format validation Assemblies are PE files They contain a special slot (pointing to an header with relevant addresses) + an unique x86 asm instruction (for old systems) –Donut virus Time of check: right after CLR initialization –All relevant addresses (Metadata location, IL location, etc.) point inside the PE file –Ensures assembly isolation

14 Software attacks Metadata validation As we saw, metadata is a set of linked tables Metadata is used for many crucial functions (recall for example load of types) –Structural validation (the table structure must adhere some standards) –Ex: field table pointing to a buffer (data section) –Semantic validation (rules of the CLR: type invariants, type relatinons) –Ex: subclass B of A cannot be A superclass They are done before metadata is used (i.e. before IL validation)

15 Software attacks IL validation & verification As we saw, IL is not executed but compiled on a method basis Before compiling a method, IL is validated Then, it is verified –Native code has direct memory access and can subvert isolation –Type contracts can be broken (C-style casts, access to private members…) JIT checks that IL is not used in a way it can generate unsafe native code

16 Software attacks IL validation Bytes in the IL stream are all valid IL instructions All jumps are inside the same method

17 Software attacks IL verification: Ensuring type safety class Account { private: long balance; }; void useAccount(Account* a) { // use pointer arithmetic to index // into the object wherever we like! ((long*)a)[1] = MAX_LONG; } By using pointers and unsafe casts, the attacker is able to access and modify private members of a class There is no runtime protection against this in unmanaged code. The CLR detects this sort of type system abuse during just-in-time (JIT) compilation (unsafe pointer arithmetic in this particular case) and raise an exception. A buffer overflow is another example of a type system violation: the CLR closes all of these holes by ensuring the type safety of all code The CLR verify all code before running it

18 Software attacks Ensuring type safety public SecurityInfo { private bool fullyTrusted; public bool IsFullyTrusted() { return (fullyTrusted); } public static SecurityInfo GetSecurityInfo (Assembly a) {...} } public SpoofSecurityInfo { public bool fullyTrusted; } Main() { SecurityInfo si = SecurityInfo.GetSecurityInfo(System.GetMyAssembly()); SpoofSecurityInfo sp = si; spoof.fullyTrusted = true; //do nasty things } call class SecurityInfo SecurityInfo::GetSecurityInfo(class Assembly); stloc si //store the retval (top of stack) in si ldloc si //put si on top of the stack stloc sp //put top of stack in sp TYPE UNSAFE!! The previous code will not compile, however could be possible to write corresponding IL: The JIT werification will not allow stloc sp to execute!!

19 Software attacks Ensuring type safety public SpoofSecurityInfo { public bool fullyTrusted; } Main() { SecurityInfo si = SecurityInfo.GetSecurityInfo(System.GetMyAssembly()); bool* pb = (si + 4); *pb = true; //do nasty things } ldloc si //load si on top of stack ldc.i4 4 //load 4 on top of stack add //add the top 2 operand stloc pb //store top of stack back in pb UNSAFE ldloc pb //load pb on top of stack ldc.i4 1 //load true constant stind.i1 //*pb = true The previous code will not compile, however could be possible to write corresponding IL: The JIT verification will not allow stloc sp to execute!! Type unsafe IL breaks the CLR type system

20 Software attacks Type safety The common language runtime ensures type safety by combining strong typing in the metadata with strong typing in the MSIL (local variables and stack slots). This permit to automatically verifying the type safety of programs written in MSIL. By default, all code compiled by the JIT is validated before beign JITed. –The CLR does not allow any assembly with type unsafe IL to run, with the exception of Full Trusted assemblies Not all safe code may be verifiable with existing technology => but code emitted by.NET compilers is always verifiable

21 Software attacks Summary PE file validation Metadata validation don’t run malicious code before validation IL validation correct metadata (no bogus methods/classes) CAS type contracts not broken IL verification file not corrupted

22 Software attacks Security models Traditional OS security provides isolation and access control based on user accounts. This is useful for organizations, but assumes that all code is equally trustworthy. This assumption is broken by the increasing reliance on mobile code (Web services and components, e-mail attachments, …) There is a need for more granular control of application behavior.

23 Software attacks User-based security model Programs have the same rights of the user who executes them, so they can do all the things a user can do –Often users didn’t even know what a program can do! Too many users run as administrator, too many programs require admin settings to install and run –Even when a program is executed with standard rights, the same concept holds!

24 Software attacks User-based security model example all the program used by these users have access to this folder Windows explorer may have the right to access %WINDIR%\system32 But letting a spyware- filled-P2P-client access them is not very wise… Word may have the right to access my documents folder

25 Software attacks Role-based security Evolution of User-based security Often used in business applications/3-tier applications (business logic) Windows 2000 introduces role-based security for to COM+ components,.NET and Web services You can: –define roles –define the tasks those roles can perform –nest roles to inherit characteristics from other roles –define application groups –use scripts to modify permissions dynamically

26 Software attacks Role-based security example A system to manage a company library Make a list of the sensitive operations: –Read catalog –Place hold (for self or another) –Check out book –Check in book –Add book to inventory –Remove book from inventory –Read patron history (for self or another) Some operations sensitive to information that you'll only have at run time (read a patron's history => the user is trying to access his own history or that of someone else?)

27 Software attacks Roles and tasks Browse catalog Place hold Read history Browse catalog Place hold Read history Check out book Check in book Browse catalog Place hold Read history Check out book Check in book Add book to inventory Remove book from inventory CustomerClerkManager

28 Software attacks Code-based security model Authenticate code, not the user running it => Code identity Authorize code, not the user => security policies an permission sets Enforce code authorization => CAS

29 Software attacks Evidences Code identity is based on evidences Using evidences, security policy can control the privileges granted to an application Eight types of evidences: –ApplicationDirectory: From what directory was this assembly executed? –Site: From what site was this assembly downloaded? –URL: Which is the URL of origin of this assembly? –Zone: From what zone was this assembly obtained? –Hash: What’s the hash of this assembly? –StrongName: What's the strong name of this assembly? –Publisher: Who signed this assembly?

30 Software attacks Code Identity There are only two ways for execute code: –through the class loader –through interoperability services Both of these are services provided by the CLR and are part of the security perimeter The class loader maintains information about the source of every class that it loads The class loader provides some of the evidence upon which code identity is based

31 Software attacks Strong names Metadata Intermediate Language Assembly Manifest Friendly Name:MyLibrary Version:1.0.24.0 Culture:neutral Public Key:(full128-byte value) Reference list of dependent assemblies Digital Signature // AssemblyInfo.cs using System.Reflection; [assembly: AssemblyKeyFile(@"..\..\AcmeCorp.snk")] DLL tampering and replacement creates security hole Public key token + digital signature (= Strong Name) guarantees tamper proof Digital signature built from private key and assembly file hash CLR authenticates digital signature with strong name verification

32 Software attacks Strong names sn.exe -k PublicPrivateKeyFile.snk The compiler digitally signs an assembly: –calculates a cryptographic digest (hash) of the assembly –encrypts the compile-time digest using the 1.024-bit private key from your public-private key pair file. –compiler stores this encrypted compile-time digest into assembly When the.NET loader loads an assembly: –calculates a cryptographic digest (hash) of the assembly –extracts the encrypted compile-time digest from the assembly –extracts the public key for the assembly –uses the public key to decrypt the compile-time digest –compares the runtime digest to the decrypted compile-time digest –if they are not equal, something or someone has modified the it since you compiled it; the runtime fails to load the assembly

33 Software attacks Strong names Strong Names during developement cycle: –Build the assembly with delay signing enabled –Enable strong name verification skipping for the assembly (sn.exe -Vr) –Debug and test the assembly –Obfuscate the assembly –Debug and test the obfuscated version –Delay sign the assembly (sn.exe -R).

34 Software attacks If the strong name is not present, or is not correct… …the main method is not fired! StrongNameSignatureVerification __int32 STDMETHODCALLTYPE _CorExeMain2(PBYTE pUnmappedPE, DWORD cUnmappedPE, LPWSTR pImageNameIn, LPWSTR pLoadersFileName, LPWSTR pCmdLine) { PEFile *pFile = NULL; HRESULT hr = E_FAIL; if (!StrongNameSignatureVerification(pImageNameIn, SN_INFLAG_INSTALL|SN_INFLAG_ALL_ACCESS|SN_INFLAG_RUNTIME, NULL) && StrongNameErrorInfo() != (DWORD) CORSEC_E_MISSING_STRONGNAME) { LOG((LF_ALL, LL_INFO10, "Program exiting due to strong name verification failure\n")); return -1; } //... if (SUCCEEDED(hr)) { hr = SystemDomain::ExecuteMainMethod(pFile, pImageNameIn); } //exit EEShutDown(FALSE); SafeExitProcess(GetLatchedExitCode()); return (GetLatchedExitCode()); }

35 Software attacks Authorization & Enforcement They are highly coupled Security decisions –Coded in software (dynamic, hardcoded) –Declared in assemblies (declarative security) –Inserted in Security Policy (static, configurable)

36 Software attacks Setting permission The CLR discover permissions by gathering evidences from the assembly and giving the answers to the security policy manager, which converts them into permissions. However, often we may want to restrict the set of permissions based on policy at runtime. Let’s see an example.

37 Software attacks Runtime security request Imagine an highly trusted assemblies calling to a user-provided script. The assembly invoking the script might want to restrict the effective permissions before making the call Need for a dynamic permission set management: –PermissionSet –Demand –Deny and RevertDeny, –PermitOnly and RevertPermitOnly –Assert

38 Software attacks Demanding permission using System.Security.Permissions; public class MyFileAccessor { public MyFileAccessor(String path, bool readOnly) { path = MakeFullPath(path); // helper fcn FileIOPermissionAccess desiredAccess = readOnly ? FileIOPermissionAccess.Read : FileIOPermissionAccess.AllAccess; FileIOPermission p = new FileIOPermission(desiredAccess, path); p.Demand(); // open the file } // } Create an object that represents the permission (in this case, access to a file) Demand that permission. The system look at the permissions of the caller If the caller doesn't have this particular permission, Demand throws a SecurityException.

39 Software attacks Luring attack Mscorlib.dll FileStream Assembly2.dll FileReader Assembly4 BadComponent Assembly3.exe MyComponent Local drive Internet If Assembly2 is fully trusted, Assembly4 could use it to circumvent protection Making someone other do the dirty work for you. Rather than forcing each middleman component to do its own access checks to avoid this situation, the CLR uses a technique called Stack Walk

40 Software attacks Finds that the Internet permission set does not contain FileIO permission, Internet.Contains(FileIO) = false FullTrust.Contains(FileIO) = true Finds that FileReader::read() has this permission Stack walk The CLR verifies that every caller in the call chain has the permissions demanded. Call Stack Grant Requires =================================================================================== Assembly4.exe BadComponent::Main() Assembly4.exe!BadComponent::Main() Internet Execution Assembly2.dll FileReader::read() Assembly2.dll!FileReader::read() FullTrust Environment, FileIO Mscorlib.dll FileStream::.ctor() mscorlib.dll!System.IO.FileStream::.ctor() FullTrust FileIO Raise a SecurityException. The FileStream constructor does its demand for FileIOPermission

41 Software attacks Stack walk When the local component Assembly3.exe uses FileReader to read a file, it will be given access because all asseblies in the call chain are local. However, when BadComponent attempts to use FileReader, FileStream calls Demand, the CLR walks up the stack and discover that one of the callers in the call chain don't have the requisite permissions: Demand will throw a SecurityException.

42 Software attacks If Calculate tries to: -access files anywhere in the two sensitive directories, -access an environment variable, -access the contents of the clipboard, (or if any components that Calculate uses internally tries to do any of these things) when the CLR walks the stack to check access, it notes that a stack frame denies these permissions and so denies the request Setting permissions (Deny) using System.Security.Permissions; using System.Security; public interface IUserPluggableAlgorithm { int Calculate(int a, int b); } // code snippet that uses the algorithm PermissionSet ps = new PermissionSet(); ps.AddPermission(new FileIOPermission( FileIOPermissionAccess.AllAccess, "c:\\sensitiveStuff")); ps.AddPermission(new FileIOPermission( FileIOPermissionAccess.AllAccess, "c:\\moreSensitiveStuff")); ps.AddPermission(new EnvironmentPermission( PermissionState.Unrestricted)); ps.AddPermission(new UIPermission( PermissionState.Unrestricted)); ps.Deny(); // deny these permissions int result = a.Calculate(42, 64); CodeAccessPermission.RevertDeny(); // continue doing work Recall the case of a trusted assembly calling to a user-provided script. This code places extra restrictions in the current stack frame.

43 Software attacks Denies.Contains(FileIO) = true Finds that this permission is in the Deny set Permission set and Stack walk Call Stack Grant Requires Denies ======================================================================================== MyApp.exe MyApp::Main() MyApp.exe!MyApp::Main() FullTrust - custom.dll IUserPluggableAlgorithm ::calculate() custom.dll! IUserPluggableAlgorithm::calculate() FullTrust - FileIO,... Mscorlib.dll FileStream::.ctor() mscorlib.dll!System.IO.FileStream::.ctor() FullTrust FileIO FileIO,... Raise a SecurityException. The FileStream constructor does its demand for FileIOPermission ps.Deny() FileIO,...

44 Software attacks Assert using System; using System.IO; public class ErrorLogger { public static void Log(string s) { const string fname = "c:\\temp\\errlog.txt"; FileStream logStream = new FileStream(fname, FileMode.Append, FileAccess.Write); StreamWriter logWriter = new StreamWriter(logStream); logWriter.Write(s); logWriter.Close(); logStream.Close(); } Suppose to have the following class ErrorLogger is safer than MyFileAccessor when used by arbitrary components. But the stack-walking mechanism doesn't know this: when the FileStream constructor demands permissions of its callers, the demand will fail unless every caller in the chain has the FileIOPermission demanded.

45 Software attacks Assert If ErrorLogger class was installed locally, and its assembly is granted full access to the file system by the code access security policy. But this class was designed to provide service to other assemblies, some of which aren't granted permissions to write to the local file system! This impediment can be removed by having ErrorLogger assert its own authority to write to the log file.

46 Software attacks When the stack walk reaches that stack frame, it will consider the asserted permissions satisfied. Assert a file IO permission before using the FileStream. Assert public class ErrorLogger2 { public static void Log(String s) { const String fname = "c:\\temp\\errlog.txt"; FileIOPermission p = new FileIOPermission( FileIOPermissionAccess.Append, fname); p.Assert(); FileStream logStream = new FileStream(fname, FileMode.Append, FileAccess.Write); StreamWriter logWriter = new StreamWriter(logStream); //... } You can only assert permissions that your assembly has been granted! ErrorLogger installed as a local component is granted full access to the FileIO.

47 Software attacks Assert and Stack walk Now, when the FileStream constructor demands FileIO permission it is going to check Log(), find that it has permission, then hit the wall that the Assert put up, and goes no further up the stack. (FOR THAT permission!) Call Stack Grant Requires =================================================================================== mscorlib.dll!System.IO.FileStream::.ctor() FullTrust FileIO ErrorLogger2::Log() FullTrust Environment, FileIO -------------------------Assert(Environment, FileIO)------------------------------- Assembly4.exe!BadComponent::Main() Internet Execution Since Log() is opening a very specific file, and since I've done a full security review on its code, I've decided to enable this scenario. I can do that by calling Assert() for Environment and FileIO permission in Log(), which will create a situation like the following: Stack call Stack walk

48 Software attacks Declarative Security This powerful mechanism allows you to insert code access security checks into your code by annotating classes, fields, or methods. The declarations are encoded in the assembly metadata and are enforced by the.NET security system. [FileIOPermission(SecurityAction.Demand, UnmanagedCode = true)] void aMethod() {... }

49 Software attacks Security policy Permissions are assigned on a per-assembly basis by the Class Loader in the CLR. The steps are: –Gather evidence –Present evidence to security policy –discover assigned permission set It is possible to fine-tune permission set based on assembly requirements

50 Software attacks Evaluating Security Policy To discover the permission set assigned to that assembly, a graph is traversed. The root node is really just a starting place for the traversal: –it matches all code –by default refers to the permission set named Nothing, which contains no permissions. The traversal of the graph is governed by a couple of rules. –if a parent node doesn't match, none of its children are tested for matches –each node can also have the Exclusive attribute, that influence the traversal: only the permission set for that particular node will be used

51 Software attacks Evaluating Security Policy Zone: MyComputer ps:permission1 Zone: Internet ps:permission2 URL: http://.com/* ps:permission3 Publisher: Microsoft ps:permission4 Publisher: ACME Corp ps:permission3 Publisher: ACME Corp ps:permission4 All code ps:nothing Resulting permission set permission1 permission3

52 Software attacks Evaluating Security Policy There is more than one graph: –a machine policy level, –a user policy level, –an application domain policy level, They are evaluated in that order. The resulting set is the intersection of the sets discovered during the traversal of the three graphs

53 Software attacks AppDomains Last enforcement technique, independent from permissions An AppDomain is conceptually similar to a process, but has a much lighter weight. When a process hosts the CLR, it always has a default AppDomain where all managed types are loaded. By creating multiple AppDomains, types in one AppDomain cannot liberaly access types in any other AppDomains. –Sharing references between AppDomains requires the use of remoting. If A and B are in separate AppDomains and A want to access B objects, B has to pass a reference to A. –A can't poke around without being invited.

54 Software attacks Attacks Against CAS Misuse of Assert Unmanaged code security permissions: –Permission to call unmanaged code, it can bypass all CAS –no permission to the file system, but allowed to call into unmanaged code => call to the Win32 API –No protection if an attacker executes unmanaged code as admin Permission escalation by change of location: –Assembly used from Internet => low permissions –Convince the victim to install a copy of the assembly on his machine => permission escalation

55 Software attacks Attacks Against CAS Fully trusted assembly –Can cross AppDomain boundaries –Can pass over IStackWalk.Deny with new PermissionSet( PermissionState.Unrestricted).Assert(); –Can access private members (via Reflection) by turning off JIT checks SecurityManager.SecurityEnabled = false; Remember the principle of least privilege, and design and code with it in mind.

56 Software attacks The old new thing How an.exe assembly get turned into code? _CorExeMain2 starts the process –verifies the signature on the assembly (StrongNameSignatureVerification) –gets the execution engine (EE) ready (CoInitializeEE ) EEStartup starts up all supporting services -garbage collector, -JIT -thread pool manager. –SystemDomain::ExecuteMainMethod makes the Class Loder load an JIT the application main method

57 Software attacks The old new thing __int32 STDMETHODCALLTYPE _CorExeMain2(PBYTE pUnmappedPE, DWORD cUnmappedPE, LPWSTR pImageNameIn, LPWSTR pLoadersFileName, LPWSTR pCmdLine) { PEFile *pFile = NULL; HRESULT hr = E_FAIL; if (!StrongNameSignatureVerification(pImageNameIn, SN_INFLAG_INSTALL|SN_INFLAG_ALL_ACCESS|SN_INFLAG_RUNTIME, NULL) && StrongNameErrorInfo() != (DWORD) CORSEC_E_MISSING_STRONGNAME) { LOG((LF_ALL, LL_INFO10, "Program exiting due to strong name verification failure\n")); return -1; } //... if (SUCCEEDED(hr)) { hr = SystemDomain::ExecuteMainMethod(pFile, pImageNameIn); } //exit EEShutDown(FALSE); SafeExitProcess(GetLatchedExitCode()); return (GetLatchedExitCode()); } Remember?

58 Software attacks The old new thing This is unmanaged, native code. Here we are going to attack: API patching of –RegQueryValueEx –RegOpenKeyEx Recall delay signing and sn.exe -Vr Insert via API patch a bogus voice in HKLM\Software\Microsoft\StrongName\Verification This makes the CLR skip StrongName verification for our assembly => tampering Microsoft did a number of things to avoid this situation, but a way can be found

59 Software attacks


Download ppt "Software attacks.NET security. Software attacks The problem Buffer owerflow: one silly but very common bug Can allow a determined attacker to obtain control."

Similar presentations


Ads by Google