Inheritance: IAnalysisContext
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEHeader peHeader = context.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)
        {
            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 AnalysisApplicability CanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
        {
            PE portableExecutable = context.PE;
            AnalysisApplicability result = AnalysisApplicability.NotApplicableToSpecifiedTarget;

            reasonForNotAnalyzing = MetadataConditions.ImageIsKernelModeBinary;
            if (portableExecutable.IsKernelMode) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsResourceOnlyBinary;
            if (portableExecutable.IsResourceOnly) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsILOnlyManagedAssembly;
            if (portableExecutable.IsILOnly) { return result; }

            if (portableExecutable.LinkerVersion < MinimumSupportedLinkerVersion)
            {
                reasonForNotAnalyzing = string.Format(
                    MetadataConditions.ImageCompiledWithOutdatedTools,                    
                    portableExecutable.LinkerVersion, 
                    MinimumSupportedLinkerVersion);

                return result;
            }

            return AnalysisApplicability.ApplicableToSpecifiedTarget;
        }
        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));
        }
        public override AnalysisApplicability CanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
        {
            PE portableExecutable = context.PE;
            AnalysisApplicability result = AnalysisApplicability.NotApplicableToSpecifiedTarget;

            reasonForNotAnalyzing = MetadataConditions.ImageIsXBoxBinary;
            if (portableExecutable.IsXBox) { return result; }

            return AnalysisApplicability.ApplicableToSpecifiedTarget;
        }
        public override AnalysisApplicability CanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
        {
            // Checks for missing policy should always be evaluated as the last action, so that 
            // we do not raise an error in cases where the analysis would not otherwise be applied.

            // Missing required configuration: 'vulnerable binary name and version metadata'
            reasonForNotAnalyzing = RuleResources.BA2005_MissingRequiredConfiguration;
            if (context.Policy == null) { return AnalysisApplicability.NotApplicableDueToMissingConfiguration; }

            return AnalysisApplicability.ApplicableToSpecifiedTarget;
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            string executableImportSection = null;
            PEHeader peHeader = context.PE.PEHeaders.PEHeader;
            DirectoryEntry importTable = peHeader.ImportTableDirectory;

            if (importTable.RelativeVirtualAddress != 0 && context.PE.PEHeaders.SectionHeaders != null)
            {
                int importSize = peHeader.ImportTableDirectory.Size;
                foreach (SectionHeader sectionHeader in context.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(ResultLevel.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(ResultLevel.Pass, context, null,
                    nameof(RuleResources.BA2010_Pass),
                    context.TargetUri.GetFileName()));
        }
        public override AnalysisApplicability CanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
        {
            AnalysisApplicability applicability = StackProtectionUtilities.CommonCanAnalyze(context, out reasonForNotAnalyzing);

            // Checks for missing policy should always be evaluated as the last action, so that 
            // we do not raise an error in cases where the analysis would not otherwise be applied.
            if (applicability == AnalysisApplicability.ApplicableToSpecifiedTarget)
            {
                reasonForNotAnalyzing = RuleResources.BA2005_MissingRequiredConfiguration;
                if (context.Policy == null) { return AnalysisApplicability.NotApplicableDueToMissingConfiguration; }
            }
            return applicability;
        }
        internal static AnalysisApplicability CommonCanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
        {
            PE portableExecutable = context.PE;
            AnalysisApplicability result = AnalysisApplicability.NotApplicableToSpecifiedTarget;

            reasonForNotAnalyzing = MetadataConditions.ImageIsResourceOnlyBinary;
            if (portableExecutable.IsResourceOnly) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsILOnlyManagedAssembly;
            if (portableExecutable.IsILOnly) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsXBoxBinary;
            if (portableExecutable.IsXBox) { return result; }

            return AnalysisApplicability.ApplicableToSpecifiedTarget;
        }
        public override AnalysisApplicability CanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
        {
            PE portableExecutable = context.PE;
            AnalysisApplicability result = AnalysisApplicability.NotApplicableToSpecifiedTarget;

            reasonForNotAnalyzing = MetadataConditions.ImageIsNot64BitBinary;
            if (context.PE.PEHeaders.PEHeader.Magic != PEMagic.PE32Plus) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsKernelModeBinary;
            if (portableExecutable.IsKernelMode) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsResourceOnlyBinary;
            if (portableExecutable.IsResourceOnly) { return result; }

            return AnalysisApplicability.ApplicableToSpecifiedTarget;
        }
        public override AnalysisApplicability CanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
        {
            PE portableExecutable = context.PE;
            AnalysisApplicability result = AnalysisApplicability.NotApplicableToSpecifiedTarget;

            reasonForNotAnalyzing = MetadataConditions.ImageIsKernelModeBinary;
            if (portableExecutable.IsKernelMode) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsXBoxBinary;
            if (portableExecutable.IsXBox) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsPreVersion7WindowsCEBinary;
            if (OSVersions.IsWindowsCEPriorToV7(portableExecutable)) { return result; }

            return AnalysisApplicability.ApplicableToSpecifiedTarget;
        }
        public override AnalysisApplicability CanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
        {
            PE portableExecutable = context.PE;
            AnalysisApplicability result = AnalysisApplicability.NotApplicableToSpecifiedTarget;

            reasonForNotAnalyzing = MetadataConditions.ImageIsKernelModeBinary;
            if (portableExecutable.IsKernelMode) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsNot64BitBinary;
            if (portableExecutable.PEHeaders.PEHeader.Magic != PEMagic.PE32Plus) { return result; }

            // TODO need to put a check here for verifying that the
            // compiler that built the target supports high entropy va                       

            return AnalysisApplicability.ApplicableToSpecifiedTarget;
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEHeader peHeader = context.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 (context.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()));
        }
        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));
        }
        public override AnalysisApplicability CanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
        {
            PE portableExecutable = context.PE;
            AnalysisApplicability result = AnalysisApplicability.NotApplicableToSpecifiedTarget;

            reasonForNotAnalyzing = MetadataConditions.ImageIsILOnlyManagedAssembly;
            if (portableExecutable.IsILOnly) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsResourceOnlyBinary;
            if (portableExecutable.IsResourceOnly) { return result; }

            // Checks for missing policy should always be evaluated as the last action, so that 
            // we do not raise an error in cases where the analysis would not otherwise be applied.
            reasonForNotAnalyzing = RuleResources.BA2005_MissingRequiredConfiguration;
            if (context.Policy == null) { return AnalysisApplicability.NotApplicableDueToMissingConfiguration; }

            return AnalysisApplicability.ApplicableToSpecifiedTarget;
        }
        public override void Initialize(BinaryAnalyzerContext context)
        {
            if (context.Policy == null) { return; }

            _files = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
            _filesToVulnerabilitiesMap = new Dictionary<string, VulnerableDependencyDescriptor>();

            foreach (VulnerableDependencyDescriptor descriptor in context.Policy.GetProperty(VulnerableDependencies).Values)
            {
                foreach (string fileHash in descriptor.FileHashes)
                {
                    _filesToVulnerabilitiesMap[fileHash] = descriptor;
                    _files.Add(fileHash.Split('#')[0]);
                }
            }

            return;
        }
        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(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)
        {
            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(ResultKind.Error, context, null,
                        nameof(RuleResources.BA2008_Fail)));
                return;
            }

            // '{0}' enables the control flow guard mitigation.
            context.Logger.Log(this,
                RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                    nameof(RuleResources.BA2008_Pass)));
        }
Exemple #20
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            Native.WINTRUST_DATA winTrustData;
            string algorithmName, filePath;

            filePath = context.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 image was signed with '{1}',
                // cryptographically strong algorithm(s).
                context.Logger.Log(this,
                    RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                        nameof(RuleResources.BA2022_Pass),
                        context.TargetUri.GetFileName(),
                        algorithmName));
            }
        }
        internal static AnalysisApplicability CommonCanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
        {
            PE portableExecutable = context.PE;
            AnalysisApplicability result = AnalysisApplicability.NotApplicableToSpecifiedTarget;

            reasonForNotAnalyzing = MetadataConditions.ImageIsResourceOnlyBinary;
            if (portableExecutable.IsResourceOnly) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsILOnlyManagedAssembly;
            if (portableExecutable.IsILOnly) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsXBoxBinary;
            if (portableExecutable.IsXBox) { return result; }

            // .NET native compiled binaries are not fully /GS enabled. This is
            // considered reasonable, as the binaries themselves consist strictly
            // of cross-compiled MSIL. The supporting native libraries for these
            // applications exists in a separate (/GS enabled) native dll.
            reasonForNotAnalyzing = MetadataConditions.ImageIsDotNetNativeBinary;
            if (portableExecutable.IsDotNetNative) { return result; }

            reasonForNotAnalyzing = null;
            return AnalysisApplicability.ApplicableToSpecifiedTarget;
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEHeader peHeader = context.PE.PEHeaders.PEHeader;

            if (context.Pdb == null)
            {
                Errors.LogExceptionLoadingPdb(context, context.PdbParseException.Message);
                return;
            }

            Pdb di = context.Pdb;

            TruncatedCompilandRecordList warningTooLowModules = new TruncatedCompilandRecordList();
            TruncatedCompilandRecordList disabledWarningModules = new TruncatedCompilandRecordList();
            TruncatedCompilandRecordList unknownLanguageModules = new TruncatedCompilandRecordList();
            TruncatedCompilandRecordList allWarningLevelLowModules = new TruncatedCompilandRecordList();

            string exampleTooLowWarningCommandLine = null;
            int overallMinimumWarningLevel = Int32.MaxValue;
            string exampleDisabledWarningCommandLine = null;
            List<int> overallDisabledWarnings = new List<int>();

            foreach (DisposableEnumerableView<Symbol> omView in di.CreateObjectModuleIterator())
            {
                Symbol om = omView.Value;
                ObjectModuleDetails omDetails = om.GetObjectModuleDetails();
                if (omDetails.Language == Language.Unknown)
                {
                    // See if this module contributed to an executable section. If not, we can ignore the module.
                    if (di.CompilandWithIdIsInExecutableSectionContrib(om.SymIndexId))
                    {
                        unknownLanguageModules.Add(om.CreateCompilandRecord());
                    }

                    continue;
                }

                if ((omDetails.Language != Language.C) && (omDetails.Language != Language.Cxx))
                {
                    continue;
                }

                if (omDetails.Compiler != "Microsoft (R) Optimizing Compiler")
                {
                    continue;
                }

                if (!om.CreateChildIterator(SymTagEnum.SymTagFunction).Any())
                {
                    // uninteresting...
                    continue;
                }

                int warningLevel = omDetails.WarningLevel;
                List<int> requiredDisabledWarnings = omDetails.ExplicitlyDisabledWarnings
                    .Where(context.Policy.GetProperty(RequiredCompilerWarnings).Contains).ToList();

                if (warningLevel >= 3 && requiredDisabledWarnings.Count == 0)
                {
                    // We duplicate this condition to bail out early and avoid writing the
                    // module description or newline into sbBadWarningModules if everything
                    // in the module is OK.
                    continue;
                }

                List<string> suffix = new List<string>(2);

                overallMinimumWarningLevel = Math.Min(overallMinimumWarningLevel, warningLevel);
                if (warningLevel < 3)
                {
                    exampleTooLowWarningCommandLine = exampleTooLowWarningCommandLine ?? omDetails.CommandLine;

                    string msg = "[warning level: " + warningLevel.ToString(CultureInfo.InvariantCulture) + "]";
                    warningTooLowModules.Add(om.CreateCompilandRecordWithSuffix(msg));
                    suffix.Add(msg);
                }

                if (requiredDisabledWarnings.Count != 0)
                {
                    MergeInto(overallDisabledWarnings, requiredDisabledWarnings);
                    exampleDisabledWarningCommandLine = exampleDisabledWarningCommandLine ?? omDetails.CommandLine;

                    string msg = "[Explicitly disabled warnings: " + CreateTextWarningList(requiredDisabledWarnings) + "]";
                    disabledWarningModules.Add(om.CreateCompilandRecordWithSuffix(msg));
                    suffix.Add(msg);
                }

                allWarningLevelLowModules.Add(om.CreateCompilandRecordWithSuffix(String.Join(" ", suffix)));
            }

            if (unknownLanguageModules.Empty &&
                exampleTooLowWarningCommandLine == null &&
                exampleDisabledWarningCommandLine == null)
            {
                // '{0}' was compiled at a secure warning level ({1}) and does not 
                // include any modules that disable specific warnings which are 
                // required by policy. As a result, there is a greater likelihood 
                // that memory corruption, information disclosure, double-free and 
                // other security-related vulnerabilities do not exist in code.
                context.Logger.Log(this,
                    RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                        nameof(RuleResources.BA2007_Pass), 
                        overallMinimumWarningLevel.ToString()));
                return;
            }

            if (!unknownLanguageModules.Empty)
            {
                // '{0}' contains code from an unknown language, preventing a 
                // comprehensive analysis of the compiler warning settings. 
                // The language could not be identified for the following modules: {1}
                context.Logger.Log(this, 
                    RuleUtilities.BuildResult(ResultKind.Error, context, null,
                        nameof(RuleResources.BA2007_Fail_UnknownModuleLanguage),
                        unknownLanguageModules.CreateSortedObjectList()));
            }

            if (exampleTooLowWarningCommandLine != null)
            {
                // '{0}' was compiled at too low a warning level. Warning level 3 enables 
                // important static analysis in the compiler to flag bugs that can lead 
                // to memory corruption, information disclosure, or double-free 
                // vulnerabilities.To resolve this issue, compile at warning level 3 or 
                // higher by supplying / W3, / W4, or / Wall to the compiler, and resolve 
                // the warnings emitted.
                // An example compiler command line triggering this check: {1}
                // Modules triggering this check: {2}
                context.Logger.Log(this,
                    RuleUtilities.BuildResult(ResultKind.Error, context, null,
                        nameof(RuleResources.BA2007_Fail_InsufficientWarningLevel),
                        overallMinimumWarningLevel.ToString(),
                        exampleTooLowWarningCommandLine,
                        warningTooLowModules.CreateTruncatedObjectList()));
            }

            if (exampleDisabledWarningCommandLine != null)
            {
                // '{0}' disables compiler warning(s) which are required by policy. A 
                // compiler warning is typically required if it has a high likelihood of 
                // flagging memory corruption, information disclosure, or double-free 
                // vulnerabilities. To resolve this issue, enable the indicated warning(s) 
                // by removing /Wxxxx switches (where xxxx is a warning id indicated here) 
                // from your command line, and resolve any warnings subsequently raised 
                // during compilation.
                // An example compiler command line triggering this check was: {1}
                // Modules triggering this check were: {2}
                context.Logger.Log(this,
                    RuleUtilities.BuildResult(ResultKind.Error, context, null,
                        nameof(RuleResources.BA2007_Fail_WarningsDisabled),
                        exampleDisabledWarningCommandLine,
                        disabledWarningModules.CreateTruncatedObjectList()));
            }
        }
Exemple #23
0
 public static bool IsELF(this BinaryAnalyzerContext target)
 {
     return(target.Binary is ELFBinary ret);
 }
        private bool EnablesControlFlowGuard(BinaryAnalyzerContext context)
        {
            PEHeader peHeader = context.PE.PEHeaders.PEHeader;
            if (((uint)peHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_CONTROLFLOWGUARD) == 0)
            {
                return false;
            }

            SafePointer loadConfigRVA = new SafePointer(context.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress);
            if (loadConfigRVA.Address == 0)
            {
                return false;
            }

            SafePointer loadConfigVA = context.PE.RVA2VA(loadConfigRVA);

            if (context.PE.Is64Bit)
            {
                ImageLoadConfigDirectory64 loadConfig = new ImageLoadConfigDirectory64(peHeader, loadConfigVA);

                Int32 imageDirectorySize = (Int32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.Size);
                UInt64 guardCFCheckFunctionPointer = (UInt64)loadConfig.GetField(ImageLoadConfigDirectory64.Fields.GuardCFCheckFunctionPointer);
                UInt64 guardCFFunctionTable = (UInt64)loadConfig.GetField(ImageLoadConfigDirectory64.Fields.GuardCFFunctionTable);
                UInt32 guardFlags = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory64.Fields.GuardFlags);

                if (imageDirectorySize >= IMAGE_LOAD_CONFIG_MINIMUM_SIZE_64 &&
                    guardCFCheckFunctionPointer != 0 &&
                    guardCFFunctionTable != 0 &&
                    (guardFlags & IMAGE_GUARD_CF_CHECKS) == IMAGE_GUARD_CF_CHECKS)
                {
                    return true;
                }
            }
            else
            {
                ImageLoadConfigDirectory32 loadConfig = new ImageLoadConfigDirectory32(peHeader, loadConfigVA);

                Int32 imageDirectorySize = (Int32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.Size);
                UInt32 guardCFCheckFunctionPointer = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.GuardCFCheckFunctionPointer);
                UInt32 guardCFFunctionTable = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.GuardCFFunctionTable);
                UInt32 guardFlags = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.GuardFlags);

                if (imageDirectorySize >= IMAGE_LOAD_CONFIG_MINIMUM_SIZE_32 &&
                    guardCFCheckFunctionPointer != 0 &&
                    guardCFFunctionTable != 0 &&
                    (guardFlags & IMAGE_GUARD_CF_CHECKS) == IMAGE_GUARD_CF_CHECKS)
                {
                    return true;
                }
            }

            return false;
        }
 public override AnalysisApplicability CanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
 {
     return StackProtectionUtilities.CommonCanAnalyze(context, out reasonForNotAnalyzing);
 }
 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(ResultKind.Error, context, null,
             nameof(RuleResources.BA2012_Fail),
             cookie));
 }
 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(ResultKind.Error, context, null,
             nameof(RuleResources.BA2012_Fail_CouldNotLocateCookie)));
 }
        private bool Validate32BitImage(BinaryAnalyzerContext context)
        {
            PEHeader peHeader = context.PE.PEHeaders.PEHeader;
            SafePointer sp = new SafePointer(context.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress);
            SafePointer loadConfigVA = context.PE.RVA2VA(sp);
            ImageLoadConfigDirectory32 loadConfig = new ImageLoadConfigDirectory32(peHeader, loadConfigVA);

            UInt32 cookieVA = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.SecurityCookie);
            UInt32 baseAddress = (UInt32)peHeader.ImageBase;

            // we need to find the offset in the file based on the cookie's VA
            UInt32 sectionSize, sectionVA = 0;
            SectionHeader ish = new SectionHeader();
            bool foundCookieSection = false;
            foreach (SectionHeader t in context.PE.PEHeaders.SectionHeaders)
            {
                sectionVA = (UInt32)t.VirtualAddress + baseAddress;
                sectionSize = (UInt32)t.VirtualSize;
                if ((cookieVA >= sectionVA) &&
                    (cookieVA < sectionVA + sectionSize))
                {
                    ish = t;
                    foundCookieSection = true;
                    break;
                }
            }

            if (!foundCookieSection)
            {
                LogCouldNotLocateCookie(context);
                return false;
            }

            UInt64 fileCookieOffset = (cookieVA - baseAddress) - (sectionVA - baseAddress) + (UInt32)ish.PointerToRawData;
            SafePointer fileCookiePtr = loadConfigVA;
            fileCookiePtr.Address = (int)fileCookieOffset;
            UInt32 cookie = BitConverter.ToUInt32(fileCookiePtr.GetBytes(8), 0);

            if (!StackProtectionUtilities.DefaultCookiesX86.Contains(cookie) && context.PE.Machine == Machine.I386)
            {
                LogFailure(context, cookie.ToString("x"));
                return false;
            }

            return true;
        }
Exemple #29
0
 public static bool IsPE(this BinaryAnalyzerContext target)
 {
     return(target.Binary is PEBinary);
 }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEHeader peHeader = context.PE.PEHeaders.PEHeader;
            Pdb pdb = context.Pdb;

            if (pdb == null)
            {
                Errors.LogExceptionLoadingPdb(context, context.PdbParseException);
                return;
            }

            List<string> names = new List<string>();
            foreach (DisposableEnumerableView<Symbol> functionView in pdb.CreateGlobalFunctionIterator())
            {
                Symbol function = functionView.Value;
                if (function.IsManaged) { continue; }
                if (!function.IsSafeBuffers) { continue; }

                string functionName = function.GetUndecoratedName();

                if (functionName == "__security_init_cookie" ||
                    context.Policy.GetProperty(ApprovedFunctionsThatDisableStackProtection).Contains(functionName))
                {
                    continue;
                }
                names.Add(functionName);
            }

            if (names.Count != 0)
            {
                string functionNames = string.Join(";", names);

                // '{0}' is a C or C++ binary built with function(s) ({1}) that disable 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. Disabling the stack protector, even on a
                // function -by-function basis, is disallowed by SDL policy. To resolve this
                // issue, remove occurrences of __declspec(safebuffers) from your code. If the
                // additional code inserted by the stack protector has been shown in profiling
                // to cause a significant performance problem for your application, attempt to
                // move stack buffer modifications out of the hot path of execution to allow the
                // compiler to avoid inserting stack protector checks in these locations rather
                // than disabling the stack protector altogether.
                context.Logger.Log(this,
                    RuleUtilities.BuildResult(ResultLevel.Error, context, null,
                        nameof(RuleResources.BA2014_Error),
                        context.TargetUri.GetFileName(),
                        functionNames));
                return;
            }

            // '{0}' is a C or C++ binary built with the stack protector buffer
            // security feature enabled which does not disable protection for
            // any individual functions (via __declspec(safebuffers), making it
            // more difficult for an attacker to exploit stack buffer overflow
            // memory corruption vulnerabilities.
            context.Logger.Log(this,
                RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                    nameof(RuleResources.BA2014_Pass),
                    context.TargetUri.GetFileName()));
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEHeader optionalHeader = context.PE.PEHeaders.PEHeader;

            if ((optionalHeader.DllCharacteristics & DllCharacteristics.DynamicBase) != DllCharacteristics.DynamicBase)
            {
                // '{0}' is not marked as DYNAMICBASE. This means that the binary is not eligible for relocation 
                // by Address Space Layout Randomization (ASLR). ASLR is an important mitigation that makes it 
                // more difficult for an attacker to exploit memory corruption vulnerabilities. To resolve this 
                // issue, configure your tool chain to build with this feature enabled. For C and C++ binaries, 
                // add /DYNAMICBASE to your linker command line. For .NET applications, use a compiler shipping 
                // with Visual Studio 2008 or later.
                context.Logger.Log(this,
                    RuleUtilities.BuildResult(ResultKind.Error, context, null,
                        nameof(RuleResources.BA2009_Fail_NotDynamicBase)));
                return;
            }

            CoffHeader coffHeader = context.PE.PEHeaders.CoffHeader;

            if ((coffHeader.Characteristics & Characteristics.RelocsStripped) == Characteristics.RelocsStripped)
            {
                // '{0}' is marked as DYNAMICBASE but relocation data has been stripped
                // from the image, preventing address space layout randomization. 
                context.Logger.Log(this,
                    RuleUtilities.BuildResult(ResultKind.Error, context, null,
                        nameof(RuleResources.BA2009_Fail_RelocsStripped)));
                return;
            }

            if (context.PE.Subsystem == Subsystem.WindowsCEGui)
            {
                Debug.Assert(context.PE.OSVersion >= OSVersions.WindowsCE7);

                bool relocSectionFound = false;


                // For WinCE 7+ ASLR is a machine-wide setting and binaries must
                // have relocation info present in order to be dynamically rebased.
                foreach (SectionHeader sectionHeader in context.PE.PEHeaders.SectionHeaders)
                {
                    if (sectionHeader.Name.Equals(".reloc", StringComparison.OrdinalIgnoreCase) &&
                        sectionHeader.SizeOfRawData > 0)
                    {
                        relocSectionFound = true;
                        break;
                    }
                }

                if (!relocSectionFound)
                {
                    // EnableAddressSpaceLayoutRandomization_WinCENoRelocationSection_Fail	'{0}'
                    // is a Windows CE image but does not contain any relocation data, preventing 
                    // address space layout randomization.	
                    context.Logger.Log(this,
                        RuleUtilities.BuildResult(ResultKind.Error, context, null,
                            nameof(RuleResources.BA2009_Fail_WinCENoRelocationSection)));
                    return;
                }
            }

            //'{0}' is properly compiled to enable address space layout randomization.
            context.Logger.Log(this,
                RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                    nameof(RuleResources.BA2009_Pass)));
        }
        public override AnalysisApplicability CanAnalyze(BinaryAnalyzerContext context, out string reasonForNotAnalyzing)
        {
            PE portableExecutable = context.PE;
            AnalysisApplicability result = AnalysisApplicability.NotApplicableToSpecifiedTarget;

            reasonForNotAnalyzing = MetadataConditions.ImageIsKernelModeBinary;
            if (portableExecutable.IsKernelMode) { return result; }

            reasonForNotAnalyzing = MetadataConditions.ImageIsILOnlyManagedAssembly;
            if (portableExecutable.IsILOnly) { return result; }

            reasonForNotAnalyzing = null;
            return AnalysisApplicability.ApplicableToSpecifiedTarget;
        }