Beispiel #1
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEHeader           peHeader           = context.PE.PEHeaders.PEHeader;
            DllCharacteristics dllCharacteristics = peHeader.DllCharacteristics;

            CoffHeader      coffHeader      = context.PE.PEHeaders.CoffHeader;
            Characteristics characteristics = coffHeader.Characteristics;


            bool highEntropyVA = ((int)dllCharacteristics & 0x0020 /*IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA*/) == 0x0020;

            //  /LARGEADDRESSAWARE is necessary for HIGH_ENTROPY_VA to have effect
            bool largeAddressAware = (characteristics & Characteristics.LargeAddressAware /*IMAGE_FILE_LARGE_ADDRESS_AWARE*/) == Characteristics.LargeAddressAware;

            if (!highEntropyVA && !largeAddressAware)
            {
                // '{0}' does not declare itself as high entropy ASLR compatible. High entropy allows
                // Address Space Layout Randomization to be more effective in mitigating memory
                // corruption vulnerabilities. To resolve this issue, configure your tool chain to
                // mark the program high entropy compatible; e.g. by supplying /HIGHENTROPYVA as well
                // as /LARGEADDRESSAWARE to the C or C++ linker command line.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultKind.Error, context, null,
                                                             nameof(RuleResources.BA2015_Fail_NeitherHighEntropyVANorLargeAddressAware)));
                return;
            }

            if (!highEntropyVA)
            {
                // '{0}' does not declare itself as high entropy ASLR compatible. High entropy allows
                // Address Space Layout Randomization to be more effective in mitigating memory
                // corruption vulnerabilities. To resolve this issue, configure your tool chain to
                // mark the program high entropy compatible; e.g. by supplying /HIGHENTROPYVA to the
                // C or C++ linker command line. (This image was determined to have been properly
                // compiled as /LARGEADDRESSAWARE.)
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultKind.Error, context, null,
                                                             nameof(RuleResources.BA2015_Fail_NoHighEntropyVA)));
                return;
            }

            if (!largeAddressAware)
            {
                // '{0}' does not declare itself as high entropy ASLR compatible. High entropy allows
                // Address Space Layout Randomization to be more effective in mitigating memory
                // corruption vulnerabilities. To resolve this issue, configure your tool chain to
                // mark the program high entropy compatible by supplying /LARGEADDRESSAWARE to the C
                // or C++ linker command line. (This image was determined to have been properly
                // compiled as /HIGHENTROPYVA.)
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultKind.Error, context, null,
                                                             nameof(RuleResources.BA2015_Fail_NoLargeAddressAware)));
                return;
            }

            //'{0}' is high entropy ASLR compatible.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                         nameof(RuleResources.BA2015_Pass)));
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEHeader peHeader = context.PE.PEHeaders.PEHeader;

            UInt64 imageBase = peHeader.ImageBase;

            if (imageBase <= 0xFFFFFFFF)
            {
                // '{0}' is a 64-bit image with a preferred base address below the 4GB boundary.
                // Having a preferred base address below this boundary triggers a compatibility
                // mode in Address Space Layout Randomization (ASLR) on recent versions of
                // Windows that reduces the number of locations to which ASLR may relocate the
                // binary. This reduces the effectiveness of ASLR at mitigating memory corruption
                // vulnerabilities. To resolve this issue, either use the default preferred base
                // address by removing any uses of /baseaddress from compiler command lines, or
                // /BASE from linker command lines (recommended), or configure your program to
                // start at a base address above 4GB when compiled for 64 bit platforms (by
                // changing the constant passed to /baseaddress / /BASE). Note that if you choose
                // to continue using a custom preferred base address, you will need to make this
                // modification only for 64-bit builds, as base addresses above 4GB are not valid
                // for 32-bit binaries.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultKind.Error, context, null,
                                                             nameof(RuleResources.BA2001_Fail)));
                return;
            }

            // '{0}' is marked as NX compatible.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                         nameof(RuleResources.BA2001_Pass)));
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            // Uses Windows Certificate Interop
            BinaryParsers.PlatformSpecificHelpers.ThrowIfNotOnWindows();
            PEBinary target = context.PEBinary();

            Native.WINTRUST_DATA winTrustData;
            string algorithmName, filePath;

            filePath = target.PE.FileName;

            winTrustData = new Native.WINTRUST_DATA();

            if (InvokeVerifyAction(context, filePath, out winTrustData, out algorithmName))
            {
                // '{0}' appears to be signed securely by a trusted publisher with no
                // verification or time stamp errors. Revocation checking was performed
                // on the entire certificate chain, excluding the root certificate.
                // The following digitial signature algorithms were detected: {1}
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                             nameof(RuleResources.BA2022_Pass),
                                                             context.TargetUri.GetFileName(),
                                                             algorithmName));
            }
        }
        private void AnalyzeManagedPE(BinaryAnalyzerContext context)
        {
            Version minCscVersion =
                context.Policy.GetProperty(MinimumToolVersions)[nameof(Language.CSharp)];

            PE pe = context.PEBinary().PE;

            if (pe.LinkerVersion < minCscVersion)
            {
                // '{0}' is a managed assembly that was compiled with an outdated toolchain
                // ({1}) that does not support security features (such as SHA256 PDB
                // checksums and reproducible builds) that must be enabled by policy. To
                // resolve this issue, compile with more recent tools ({2} or later).
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(FailureLevel.Error, context, null,
                                                             nameof(RuleResources.BA2006_Error_OutdatedCsc),
                                                             context.TargetUri.GetFileName(),
                                                             pe.LinkerVersion.ToString(),
                                                             minCscVersion.ToString()));

                return;
            }

            // '{0}' is a managed assembly that was compiled with toolchain ({1}) that supports all security features that must be enabled by policy.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                         nameof(RuleResources.BA2006_Pass_Csc),
                                                         context.TargetUri.GetFileName(),
                                                         pe.LinkerVersion.ToString()));
        }
        private bool GetSignerHashAlgorithms(
            BinaryAnalyzerContext context,
            Native.WINTRUST_DATA winTrustData,
            out string hashAlgorithm,
            out string hashEncryptionAlgorithm)
        {
            string      failedApiName;
            CryptoError cryptoError;

            cryptoError = GetSignerHashAlgorithms(
                winTrustData.hWVTStateData,
                out hashAlgorithm,
                out hashEncryptionAlgorithm,
                out failedApiName);

            if (cryptoError != CryptoError.ERROR_SUCCESS)
            {
                // '{0}' signing could not be completely verified because
                // '{1}' failed with error code: '{2}'.
                context.Logger.Log(this, RuleUtilities.BuildResult(FailureLevel.Error, context, null,
                                                                   nameof(RuleResources.BA2022_Error_WinTrustVerifyApiError),
                                                                   context.TargetUri.GetFileName(),
                                                                   failedApiName,
                                                                   cryptoError.ToString()));
                return(false);
            }

            return(true);
        }
        private void GenerateCompilandsAndLog(BinaryAnalyzerContext context, List <ObjectModuleDetails> compilandsWithOneOrMoreInsecureFileHashes, FailureLevel failureLevel)
        {
            string compilands = compilandsWithOneOrMoreInsecureFileHashes.CreateOutputCoalescedByCompiler();

            //'{0}' is a native binary that links one or more object files which were hashed
            // using an insecure checksum algorithm (MD5). MD5 is subject to collision attacks
            // and its use can compromise supply chain integrity. Pass '/ZH:SHA-256' on the
            // cl.exe command-line to enable secure source code hashing. The following modules
            // are out of policy: {1}
            if (failureLevel == FailureLevel.Warning)
            {
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(failureLevel,
                                                             context,
                                                             null,
                                                             nameof(RuleResources.BA2004_Warning_NativeWithInsecureStaticLibraryCompilands),
                                                             context.TargetUri.GetFileName(),
                                                             compilands));
                return;
            }

            context.Logger.Log(this,
                               RuleUtilities.BuildResult(failureLevel,
                                                         context,
                                                         null,
                                                         nameof(RuleResources.BA2004_Error_NativeWithInsecureDirectCompilands),
                                                         context.TargetUri.GetFileName(),
                                                         compilands));
        }
Beispiel #7
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            IELF elf = context.ELFBinary().ELF;

            HashSet <string> symbolNames =
                new HashSet <string>
                (
                    ELFUtility.GetAllSymbols(elf).Select <ISymbolEntry, string>(sym => sym.Name)
                );

            foreach (string stack_chk in stack_check_symbols)
            {
                if (symbolNames.Contains(stack_chk))
                {
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                                 nameof(RuleResources.BA3003_Pass),
                                                                 context.TargetUri.GetFileName()));
                    return;
                }
            }
            // If we haven't found the stack protector, we assume it wasn't used.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                         nameof(RuleResources.BA3003_Error),
                                                         context.TargetUri.GetFileName()));
        }
Beispiel #8
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEBinary target   = context.PEBinary();
            PEHeader peHeader = target.PE.PEHeaders.PEHeader;

            if ((peHeader.DllCharacteristics & DllCharacteristics.NxCompatible /*IMAGE_DLLCHARACTERISTICS_NX_COMPAT*/) == 0)
            {
                // '{0}' is not marked NX compatible. The NXCompat bit, also known as "Data Execution Prevention"
                // (DEP) or "Execute Disable" (XD), is a processor feature that allows a program to mark a piece
                // of memory as non - executable. This helps mitigate memory corruption vulnerabilities by
                // preventing an attacker from supplying direct shellcode in their exploit, because the exploit
                // comes in the form of input data to the exploited program on a data segment, rather than on an
                // executable code segment. To resolve this issue, ensure that your tool chain is configured to mark
                //your binaries as NX compatible, e.g. by passing / NXCOMPAT to the C / C++ linker.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                             nameof(RuleResources.BA2016_Error),
                                                             context.TargetUri.GetFileName()));
                return;
            }

            // '{0}' is marked as NX compatible.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                         nameof(RuleResources.BA2016_Pass),
                                                         context.TargetUri.GetFileName()));
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEBinary target = context.PEBinary();
            PE       pe     = target.PE;

            // Analysis may return one or more failures, each of which uses a format
            // string stored in the MessageResourceNames array above to produce a result.
            // By convention, we recapitulate that format string when we return the
            // associated result, to document the specific failure or pass condition.

            if (!this.IsSecure(target))
            {
                // '{0}' is not secure for some reaons.
                // To resolve this issue, pass /beEvenMoreSecure on both the compiler
                // and linker command lines. Binaries also require the
                // /beSecure option in order to enable the enhanced setting.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(FailureLevel.Error, context, null,
                                                             nameof(RuleResources.BAXXXX_Error),
                                                             context.TargetUri.GetFileName()));
                return;
            }

            // '{0}' enables /beEvenMoreSecure on both the compiler and linker
            // command-lines, preventing a broad range of conditions that
            // bad actors can use to engage in their malignant, unfortunately
            // often-profitable foolishness.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                         nameof(RuleResources.BAXXXX_Pass),
                                                         context.TargetUri.GetFileName()));
        }
Beispiel #10
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            Native.WINTRUST_DATA winTrustData;
            string algorithmName, filePath;

            filePath = context.PE.FileName;

            winTrustData = new Native.WINTRUST_DATA();

            try
            {
                if (InvokeVerifyAction(context, filePath, out winTrustData, out algorithmName))
                {
                    // '{0}' appears to be signed securely by a trusted publisher with
                    // no verification or time stamp errors. Revocation checking was
                    // performed on the entire certificate chain, excluding the root
                    // certificate. The image was signed with '{1}', a
                    // cryptographically strong algorithm.
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                                 nameof(RuleResources.BA2022_Pass),
                                                                 algorithmName));
                }
            }
            finally
            {
                if (winTrustData.hWVTStateData != IntPtr.Zero)
                {
                    InvokeCloseAction(winTrustData);
                }
            }
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            IELF elf = context.ELFBinary().ELF;

            if (elf.Type == FileType.Executable)
            {
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                             nameof(RuleResources.BA3001_Error),
                                                             context.TargetUri.GetFileName()));
                return;
            }
            else if (elf.Type == FileType.SharedObject)
            {
                // Check that it is an executable SO instead of a normal shared library
                // Looking for a program header segment seems to work well here.
                if (elf.Segments.Where(seg => seg.Type == SegmentType.ProgramHeader).Any())
                {
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                                 nameof(RuleResources.BA3001_Pass_Executable),
                                                                 context.TargetUri.GetFileName()));
                    return;
                }
                else
                {
                    // '{0}' does not have an imports section that is marked as executable.
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                                 nameof(RuleResources.BA3001_Pass_Library),
                                                                 context.TargetUri.GetFileName()));
                    return;
                }
            }
        }
        private void AnalyzeManagedAssemblyAndPdb(BinaryAnalyzerContext context)
        {
            PEBinary target = context.PEBinary();
            Pdb      di     = target.Pdb;

            if (target.PE.ManagedPdbSourceFileChecksumAlgorithm(di.FileType) != ChecksumAlgorithmType.Sha256)
            {
                // '{0}' is a managed binary compiled with an insecure (SHA-1) source code hashing algorithm.
                // SHA-1 is subject to collision attacks and its use can compromise supply chain integrity.
                // Pass '-checksumalgorithm:SHA256' on the csc.exe command-line or populate the project
                // <ChecksumAlgorithm> property with 'SHA256' to enable secure source code hashing.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultKind.Fail, context, null,
                                                             nameof(RuleResources.BA2004_Error_Managed),
                                                             context.TargetUri.GetFileName()));
                return;
            }

            // '{0}' is a {1} binary which was compiled with a secure (SHA-256)
            // source code hashing algorithm.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                         nameof(RuleResources.BA2004_Pass),
                                                         context.TargetUri.GetFileName(),
                                                         "managed"));
        }
Beispiel #13
0
 private void LogCouldNotLocateCookie(BinaryAnalyzerContext context)
 {
     // '{0}' is a C or C++ binary that enables the stack protection feature
     // but the security cookie could not be located. The binary may be corrupted.
     context.Logger.Log(this,
                        RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                  nameof(RuleResources.BA2012_Error_CouldNotLocateCookie)));
 }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEHeader peHeader = context.PE.PEHeaders.PEHeader;

            // TODO: do we really require this check? What is the proposed fix to this issue?
            if (peHeader.SectionAlignment < PAGE_SIZE)
            {
                // '{0}' has a section alignment ({1}) that is less than page size ({2}).
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultKind.Error, context, null,
                                                             nameof(RuleResources.BA2021_Fail),
                                                             context.PE.FileName,
                                                             "0x" + peHeader.SectionAlignment.ToString("x"),
                                                             "0x" + PAGE_SIZE.ToString("x")));
                return;
            }

            var sectionHeaders = context.PE.PEHeaders.SectionHeaders;

            List <string> badSections = new List <string>();

            if (sectionHeaders != null)
            {
                foreach (SectionHeader sectionHeader in sectionHeaders)
                {
                    SectionCharacteristics wxFlags = SectionCharacteristics.MemWrite | SectionCharacteristics.MemExecute;

                    if ((sectionHeader.SectionCharacteristics & wxFlags) == wxFlags)
                    {
                        badSections.Add(sectionHeader.Name);
                    }
                }
            }

            if (badSections.Count == 0)
            {
                // '{0}' contains no data or code sections marked as both shared and executable.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                             nameof(RuleResources.BA2021_Pass)));
                return;
            }

            string badSectionsText = String.Join(";", badSections);

            // '{0}' contains PE section(s)({ 1}) that are both writable and executable.
            // Writable and executable memory segments make it easier for an attacker to
            //exploit memory corruption vulnerabilities, because it may give an attacker
            // executable location(s) to inject shellcode. To resolve this
            // issue, configure your toolchain to not emit memory sections that are
            // writable and executable.For example, look for uses of / SECTION on the
            // linker command line for C and C++ programs, or  #pragma section in C and
            // C++ source code, which mark a section with both attributes.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultKind.Error, context, null,
                                                         nameof(RuleResources.BA2021_Fail),
                                                         badSectionsText));
        }
Beispiel #15
0
 private void LogInvalidCookieOffsetForKnownPackedFile(BinaryAnalyzerContext context)
 {
     // '{0}' appears to be a packed C or C++ binary that reports a security cookie
     // offset that exceeds the size of the packed file. Use of the stack protector (/GS)
     // feature therefore could not be verified. The file was possibly packed by: {1}
     context.Logger.Log(this,
                        RuleUtilities.BuildResult(ResultLevel.Warning, context, null,
                                                  nameof(RuleResources.BA2012_Warning_InvalidSecurityCookieOffset),
                                                  context.PE.Packer.ToString()));
 }
Beispiel #16
0
 private void LogInvalidCookieOffset(BinaryAnalyzerContext context)
 {
     // The security cookie offset for '{0}' exceeds the size of the image.
     // The file may be corrupted or processed by an executable packer.
     // feature therefore could not be verified. The file was possibly packed by: {1}
     context.Logger.Log(this,
                        RuleUtilities.BuildResult(ResultLevel.Warning, context, null,
                                                  nameof(RuleResources.BA2012_Warning_InvalidSecurityCookieOffset),
                                                  context.PE.Packer.ToString()));
 }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEBinary target = context.PEBinary();

            string         executableImportSection = null;
            PEHeader       peHeader    = target.PE.PEHeaders.PEHeader;
            DirectoryEntry importTable = peHeader.ImportTableDirectory;

            if (importTable.RelativeVirtualAddress != 0 && target.PE.PEHeaders.SectionHeaders != null)
            {
                int importSize = peHeader.ImportTableDirectory.Size;
                foreach (SectionHeader sectionHeader in target.PE.PEHeaders.SectionHeaders)
                {
                    SectionCharacteristics memExecute = SectionCharacteristics.MemExecute;
                    if ((sectionHeader.SectionCharacteristics & memExecute) == 0)
                    {
                        continue;
                    }

                    int size    = sectionHeader.SizeOfRawData;
                    int address = sectionHeader.VirtualAddress;

                    if ((address <= importTable.RelativeVirtualAddress) &&
                        (address + size >= importTable.RelativeVirtualAddress + importTable.Size))
                    {
                        // Our import section is in a writable section - bad
                        executableImportSection = sectionHeader.Name;
                        break;
                    }
                }
            }

            if (executableImportSection != null)
            {
                // '{0}' has the imports section marked executable. Because the loader will always mark
                // the imports section as writable, it is important to mark this section as non-executable,
                // so that an attacker cannot place shellcode here. To resolve this issue, ensure that your
                //program does not mark the imports section as executable. Look for uses of /SECTION or
                // /MERGE on the linker command line, or #pragma segment in source code, which change the
                // imports section to be executable, or which merge the ".rdata" segment into an executable
                // section.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(FailureLevel.Error, context, null,
                                                             nameof(RuleResources.BA2010_Error),
                                                             context.TargetUri.GetFileName()));
                return;
            }

            // '{0}' does not have an imports section that is marked as executable.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                         nameof(RuleResources.BA2010_Pass),
                                                         context.TargetUri.GetFileName()));
        }
        /// <summary>
        /// Checks if Fortified functions are used--the -DFORTIFY_SOURCE=2 flag enables these when -O2 is enabled.
        ///
        /// Check implementation:
        /// -Get all function symbols in the ELF binary
        /// -Check for any fortified functions--if we find any, we used the option.
        /// -Check for any unfortified functions.  If we only find unfortified functions, one of two things is true:
        ///     1) Fortify Source wasn't used; or
        ///     2) Fortify Source was used, but gcc/clang was unable to statically find anything that needed to be fortified.
        ///     We report on both cases.
        /// -If no fortifiable functions were used at all, the rule doesn't apply.
        /// </summary>
        public override void Analyze(BinaryAnalyzerContext context)
        {
            IELF elf = context.ELFBinary().ELF;

            IEnumerable <ISymbolEntry> symbols =
                ELFUtility.GetAllSymbols(elf).Where(sym => sym.Type == SymbolType.Function || sym.Type == SymbolType.Object);

            List <ISymbolEntry> protectedFunctions   = new List <ISymbolEntry>();
            List <ISymbolEntry> unprotectedFunctions = new List <ISymbolEntry>();

            foreach (ISymbolEntry e in symbols)
            {
                if (unfortifiedFunctions.Contains(e.Name))
                {
                    unprotectedFunctions.Add(e);
                }
                else if (fortifiedFunctions.Contains(e.Name))
                {
                    protectedFunctions.Add(e);
                }
            }

            if (protectedFunctions.Any())
            {
                if (unprotectedFunctions.Any())
                {
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                                 nameof(RuleResources.BA3030_Pass_SomeFunctionsChecked),
                                                                 context.TargetUri.GetFileName()));
                }
                else
                {
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                                 nameof(RuleResources.BA3030_Pass_AllFunctionsChecked),
                                                                 context.TargetUri.GetFileName()));
                }
            }
            else if (unprotectedFunctions.Any())
            {
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(FailureLevel.Error, context, null,
                                                             nameof(RuleResources.BA3030_Error),
                                                             context.TargetUri.GetFileName()));
            }
            else
            {
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                             nameof(RuleResources.BA3030_Pass_NoCheckableFunctions),
                                                             context.TargetUri.GetFileName()));
            }
        }
Beispiel #19
0
        protected void LogResult(string jPointer, string formatId, params string[] args)
        {
            Region region = GetRegionFromJPointer(jPointer);

            // All messages start with "In {file}, at {jPointer}, ...". Prepend the jPointer to the args.
            string[] argsWithPointer = new string[args.Length + 1];
            Array.Copy(args, 0, argsWithPointer, 1, args.Length);
            argsWithPointer[0] = jPointer;

            Context.Logger.Log(this,
                               RuleUtilities.BuildResult(DefaultLevel, Context, region, formatId, argsWithPointer));
        }
Beispiel #20
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEBinary target = context.PEBinary();

            var sectionHeaders = target.PE.PEHeaders.SectionHeaders;

            List <string> badSections = new List <string>();

            if (sectionHeaders != null)
            {
                foreach (SectionHeader sectionHeader in sectionHeaders)
                {
                    SectionCharacteristics wsFlags = SectionCharacteristics.MemWrite | SectionCharacteristics.MemShared;

                    if ((sectionHeader.SectionCharacteristics & wsFlags) == wsFlags) // IMAGE_SCN_MEM_WRITE & IMAGE_SCN_MEM_SHARED
                    {
                        badSections.Add(sectionHeader.Name);
                    }
                }
            }

            if (badSections.Count == 0)
            {
                // Image '{0}' contains no data or code sections marked as both shared and writable.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                             nameof(RuleResources.BA2019_Pass),
                                                             context.TargetUri.GetFileName()));
                return;
            }

            string badSectionsText = String.Join(";", badSections);

            // '{0}' contains PE section(s) ({1}) that are both writable and executable.
            // Writable and executable memory segments make it easier for an attacker
            // to exploit memory corruption vulnerabilities, because it may provide an
            // attacker executable location(s) to inject shellcode. To resolve this
            // issue, configure your tools to not emit memory sections that are writable
            // and executable. For example, look for uses of /SECTION on the linker
            // command line for C and C++ programs, or #pragma section in C and C++
            // source code, which mark a section with both attributes. Enabling
            // incremental linking via the /INCREMENTAL argument (the default for
            // Microsoft Visual Studio debug build) can also result in a writable and
            // executable section named 'textbss'. For this case, disable incremental
            // linking (or analyze an alternate build configuration that disables this
            // feature) to resolve the problem.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(FailureLevel.Error, context, null,
                                                         nameof(RuleResources.BA2019_Error),
                                                         context.TargetUri.GetFileName(),
                                                         badSectionsText));
        }
Beispiel #21
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            // Throw a platform unsupported exception--FileVersionInfo does not behave "correctly" on Linux.
            BinaryParsers.PlatformSpecificHelpers.ThrowIfNotOnWindows();

            PEBinary target = context.PEBinary();

            string fileName = Path.GetFileName(target.PE.FileName);

            Version minimumVersion;

            if (context.Policy.GetProperty(VulnerableBinaries).TryGetValue(fileName, out minimumVersion))
            {
                FileVersionInfo fvi              = FileVersionInfo.GetVersionInfo(Path.GetFullPath(target.PE.FileName));
                string          rawVersion       = fvi.FileVersion ?? string.Empty;
                Match           sanitizedVersion = s_versionRegex.Match(rawVersion);
                if (!sanitizedVersion.Success)
                {
                    // Version information for '{0}' could not be parsed. The binary therefore could not be verified not to be an obsolete binary that is known to be vulnerable to one or more security problems.
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                                 nameof(RuleResources.BA2005_Error_CouldNotParseVersion),
                                                                 context.TargetUri.GetFileName()));
                    return;
                }

                var actualVersion = new Version(sanitizedVersion.Value);
                if (actualVersion < minimumVersion)
                {
                    // '{0}' appears to be an obsolete library (version {1}) for which there are one
                    // or more known security vulnerabilities. To resolve this issue, obtain a version
                    //of {0} that is version {2} or greater. If this binary is not in fact {0},
                    // ignore this warning.
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                                 nameof(RuleResources.BA2005_Error),
                                                                 context.TargetUri.GetFileName(),
                                                                 sanitizedVersion.Value,
                                                                 minimumVersion.ToString()));
                    return;
                }
            }

            // '{0}' is not known to be an obsolete binary that is
            //vulnerable to one or more security problems.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                         nameof(RuleResources.BA2005_Pass),
                                                         context.TargetUri.GetFileName()));
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEBinary target   = context.PEBinary();
            PEHeader peHeader = target.PE.PEHeaders.PEHeader;

            if (peHeader.LoadConfigTableDirectory.RelativeVirtualAddress == 0)
            {
                // LOAD_CONFIG block absent. This can occur in 2 cases:
                // 1. The user has C or C++ code linked with a linker older than Dev11 (VS2010)
                // 2. The code is not C or C++ code at all.
                //
                // In the first case we expect CompilerVersionCheck to fire on this code. In the
                // second case we don't want to warn because the code is likely safe;
                // e.g. .NET ngen'd images fall into this bucket.

                //'{0}' is  C or C++binary that does not contain a load config table, which
                // indicates either that it was compiled and linked with a version of the
                // compiler that precedes stack protection features or is a binary (such as
                // an ngen'ed assembly) that is not subject to relevant security issues.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                             nameof(RuleResources.BA2012_Pass_NoLoadConfig),
                                                             context.TargetUri.GetFileName()));
                return;
            }

            if (target.PE.Is64Bit)
            {
                if (!Validate64BitImage(context))
                {
                    return;
                }
            }
            else if (!Validate32BitImage(context))
            {
                return;
            }

            // '{0}' is a C or C++ binary built with the buffer security feature
            // that properly preserves the stack protecter cookie. This has the
            // effect of enabling a significant increase in entropy provided by
            // the operating system over that produced by the C runtime start-up
            // code.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                         nameof(RuleResources.BA2012_Pass),
                                                         context.TargetUri.GetFileName()));
        }
Beispiel #23
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            var sectionHeaders = context.PE.PEHeaders.SectionHeaders;

            List <string> badSections = new List <string>();

            if (sectionHeaders != null)
            {
                foreach (SectionHeader sectionHeader in sectionHeaders)
                {
                    SectionCharacteristics wsFlags = SectionCharacteristics.MemWrite | SectionCharacteristics.MemShared;

                    if ((sectionHeader.SectionCharacteristics & wsFlags) == wsFlags) // IMAGE_SCN_MEM_WRITE & IMAGE_SCN_MEM_SHARED
                    {
                        badSections.Add(sectionHeader.Name);
                    }
                }
            }

            if (badSections.Count == 0)
            {
                // Image '{0}' contains no data or code sections marked as both shared and writable.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                             nameof(RuleResources.BA2019_Pass),
                                                             context.TargetUri.GetFileName()));
                return;
            }

            string badSectionsText = String.Join(";", badSections);

            // {0} contains one or more code or data sections ({1}) which are marked as both
            // shared and writable. Because these sections are shared across processes, this
            // condition might permit a process with low privilege to mutate memory in a higher
            // privilege process. If you do not actually require that the section be both
            // writable and shared, remove one or both of these attributes (by modifying your
            // .DEF file, the appropriate linker /section switch arguments, etc.). If you are
            // required to share common data across processes (for IPC or other purposes) use
            // CreateFileMapping with proper security attributes or an actual IPC mechanism
            // instead (COM, named pipes, LPC, etc.).
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                         nameof(RuleResources.BA2019_Error),
                                                         context.TargetUri.GetFileName(),
                                                         badSectionsText));
        }
Beispiel #24
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            if (!EnablesControlFlowGuard(context))
            {
                // '{0}' does not enable the control flow guard (CFG) mitigation.
                // To resolve this issue, pass /GUARD:CF on both the compiler
                // and linker command lines. Binaries also require the
                // /DYNAMICBASE linker option in order to enable CFG.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                             nameof(RuleResources.BA2008_Error)));
                return;
            }

            // '{0}' enables the control flow guard mitigation.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                         nameof(RuleResources.BA2008_Pass)));
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            string fileName = Path.GetFileName(context.PE.FileName);

            Version minimumVersion;

            if (context.Policy.GetProperty(VulnerableBinaries).TryGetValue(fileName, out minimumVersion))
            {
                FileVersionInfo fvi              = FileVersionInfo.GetVersionInfo(Path.GetFullPath(context.PE.FileName));
                string          rawVersion       = fvi.FileVersion;
                Match           sanitizedVersion = s_versionRegex.Match(rawVersion);
                if (!sanitizedVersion.Success)
                {
                    // Version information for '{0}' could not be parsed. The binary therefore could not be verified not to be an obsolete binary that is known to be vulnerable to one or more security problems.
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultKind.Error, context, null,
                                                                 nameof(RuleResources.BA2005_Fail_CouldNotParseVersion)));
                    return;
                }

                var actualVersion = new Version(sanitizedVersion.Value);
                if (actualVersion < minimumVersion)
                {
                    // '{0}' appears to be an obsolete library (version {1}) for which there are one
                    // or more known security vulnerabilities. To resolve this issue, obtain a version
                    //of {0} that is version {2} or greater. If this binary is not in fact {0},
                    // ignore this warning.
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultKind.Error, context, null,
                                                                 nameof(RuleResources.BA2005_Fail),
                                                                 sanitizedVersion.Value,
                                                                 minimumVersion.ToString()));
                    return;
                }
            }

            // '{0}' is not known to be an obsolete binary that is
            //vulnerable to one or more security problems.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                         nameof(RuleResources.BA2005_Pass)));
        }
        public override void Analyze(SqlFileContext context)
        {
            ColumnDefinition node = (ColumnDefinition)context.Fragment;

            SqlDataTypeReference sdtr = node.DataType as SqlDataTypeReference;

            if (sdtr == null)
            {
                return;
            }

            if (sdtr.SqlDataTypeOption != SqlDataTypeOption.VarBinary &&
                sdtr.SqlDataTypeOption != SqlDataTypeOption.VarChar &&
                sdtr.SqlDataTypeOption != SqlDataTypeOption.NVarChar)
            {
                return;
            }

            if (sdtr.Parameters.Count > 0)
            {
                Region region = sdtr.CreateRegion();

                int size = Int32.Parse(sdtr.Parameters[0].Value);

                if (size <= context.Policy.GetProperty(SmallSizeThreshold))
                {
                    // The data type for column '{0}' was defined as {1} of a
                    // small size ({2}) which may incur additional storage and
                    // performance costs. Declare this data type as a fixed size
                    // or ignore the warning in cases performance is not a concern.
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultKind.Warning, context, region,
                                                                 nameof(RuleResources.SQL2009_Default),
                                                                 node.ColumnIdentifier.Value,
                                                                 sdtr.SqlDataTypeOption.ToString(),
                                                                 size.ToString()));
                }
            }
            return;
        }
Beispiel #27
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PE pe = context.PE;

            if (pe.IsKernelMode &&
                (pe.FileVersion.FileMajorPart < 10 ||
                 pe.FileVersion.FileBuildPart < 15000))
            {
                if (pe.FileVersion.FileBuildPart < 15000)
                {
                    // '{0}' is a kernel mode portable executable compiled for a
                    // version of Windows that does not support the control flow
                    // guard feature for kernel mode binaries.
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultLevel.NotApplicable, context, null,
                                                                 nameof(RuleResources.BA2008_NotApplicable_UnsupportKernelModeVersion),
                                                                 context.TargetUri.GetFileName()));
                }
            }

            if (!EnablesControlFlowGuard(context))
            {
                // '{0}' does not enable the control flow guard (CFG) mitigation.
                // To resolve this issue, pass /GUARD:CF on both the compiler
                // and linker command lines. Binaries also require the
                // /DYNAMICBASE linker option in order to enable CFG.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                             nameof(RuleResources.BA2008_Error),
                                                             context.TargetUri.GetFileName()));
                return;
            }

            // '{0}' enables the control flow guard mitigation.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                         nameof(RuleResources.BA2008_Pass),
                                                         context.TargetUri.GetFileName()));
        }
Beispiel #28
0
 private void LogFailure(BinaryAnalyzerContext context, string cookie)
 {
     // '{0}' is a C or C++ binary that interferes with the stack protector. The
     // stack protector (/GS) is a security feature of the compiler which makes
     // it more difficult to exploit stack buffer overflow memory corruption
     // vulnerabilities. The stack protector relies on a random number, called
     // the "security cookie", to detect these buffer overflows. This 'cookie'
     // is statically linked with your binary from a Visual C++ library in the
     // form of the symbol __security_cookie. On recent Windows versions, the
     // loader looks for the magic statically linked value of this cookie, and
     // initializes the cookie with a far better source of entropy -- the system's
     // secure random number generator -- rather than the limited random number
     // generator available early in the C runtime startup code. When this symbol
     // is not the default value, the additional entropy is not injected by the
     // operating system, reducing the effectiveness of the stack protector. To
     // resolve this issue, ensure that your code does not reference or create a
     // symbol named __security_cookie or __security_cookie_complement. NOTE:
     // the modified cookie value detected was: {1}
     context.Logger.Log(this,
                        RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                  nameof(RuleResources.BA2012_Error),
                                                  cookie));
 }
Beispiel #29
0
        private string RetrieveSignatureAlgorithmAndCertInfo(
            BinaryAnalyzerContext context,
            Native.WINTRUST_DATA winTrustData,
            out Native.CERT_INFO certInfo)
        {
            string      failedApiName;
            CryptoError cryptoError;

            cryptoError = GetCertInfo(winTrustData.hWVTStateData, out certInfo, out failedApiName);

            if (cryptoError != CryptoError.ERROR_SUCCESS)
            {
                // '{0}' signing could not be completely verified because
                // '{1}' failed with error code: '{2}'.
                context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                                   nameof(RuleResources.BA2022_Error_WinTrustVerifyApiError),
                                                                   failedApiName,
                                                                   cryptoError.ToString()));
                return(null);
            }

            return(GetAlgorithmName(certInfo.SignatureAlgorithm.pszObjId));
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            IELF elf = context.ELFBinary().ELF;

            foreach (var seg in elf.Segments)
            {
                if (((uint)seg.Type) == GNU_RELRO_ID)
                {
                    // Pass
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                                 nameof(RuleResources.BA3010_Pass),
                                                                 context.TargetUri.GetFileName()));
                    return;
                }
            }

            // Fail
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                                                         nameof(RuleResources.BA3010_Error),
                                                         context.TargetUri.GetFileName()));
        }