1 / 59

Software attacks

Software attacks. .NET security. 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:

gloria
Download Presentation

Software attacks

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Software attacks .NET security

  2. 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. 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. .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. Common Language Runtime • At the heart of the .NET platform is a common language runtime engine and a base framework XML Web Services WebForms WindowsForms JScript Data and XML classes VC++ Base framework classes VB Common Language Runtime MSIL C# Verifier Loader JIT ... GC Native Code ...

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

  8. The stub code directs program execution to the JIT compiler. foo call(…) foo.A jmp foo.B jmp JIT Managed Code Blocks When a method is called: push ebp; mov ebp, esp; … push ebp; … call bar.A bar call(…) bar.A jmp push ebp; … call bar.B bar.B call JIT compiler W/ verification Universal JIT Thunk 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. 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. Events Fields Assembly Module list Module Type list Foo Global methods main Properties Methods MyFoo Params int a Metadata The metadata hierarchy class Foo {publicvoid MyFoo() { ... } } publicstaticvoid Main(string[] args) {...}

  11. PE File Format Assembly Manifest 4-part name list of dependent assemblies Metadata IL MyLibrary, Version=1.0.24.0, Culture=neutral, PublicKeyToken=29989D7A39ACF230 BobsLibrary, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null Resources 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

  12. 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. 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. 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. 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. IL validation • Bytes in the IL stream are all valid IL instructions • All jumps are inside the same method

  17. IL verification: Ensuring type safety The CLR verify all code before running it 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

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

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

  20. 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. don’t run malicious code before validation Metadata validation correct metadata (no bogus methods/classes) IL validation file not corrupted IL verification CAS type contracts not broken Summary PE file validation

  22. 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. 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. 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 Word may have the right to access my documents folder But letting a spyware-filled-P2P-client access them is not very wise…

  25. 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. 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. Roles and tasks Customer Clerk Manager Browse catalog Place holdRead history Browse catalog Place holdRead history Check out book Check in book Browse catalog Place holdRead history Check out book Check in book Add book to inventory Remove book from inventory

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

  32. 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. 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. 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. 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. 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. 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. Demanding permission using System.Security.Permissions; publicclass 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. Assembly3.exe MyComponent Assembly2.dll Mscorlib.dll Local drive FileReader FileStream Local drive Assembly4 BadComponent Internet Luring attack Making someone other do the dirty work for you. If Assembly2 is fully trusted, Assembly4 could use it to circumvent protection 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. Assembly2.dll FileReader::read() Mscorlib.dll FileStream::.ctor() Internet.Contains(FileIO) = false FullTrust.Contains(FileIO) = true mscorlib.dll!System.IO.FileStream::.ctor()  FullTrust           FileIO Assembly2.dll!FileReader::read()            FullTrust           Environment, FileIO The FileStream constructor does its demand for FileIOPermission Finds that FileReader::read() has this permission Finds that the Internet permission set does not contain FileIO permission, Stack walk The CLR verifies that every caller in the call chain has the permissions demanded. Assembly4.exe BadComponent::Main() Call Stack                             Grant               Requires=================================================================================== Assembly4.exe!BadComponent::Main()      Internet            Execution Raise a SecurityException.

  41. 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. 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) Recall the case of a trusted assembly calling to a user-provided script. This code places extra restrictions in the current stack frame. using System.Security.Permissions; using System.Security; publicinterface 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

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

  44. Assert Suppose to have the following class using System; using System.IO; publicclass ErrorLogger { publicstaticvoid Log(string s) { conststring 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(); } } 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. 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. Assert a file IO permission before using the FileStream. When the stack walk reaches that stack frame, it will consider the asserted permissions satisfied. Assert ErrorLogger installed as a local component is granted full access to the FileIO. publicclass 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!

  47. 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!) Assert and Stack walk 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: Call Stack                             Grant               Requires===================================================================================mscorlib.dll!System.IO.FileStream::.ctor()  FullTrust           FileIOErrorLogger2::Log()            FullTrust           Environment, FileIO-------------------------Assert(Environment, FileIO)-------------------------------Assembly4.exe!BadComponent::Main()      Internet            Execution Stack walk Stack call

  48. 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. 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. 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

More Related