From 774ab1197d11d2004bce3584aaa1698709385460 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 4 Aug 2021 15:00:13 +0200 Subject: [PATCH 01/16] Adding PingCastle Parser Signed-off-by: Sebastian --- scanners/pingcastle/parser/Dockerfile | 16 + .../__testFiles__/ad_hc_test.domain.com.html | 5755 +++++++++++++++++ .../__testFiles__/ad_hc_test.domain.com.xml | 1 + scanners/pingcastle/parser/package-lock.json | 32 + .../parser/package-lock.json.license | 3 + scanners/pingcastle/parser/package.json | 17 + .../pingcastle/parser/package.json.license | 3 + scanners/pingcastle/parser/parser.js | 83 + scanners/pingcastle/parser/parser.test.js | 209 + 9 files changed, 6119 insertions(+) create mode 100644 scanners/pingcastle/parser/Dockerfile create mode 100644 scanners/pingcastle/parser/__testFiles__/ad_hc_test.domain.com.html create mode 100644 scanners/pingcastle/parser/__testFiles__/ad_hc_test.domain.com.xml create mode 100644 scanners/pingcastle/parser/package-lock.json create mode 100644 scanners/pingcastle/parser/package-lock.json.license create mode 100644 scanners/pingcastle/parser/package.json create mode 100644 scanners/pingcastle/parser/package.json.license create mode 100644 scanners/pingcastle/parser/parser.js create mode 100644 scanners/pingcastle/parser/parser.test.js diff --git a/scanners/pingcastle/parser/Dockerfile b/scanners/pingcastle/parser/Dockerfile new file mode 100644 index 0000000000..0ab13ef768 --- /dev/null +++ b/scanners/pingcastle/parser/Dockerfile @@ -0,0 +1,16 @@ +# SPDX-FileCopyrightText: 2020 iteratec GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +ARG namespace +ARG baseImageTag +FROM node:14-alpine as build +RUN mkdir -p /home/app +WORKDIR /home/app +COPY package.json package-lock.json ./ +RUN npm ci --production + +FROM ${namespace:-securecodebox}/parser-sdk-nodejs:${baseImageTag:-latest} +WORKDIR /home/app/parser-wrapper/parser/ +COPY --from=build --chown=app:app /home/app/node_modules/ ./node_modules/ +COPY --chown=app:app parser.js ./parser.js diff --git a/scanners/pingcastle/parser/__testFiles__/ad_hc_test.domain.com.html b/scanners/pingcastle/parser/__testFiles__/ad_hc_test.domain.com.html new file mode 100644 index 0000000000..38605b52b0 --- /dev/null +++ b/scanners/pingcastle/parser/__testFiles__/ad_hc_test.domain.com.html @@ -0,0 +1,5755 @@ + + + + + + + + + + +test.domain.com PingCastle 2021-08-04 + + + + + + + + + + + + + + + + +
+ +

test.domain.com - Healthcheck analysis

+

Date: 2021-08-04 - Engine version: 2.9.2.0

+
+This report has been generated with the Basic Edition of PingCastle ?. +
Being part of a commercial package is forbidden (selling the information contained in the report).
+If you are an auditor, you MUST purchase an Auditor license to share the development effort.
+
+ + +
+
+
+
+
+ +
+

This section focuses on the core security indicators.
Locate the sub-process determining the score and fix some rules in that area to get a score improvement.

+ +
+

Indicators

+
+ +
+
+
050100
+
+
+

Domain Risk Level: 60 / 100

+

It is the maximum score of the 4 indicators and one score cannot be higher than 100. The lower the better

+
+
+
+ +
+
+
+
050100
+
+
+

Stale Object : 25 /100

+

It is about operations related to user or computer objects

+
+
+

3 rules matched

+
+
+
+ +
+
+
+
050100
+
+
+

Trusts : 0 /100

+

It is about links between two Active Directories

+
+
+

0 rules matched

+
+
+
+ +
+
+
+
050100
+
+
+

Privileged Accounts : 60 /100

+

It is about administrators of the Active Directory

+
+
+

4 rules matched

+
+
+
+ +
+
+
+
050100
+
+
+

Anomalies : 50 /100

+

It is about specific security control points

+
+
+

9 rules matched

+
+
+
+ +
+ + +
+
+ + + + + +
Stale ObjectsPrivileged accountsTrustsAnomalies
Inactive user or computer
Account take over
Old trust protocol
Audit
Network topography
ACL Check
SID Filtering
Backup
Object configuration
Admin control
SIDHistory
Certificate take over
Obsolete OS
Control paths
Trust impermeability
Golden ticket
Old authentication protocols
Delegation Check
Trust inactive
Local group vulnerability
Provisioning
Irreversible change
Trust with Azure
Network sniffing
Replication
Privilege control
Pass-the-credential
Vulnerability management
Read-Only Domain Controllers
Password retrieval
Reconnaissance
Temporary admins
Weak password
+
+
+ Legend:
+   score is 0 - no risk identified but some improvements detected
+   score between 1 and 10 - a few actions have been identified
+   score between 10 and 30 - rules should be looked with attention
+   score higher than 30 - major risks identified +
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+

This section represents the maturity score (inspired from ANSSI).

This feature is reserved for customers who have purchased a license

+
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+ +
+
+
+
050100
+
+
+

Stale Objects : 25 /100

+

It is about operations related to user or computer objects

+
+
+
+ + +
+ + +
+
+ +
+ + + ++ 10 Point(s) +
+ +
+
+

DC Vulnerability (SMB v1)

+Rule ID:

S-SMB-v1

+Description:

The purpose is to verify if Domain Controller(s) are vulnerable to the SMB v1 vulnerability

+Technical explanation:

The SMB downgrade attack is used to obtain credentials or executing commands on behalf of a user by using SMB v1 as protocol. Indeed, because SMB v1 supports old authentication protocol, the integrity can be bypassed

+Advised solution:

It is highly recommended by Microsoft to disable SMB v1 whenever it is possible on both client and server side. Do note that if you are still not following best practices regarding the usage of deprecated OS (Windows 2000, 2003, XP, CE), regarding Network printer using SMBv1 scan2shares functionalities, or regarding software accessing Windows share with a custom implementation relying on SMB v1, you should consider fixing this issues before disabling SMB v1, as it will generates additional errors.

+Points:

10 points if present

+Documentation:

https://github.com/lgandx/Responder-Windows
+https://blogs.technet.microsoft.com/josebda/2015/04/21/the-deprecation-of-smb1-you-should-be-planning-to-get-rid-of-this-old-smb-dialect
+https://docs.microsoft.com/windows-server/storage/file-server/troubleshoot/detect-enable-and-disable-smbv1-v2-v3
+[FR]ANSSI CERTFR-2017-ACT-019
+[FR]ANSSI CERTFR-2016-ACT-039

Details:

The detail can be found in Domain controllers

+
+ +
Domain controller
WIN-GH3R6KE1P1Q
+
+
+
+ + + ++ 10 Point(s) +
+ +
+
+

Check the process of registration of computers to the domain

+Rule ID:

S-ADRegistration

+Description:

The purpose is to ensure that basic users cannot register extra computers in the domain

+Technical explanation:

By default, a basic user can register up to 10 computers within the domain. This default configuration represents a security issue as basic users shouldn't be able to create such accounts and this task should be handled by administrators.

+Advised solution:

To solve the issue limit the number of extra computers that can be registered by a basic user. It can be reduced by modifying the value of ms-DS-MachineAccountQuota to zero (0). Another solution can be to remove altogether the authenticated users group in the domain controllers policy. Do note that if you need to set delegation to an account so it can add computers to the domain, it can be done through 2 methods: Delegation in the OU or by assigning the SeMachineAccountPrivilege to a special group

+Points:

10 points if present

+Documentation:

https://docs.microsoft.com/troubleshoot/windows-server/identity/default-workstation-numbers-join-domain
+http://prajwaldesai.com/allow-domain-user-to-add-computer-to-domain/
+http://blog.backslasher.net/preventing-users-from-adding-computers-to-a-domain.html

+
+
+
+ + + ++ 5 Point(s) +
+ +
+
+

Check for completeness of network declaration

+Rule ID:

S-DC-SubnetMissing

+Description:

The purpose is to ensure that the minimum set of subnet(s) has been configured in the domain

+Technical explanation:

When multiple sites are created in a domain, networks should be declared in the domain in order to optimize processes such as DC attribution. In addition, PingCastle can collect the information to be able to build a network map. This rule has been triggered because at least one domain controller has an IP address which was not found in subnet declaration. These IP addresses have been collected by querying the DC FQDN IP address in both IPv6 and IPv4 format.

+Advised solution:

Locate the IP address which was found as not being part of declared subnet then add this subnet to the "Active Directory Sites" tool. If you have found IPv6 addresses and it was not expected, you should disable the IPv6 protocol on the network card.

+Points:

5 points if present

+Details:

The detail can be found in Domain controllers

+
+ +
Domain controllerip
WIN-GH3R6KE1P1Q 10.0.2.15
+
+
+ + +
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+ +
+
+
+
050100
+
+
+

Privileged Accounts : 60 /100

+

It is about administrators of the Active Directory

+
+
+
+ + +
+ + +
+
+ +
+ + + ++ 20 Point(s) +
+ +
+
+

At least one Administrator Account can be delegated

+Rule ID:

P-Delegated

+Description:

The purpose is to ensure that all Administrator Accounts have the configuration flag "this account is sensitive and cannot be delegated" (and are not member of the built-in group "Protected Users" when your domain functional level is at least Windows Server 2012 R2).

+Technical explanation:

Without the flag "This account is sensitive and cannot be delegated" any account can be impersonated by some service account. It is a best practice to enforce this flag on administrators accounts.

+Advised solution:

To correct the situation, you should make sure that all your Administrator Accounts has the check-box "This account is sensitive and cannot be delegated" active or add your Administrator Accounts to the built-in group "Protected Users" if your domain functional level is at least Windows Server 2012 R2 (some functionalities may not work properly afterwards, you should check the official documentation). Please note that there is a section bellow in this report named "Admin Groups" which give more information.

+Points:

20 points if present

+Documentation:

[US]STIG V-36435 - Delegation of privileged accounts must be prohibited.

Details:

The detail can be found in Admin Groups

+
+
+
+ + + ++ 20 Point(s) +
+ +
+
+

Check for Native administrator usage

+Rule ID:

P-AdminLogin

+Description:

The purpose is to verify if the Native Administrator account is used.

+Technical explanation:

The Native Administrator account is the main administrator account, and it is sharing its password with Directory Services Restore Mode password. Since it is the same password, it can be used to take control of the domain even if the account is disabled, notably through a DSync attack. The last login date is retrieved through the LastLogonTimestamp LDAP attribute retrieved from the Active Directory. There is an exception for 35 days to avoid this rule to be triggered at the domain creation.

+Advised solution:

To mitigate the security risk, a good practice is to use the Native Administrator account only for emergency, while the daily work is performed through other accounts.
+ It is indeed strongly recommended to not use this account but to use nominative account for administrators and dedicated account for services.
+ Do note that the anomaly will be removed 35 days after the last native administrator login.
+
+ To track where the administrator account has been used for the last time, we recommend to extract the attribute LastLogon of the administrator account on ALL domain controllers.
+ It can be done with tools such as ADSIEdit or ADExplorer.
+ Then, for each domain controller, extract the events 4624 at the date matching the LastLogon date. You will identify the computer and the process at the origin of the logon event.
+
+ Please note that PingCastle relies on the attribute LastLogonTimestamp to perform this check. The LastLogonTimestamp attribute is replicated but has a latency of a maximum of 14 days, while LastLogon is updated at each logon and is more accurate but not replicated.
+

+Points:

20 points if the occurence is strictly lower than 35

+Documentation:

https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/implementing-least-privilege-administrative-models

+
+
+
+ + + ++ 10 Point(s) +
+ +
+
+

Avoid unexpected schema modifications which could result in domain rebuild

+Rule ID:

P-SchemaAdmin

+Description:

The purpose is to ensure that no account can make unexpected modifications to the schema

+Technical explanation:

The group "Schema Admins" is used to give permissions to alter the schema. Once a modification is performed on the schema such as new objects, it cannot be undone. This can result in a rebuild of the domain. The best practice is to have this group empty and to add an administrator when a schema update is required then to remove this group membership.

+Advised solution:

Remove the accounts or groups belonging to the "schema administrators" group.

+Points:

10 points if present

+Documentation:

[US]STIG V-72835 - Membership to the Schema Admins group must be limited
+[FR]ANSSI - Recommandations de sécurité relatives à Active Directory - R13 [subsection.3.2]

Details:

The detail can be found in Admin Groups

+
+
+
+ + + ++ 10 Point(s) +
+ +
+
+

Ensure that the Recycle Bin feature is enabled

+Rule ID:

P-RecycleBin

+Description:

The purpose is to ensure that the Recycle Bin feature is enabled

+Technical explanation:

The Recycle Bin avoids immediate deletion of objects (which can still be partially recovered by its tombstone). This lowers the administration work needed to restore. It also extends the period where traces are available when an investigation is needed.

+Advised solution:

First, be sure that the forest level is at least Windows 2008 R2.
+ You can check it with Get-ADForest or in the Domain Information section.
+ Then you can enable it using the powershell command:
+Enable-ADOptionalFeature -identity 'CN=Recycle Bin Feature,CN=Optional Features,CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=test,DC=mysmartlogon,DC=com' -Scope ForestOrConfigurationSet -Target 'test.mysmartlogon.com'

+Points:

10 points if present

+Documentation:

https://enterinit.com/powershell-enable-active-directory-recycle-bin

Details:

The detail can be found in Domain Information

+
+
+ + +
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+

Trusts

+
+
+ +
+
+
+
050100
+
+
+

Trusts : 0 /100

+

It is about links between two Active Directories

+
+
+
+ + +
+

No rule matched

+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+ +
+
+
+
050100
+
+
+

Anomalies : 50 /100

+

It is about specific security control points

+
+
+
+ + +
+ + +
+
+ +
+ + + ++ 15 Point(s) +
+ +
+
+

Check if the LAPS tool to handle the native local administrator password is installed

+Rule ID:

A-LAPS-Not-Installed

+Description:

The purpose is to make sure that there is a proper password policy in place for the native local administrator account.

+Technical explanation:

LAPS (Local Administrator Password Solution) is the advised solution to handle passwords for the native local administrator account on all workstations, as it is a simple way to handle most of the subject.

+Advised solution:

If you don't have any provisioning process or password solution to manage local administrators, you should install the LAPS solution. If you mitigate the risk differently, you should add this rule as an exception, as the risk is covered.

+Points:

15 points if present

+Documentation:

https://www.microsoft.com/en-us/download/details.aspx?id=46899
+[US]STIG V-36438 - Local administrator accounts on domain systems must not share the same password.
+[FR]ANSSI CERTFR-2015-ACT-046

Details:

The detail can be found in LAPS

+
+
+
+ + + ++ 10 Point(s) +
+ +
+
+

Check if there is the expected audit policy on domain controllers.

+Rule ID:

A-AuditDC

+Description:

The purpose is to ensure that the audit policy on domain controllers collect the right set of events.

+Technical explanation:

To detect and mitigate an attack, the right set of events need to be collected.
+ The audit policy is a compromise between too much and too few events to collect.
+ To solve this problem, the suggested audit policy from adsecurity.org is checked against the audit policy in place.
+

+Advised solution:

Identify the Audit settings to apply and fix them.
+ Be aware that there are two places for audit settings.
+ For "Simple" audit configuration:
+ in Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Local Policies -> Audit Policies
+ For "Advanced" audit configuration:
+ in Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Advanced Audit Policy Configuration
+ Also be sure that the audit GPO is applied to all domain controllers, as the underlying object may be in a OU where the GPO is not applied.
+

+Points:

10 points if present

+Documentation:

https://adsecurity.org/?p=3299

Details:

The detail can be found in Audit settings +
+ The table below shows the settings that were not found as configured in GPO for a given domain controller.

+
+ +
TypeAuditProblemRationaleDomain controller
Advanced Policy Change / Authentication Policy Change No GPO check for audit success Collect events 4713, 4716, 4739, 4867, to track trust modifications WIN-GH3R6KE1P1Q
Advanced Account Management / Computer Account Management No GPO check for audit success Collect events 4741, 4742 to track computer changes WIN-GH3R6KE1P1Q
Advanced Detailed Tracking / DPAPI Activity No GPO check for audit success Collect event 4692 to track the export of DPAPI backup key WIN-GH3R6KE1P1Q
Advanced Account Logon / Kerberos Authentication Service No GPO check for audit success Collect events 4768, 4771 for kerberos authentication WIN-GH3R6KE1P1Q
Advanced Account Logon / Kerberos Service Ticket Operations No GPO check for audit success Collect events 4769 for kerberos authentication WIN-GH3R6KE1P1Q
Advanced Logon/Logoff / Logoff No GPO check for audit success Collect events 4634 for account logoff WIN-GH3R6KE1P1Q
Advanced Logon/Logoff / Logon No GPO check for audit success Collect events 4624, 4625, 4648 for account logon WIN-GH3R6KE1P1Q
Advanced Detailed Tracking / Process Creation No GPO check for audit success Collect event 4688 to get the history of executed programs WIN-GH3R6KE1P1Q
Advanced Account Management / Security Group Management No GPO check for audit success Collect events 4728, 4732, 4756 for group membership change WIN-GH3R6KE1P1Q
Advanced System / Security System Extension No GPO check for audit success Collect events 4610, 4697 to track lsass security packages and services WIN-GH3R6KE1P1Q
Advanced Privilege Use / Sensitive Privilege Use No GPO check for audit success Collect events 4672, 4673, 4674 for privileges tracking such as the debug one WIN-GH3R6KE1P1Q
Advanced Logon/Logoff / Special Logon No GPO check for audit success Collect event 4964 for special group attributed at logon WIN-GH3R6KE1P1Q
Advanced Account Management / User Account Management No GPO check for audit success Collect events 4720,22,23,38,65,66,80,94 for user account mamangement WIN-GH3R6KE1P1Q
+
+
+
+ + + ++ 10 Point(s) +
+ +
+
+

Check for Short password length in password policy

+Rule ID:

A-MinPwdLen

+Description:

The purpose is to verify if the password policy of the domain enforces users to have at least 8 characters in their password

+Technical explanation:

A check is performed to identify if the GPO regarding password policy allows less than 8 characters password. Short passwords represents a high risk because they can fairly easily be brute-forced. Most CERT and agencies advises for at least 8 characters (and often this number goes up to 12)

+Advised solution:

To solve the issue, the best way is to either remove the GPO enabling short password, or to modify it in order to increase the password length to at least 8 characters

+Points:

10 points if present

+Documentation:

https://www.microsoft.com/en-us/research/publication/password-guidance/
+[FR]ANSSI - Privileged group members with weak password policy (vuln2_privileged_members_password)2

Details:

The detail can be found in Password policies

+
+ +
GPO
Default Domain Policy
+
+
+
+ + + ++ 10 Point(s) +
+ +
+
+

Ensure that the printer spooler cannot be abused to get the DC Credentials

+Rule ID:

A-DC-Spooler

+Description:

The purpose is to ensure that credentials cannot be extracted from the DC via its printer spooler

+Technical explanation:

When there’s an account with unconstrained delegation configured (which is fairly common) and the Print Spooler service running on a computer, you can get that computers credentials sent to the system with unconstrained delegation as a user. With a domain controller, the TGT of the DC can be extracted allowing an attacker to reuse it with a DCSync attack and obtain all user hashes and impersonate them.

+Advised solution:

The spooler service should be deactivated on domain controllers. Please note as a consequence that the Printer Pruning functionality (rarely used) will be unavailable.

+Points:

10 points if present

+Documentation:

https://adsecurity.org/?p=4056
+https://www.slideshare.net/harmj0y/derbycon-the-unintended-risks-of-trusting-active-directory

Details:

The detail can be found in Domain controllers

+
+ +
Domain controller
WIN-GH3R6KE1P1Q
+
+
+
+ + + ++ 5 Point(s) +
+ +
+
+

Ensure that there are enough DCs to provide basic redundancy

+Rule ID:

A-NotEnoughDC

+Description:

The purpose is to ensure the failure of one domain controller will not stop the domain.

+Technical explanation:

A single domain controller failure can lead to a lack of availability of the domain if the number of servers is too low. To have a minimum redundancy, the number of DC should be at least 2. For Labs, this rule can be ignored and you can add this rule into the exception list.

+Advised solution:

Increase the number of domain controllers by installing new ones.

+Points:

5 points if the occurence is strictly lower than 2

+Documentation:

https://social.technet.microsoft.com/wiki/contents/articles/14355.capacity-planning-for-active-directory-domain-services.aspx

Details:

The detail can be found in Domain controllers

+
+
+
+ + + +Informative rule +
+ +
+
+

Check the Password Policy for Service Accounts (Information)

+Rule ID:

A-NoServicePolicy

+Description:

The purpose is to give information regarding a best practice for the Service Account password policy. Indeed, having a 20+ characters password for this account greatly helps reducing the risk behind Kerberoast attack (offline crack of the TGS tickets)
+Note: PSO (Password Settings Objects) will be visible only if the user which collected the information has the permission to view it.

+Technical explanation:

The rule is purely informative, as it gives insights regarding a best practice. It verifies if there is a GPO or PSO enforcing a 20+ characters password for the Service Account.

+Advised solution:

The recommended way to handle service accounts is to use "Managed service accounts" introduced since Windows 2008 R2 (search for "msDS-ManagedServiceAccount").
+To solve the anomaly, you should implement a PSO or GPO password guarantying a 20+ length password.

+Points:

Informative rule (0 point)

+Documentation:

https://www.microsoft.com/en-us/research/publication/password-guidance/

Details:

The detail can be found in Password Policies

+
+
+
+ + + +Informative rule +
+ +
+
+

Check if LLMNR can be used to steal credentials

+Rule ID:

A-NoGPOLLMNR

+Description:

The purpose is to ensure that local name resolution protocol (LLMNR) cannot be used to collect credentials by performing a network attack

+Technical explanation:

LLMNR is a protocol which translates names such as foo.bar.com into an ip address. LLMNR has been designed to translate name locally in case the default protocol DNS is not available.
+ Regarding Active Directory, DNS is mandatory which makes LLMNR useless.
+ LLMNR exploits typo mistakes or faster response time to redirect users to a specially designed share, server or website.
+ Being trusted, this service will trigger the single sign on procedure which can be abused to retrieve the user credentials.
+
+ LLMNR is enabled by default on all OS except starting from Windows 10 v1903 and Windows Server v1903 where it is disabled.
+

+Advised solution:

Enable the GPO Turn off multicast name resolution and check that no GPO override this setting.
+ (if it is the case, the policy involved will be displayed below)

+Points:

Informative rule (0 point)

+Documentation:

https://youtu.be/Fg2gvk0qgjM

Details:

The detail can be found in Security settings

+
+
+
+ + + +Informative rule +
+ +
+
+

Check if NetCease has been put in place to mitigate Bloodhound

+Rule ID:

A-NoNetSessionHardening

+Description:

The purpose is to ensure that mitigations are in place against the Bloodhound tool

+Technical explanation:

By default, Windows computers allow any authenticated user to enumerate network sessions to it.
+This means an attacker could enumerate network sessions to a file share hosting home directories or a Domain Controller to see who’s connected to SYSVOL (to apply Group Policy) and determine which workstations each user and admin account is logged into.
+Bloodhound uses this capability extensively to map out credentials in the network.
+
+Disabling Net Session Enumeration removes the capability for any user to enumerate net session info (Recon).

+Advised solution:

If this mitigation is not part of the computer image, apply the following recommandations:
+Run the NetCease PowerShell script (referenced below) on a reference workstation.
+Open the Group Policy Management Console. Right-click the Group Policy object (GPO) that should contain the new preference item, and then click Edit .
+In the console tree under Computer Configuration, expand the Preferences folder, and then expand the Windows Settings folder.
+Right-click the Registry node, point to New, and select Registry Wizard.
+Select the reference workstation on which the desired registry settings exist, then click Next .
+Browse to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\DefaultSecurity\
+and select the check box for “SrvsvcSessionInfo” from which you want to create a Registry preference item. Select the check box for a key only if you want to create a Registry item for the key rather than for a value within the key.
+Click Finish.
+The settings that you selected appear as preference items in the Registry Wizard Values collection

+Points:

Informative rule (0 point)

+Documentation:

https://github.com/p0w3rsh3ll/NetCease
+https://adsecurity.org/?p=3299

Details:

The detail can be found in Security settings

+
+
+
+ + + +Informative rule +
+ +
+
+

Check if there is powershell logging enabled.

+Rule ID:

A-AuditPowershell

+Description:

The purpose is to ensure that Powershell logging is enabled.

+Technical explanation:

Powershell is a powerful language, also used by hackers because of this quality. Hackers are able to run programs such as mimikatz in memory using obfuscated commands such as Invoke-Mimikatz.
+ Because there is no artefact on the disk, the incident response task is difficult for the forensic analysts.
+ For this reason, we recommend to enable Powershell logging via a group policy, despite the fact that these security settings may be part of the workstation or server images.
+

+Advised solution:

Go to Computer Configuration -> Administrative Templates -> Windows Components -> Windows PowerShell
+And enable "Turn on Module logging" and "Turn on Powershell Script Block logging"
+We recommend to set "*" as the module list.
+

+Points:

Informative rule (0 point)

+Documentation:

https://adsecurity.org/?p=2604
+https://docs.microsoft.com/en-us/powershell/scripting/wmf/whats-new/script-logging?view=powershell-6
+[US]STIG V-68819 - PowerShell script block logging must be enabled

Details:

The detail can be found in Security settings

+
+
+ + +
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+

This section shows the main technical characteristics of the domain.

+
+
+ + + + + +
DomainNetbios NameDomain Functional LevelForest Functional LevelCreation dateDC countSchema versionRecycle Bin enabled
test.domain.comTESTWindows Server 2012 R2Windows Server 2012 R22021-08-04 19:42:19Z1Windows Server 2012 R2FALSE
+
+
+ +
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+

This section gives information about the user accounts stored in the Active Directory

+ + + +
+

Account analysis

+
+ +
+
+ + + + + +
Nb User AccountsNb Enabled ?Nb Disabled ?Nb Active ?Nb Inactive ?Nb Locked ?Nb pwd never Expire ?Nb SidHistory ?Nb Bad PrimaryGroup ?Nb Password not Req. ?Nb Des enabled. ?Nb unconstrained delegations ?Nb Reversible password ?
2111000000000
+
+
+ + +
+
+
+ + + + + +
+

Password Age Distribution

+
+

This feature is reserved for customers who have purchased a license

+
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+ + + + +
+

Account analysis

+
+

This section gives information about the computer accounts stored in the Active Directory

+
+
+ + + + + +
Nb Computer AccountsNb Enabled ?Nb Disabled ?Nb Active ?Nb Inactive ?Nb SidHistory ?Nb Bad PrimaryGroup ?Nb unconstrained delegations ?Nb Reversible password ?
110100010
+
+
+ + +
+
+ +
+ + + +[1] +
+ +
+
+ +
+
+ + + + + +
NameCreationLast logonDistinguished name
WIN-GH3R6KE1P1Q$2021-08-04 19:43:56Z2021-08-04 12:44:37ZCN=WIN-GH3R6KE1P1Q,OU=Domain Controllers,DC=test,DC=testuser,DC=com
+
+
+ +
+
+ + + + + +
+

Operating Systems

+
+ +
+
+ + + + + +
Operating SystemNb OSNb Enabled ?Nb Disabled ?Nb Active ?Nb Inactive ?Nb SidHistory ?Nb Bad PrimaryGroup ?Nb unconstrained delegations ?Nb Reversible password ?
Windows 2012110100010
+
+
+ + + + +
+

Domain controllers

+
+

Here is a specific zoom related to the Active Directory servers: the domain controllers.

+ +
+
+ +
+ + + +[1] +
+ +
+
+ +
+
+ + + + + +
Domain controllerOperating SystemCreation Date ?Startup TimeUptimeOwner ?Null sessions ?SMB v1 ?Remote spooler ?FSMO role ?
WIN-GH3R6KE1P1QWindows 20122021-08-04 19:43:56Z2021-08-04 05:36:41Z0 daysTEST\Domain AdminsNOYESYESPDC,
RID pool manager,
Infrastructure master,
Schema master,
Domain naming Master
+
+
+ +
+
+ + +
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+ + + + +
+

Groups

+
+

This section is focused on the groups which are critical for admin activities. If the report has been saved which the full details, each group can be zoomed with its members. If it is not the case, for privacy reasons, only general statictics are available.

+
+
+ + + + + +
Group NameNb Admins ?Nb Enabled ?Nb Disabled ?Nb Inactive ?Nb PWd never expire ?Nb Smart Card required ?Nb Service accounts ?Nb can be delegated ?Nb external users ?Nb protected users ?
Account Operators0000000000
Administrators1100000100
Backup Operators0000000000
Certificate Operators0000000000
Certificate Publishers0000000000
Dns Admins0000000000
Domain Administrators1100000100
Enterprise Administrators1100000100
Print Operators0000000000
Replicator0000000000
Schema Administrators1100000100
Server Operators0000000000
+
+
+ + + + + + + + + +
+
+ + +
+
+ +
+ + + +[1] +
+ +
+
+ +
+
+ + + + + +
SamAccountName ?Enabled ?Active ?Pwd never Expired ?Locked ?Smart Card required ?Service account ?Flag Cannot be delegated present ?Creation date ?Last login ?Password last set ?In Protected Users ?Distinguished name ?
AdministratorYESYESNONONONONO2021-08-04 19:42:31Z2021-08-04 12:49:50Z2021-08-04 11:20:33ZNOCN=Administrator,CN=Users,DC=test,DC=testuser,DC=com
+
+
+ +
+
+ +
+ + + +
+

Last Logon Distribution

+
+

This feature is reserved for customers who have purchased a license

+
+
+ + + + +
+

Delegations

+
+

Each specific rights defined for Organizational Unit (OU) are listed below.

+ +
+
+ +
+ + + +[6] +
+ +
+
+ +
+
+ + + + + +
DistinguishedNameAccountRight
DC=testTEST\Domain ControllersEXT_RIGHT_REPLICATION_GET_CHANGES_ALL
CN=MicrosoftDNS,CN=SystemNT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERSGenericWrite, WriteDacl, WriteOwner, All extended right, DSSelf, Write all prop
CN=MicrosoftDNS,CN=SystemTEST\DnsAdminsGenericWrite, WriteDacl, WriteOwner, All extended right, DSSelf, Write all prop
CN=RAS and IAS Servers Access Check,CN=SystemTEST\RAS and IAS ServersGenericWrite, WriteDacl, WriteOwner, All extended right, DSSelf, Write all prop
CN=WMIPolicy,CN=SystemTEST\Group Policy Creator OwnersGenericWrite, DSSelf, Write all prop
CN=SOM,CN=WMIPolicy,CN=SystemTEST\Group Policy Creator OwnersGenericWrite, DSSelf, Write all prop
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+

This section focuses on permissions issues that can be exploited to take control of the domain.
This is an advanced section that should be examined after having looked at the Admin Groups section.

+ + + +
+

Foreign domain involved

+
+

This analysis focuses on accounts found in control path and located in other domains.

No operative link with other domains has been found.

+ + + +
+

Indirect links

+
+

This part tries to summarize in a single table if major issues have been found.
Focus on finding critical objects such as the Everyone group then try to decrease the number of objects having indirect access.
The detail is displayed below.

+
+
+ + + + + +
Priority to remediate ?Critical Object Found ?Number of objects with Indirect ?Max number of indirect numbers ?Max ratio ?
CriticalNO000
HighNO000
MediumNO000
OtherNO000
+
+
+ + +
+

Admin groups

+
+

If the report has been saved which the full details, each object can be zoomed with its full detail. If it is not the case, for privacy reasons, only general statictics are available.

+
+
+ + + + + +
Group or user account ?Priority ?Number of users member of the group ?Number of computer member of the group ?Number of object having indirect control ?Number of unresolved members (removed?) ?Link with other domainsDetail
Account OperatorsHigh0000NoneAnalysis
AdministratorCritical00NoneAnalysis
AdministratorsCritical1 (Details)000NoneAnalysis
Backup OperatorsHigh0000NoneAnalysis
Certificate OperatorsMedium0000NoneAnalysis
Certificate PublishersOther0000NoneAnalysis
Dns AdminsMedium0000NoneAnalysis
Domain AdministratorsCritical1 (Details)000NoneAnalysis
Enterprise AdministratorsCritical1 (Details)000NoneAnalysis
Print OperatorsMedium0000NoneAnalysis
ReplicatorMedium0000NoneAnalysis
Schema AdministratorsCritical1 (Details)000NoneAnalysis
Server OperatorsHigh0000NoneAnalysis
+
+
+ + +
+

Critical Infrastructure

+
+

If the report has been saved which the full details, each object can be zoomed with its full detail. If it is not the case, for privacy reasons, only general statictics are available.

+
+
+ + + + + +
Group or user account ?Priority ?Number of users member of the group ?Number of computer member of the group ?Number of object having indirect control ?Number of unresolved members (removed?) ?Link with other domainsDetail
Builtin OUMedium00NoneAnalysis
Computers containerMedium00NoneAnalysis
Domain ControllersCritical01 (Details)00NoneAnalysis
Domain RootMedium00NoneAnalysis
Enterprise Read Only Domain ControllersOther0000NoneAnalysis
Group Policy Creator OwnersMedium1 (Details)000NoneAnalysis
Krbtgt accountMedium00NoneAnalysis
Read Only Domain ControllersMedium0000NoneAnalysis
Users containerMedium00NoneAnalysis
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+

This section focuses on the relations that this domain has with other domains

+ + + +
+

Discovered Domains

+
+

This part displays the direct links that this domain has with other domains.

+
+
+ + + + + +
Trust PartnerTypeAttributDirection ?SID Filtering active ?TGT Delegation ?Creation ?Is Active ? ?
+
+
+ + +
+

Reachable Domains

+
+

These are the domains that PingCastle was able to detect but which is not releated to direct trusts. It may be children of a forest or bastions.

+
+
+ + + + + +
Reachable domainDiscovered usingNetbiosCreation date
+
+
+ +
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+

Anomalies

+
+
+

This section focuses on security checks specific to the Active Directory environment.

+ + + +
+

Backup

+
+ +
+

The program checks the last date of the AD backup. This date is computed using the replication metadata of the attribute dsaSignature (reference).

+

Last backup date: Never

+
+ + + + +
+

LAPS

+
+ +
+

LAPS is used to have a unique local administrator password on all workstations / servers of the domain. +Then this password is changed at a fixed interval. The risk is when a local administrator hash is retrieved and used on other workstation in a pass-the-hash attack.

+

Mitigation: having a process when a new workstation is created or install LAPS and apply it through a GPO

+

LAPS installation date: Never

+
+ + +
+

Windows Event Forwarding (WEF)

+
+ +
+

Windows Event Forwarding is a native mechanism used to collect logs on all workstations / servers of the domain. +Microsoft recommends to Use Windows Event Forwarding to help with intrusion detection +Here is the list of servers configured for WEF found in GPO

+

Number of WEF configuration found: 0

+
+ + + + +
+

krbtgt (Used for Golden ticket attacks)

+
+ +
+

The account password for the krbtgt account should be rotated twice yearly at a minimum. More frequent password rotations are recommended, with 40 days the current recommendation by ANSSI. Additional rotations based on external events, such as departure of an employee who had privileged network access, are also strongly recommended.

+

You can perform this action using this script

+

You can use the version gathered using replication metadata from two reports to guess the frequency of the password change or if the two consecutive resets has been done. Version starts at 1.

+

Kerberos password last changed: 2021-08-04 12:43:57Z +version: 2 +

+
+ + + + +
+

AdminSDHolder (detect temporary elevated accounts)

+
+ +
+

This control detects accounts which are former 'unofficial' admins. +Indeed when an account belongs to a privileged group, the attribute admincount is set. If the attribute is set without being an official member, this is suspicious. To suppress this warning, the attribute admincount of these accounts should be removed after review.

+

Number of accounts to review: 0

+
+ + + + +
+

Unix Passwords

+
+ +
+

This control detects if one of the attributes userPassword or unixUserPassword has been set on accounts. +Indeed, these attributes are designed to store encrypted secrets for unix (or mainframe) interconnection. However in the large majority, interconnected systems are poorly designed and the user password is stored in these attributes in clear text or poorly encrypted. +The userPassword attribute is also used in classic LDAP systems to change the user password by setting its value. But, with Active Directory, it is considered by default as a normal attribute and doesn't trigger a password but shows instead the password in clear text. +

+

Number of accounts to review: 0

+
+ + + + +
+

Logon scripts

+
+

You can check here backdoors or typo error in the scriptPath attribute

+
+
+ + + + + + +
Script NameCount
None1
+
+
+ + + + +
+

Certificates

+
+ +
+
+

This detects trusted certificate which can be used in man in the middle attacks or which can issue smart card logon certificates

+

Number of trusted certificates: 0 +

+
+
+
+ + +
+
+ +
+ + + +[0] +
+ +
+
+ +
+
+ + + + + +
SourceStoreSubjectIssuerNotBeforeNotAfterModule sizeSignature AlgSC Logon
+
+
+ +
+
+ + +
+
+ + +
+

Advanced

+
+

This section display advanced information, if any has been found

+
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+ + + + +
+

Password policies

+
+

Note: PSO (Password Settings Objects) will be visible only if the user which collected the information has the permission to view it.
PSO shown in the report will be prefixed by "PSO:"

+
+
+ + + + + +
Policy NameComplexityMax Password AgeMin Password AgeMin Password LengthPassword HistoryReversible EncryptionLockout ThresholdLockout DurationReset account counter locker after
Default Domain Policy ?True42 day(s)1 day(s)724False0Not SetNot Set
+
+
+ + +
+

Screensaver policies

+
+

This is the settings related to screensavers stored in Group Policies. Each non compliant setting is written in red.

+
+
+ + + + + +
Policy NameScreensaver enforcedPassword requestStart after (seconds)Grace Period (seconds)
+
+
+ +
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+

GPO

+
+
+

This section focuses on security settings stored in the Active Directory technical security policies.

+ + + +
+

Obfuscated Passwords

+
+

The password in GPO are obfuscated, not encrypted. Consider any passwords listed here as compromised and change it immediatly.

+ +
+

Restricted Groups

+
+

Giving local group membership in a GPO is a way to become administrator.
The local admin of a domain controller can become domain administrator instantly.

+ + + +
+

Security settings

+
+

A GPO can be used to deploy security settings to workstations.
The best practice out of the default security baseline is reported in green.
The following settings in red are unsual and may need to be reviewed.
Each setting is accompagnied which its value and a link to the GPO explanation.

+
+
+ + + + + +
Policy NameSettingValue
+
+
+ + + + +
+

Audit settings

+
+

Audit settings allow the system to generate logs which are useful to detect intrusions. Here are the settings found in GPO.

Simple audit events are described here and Advanced audit events are described here

You can get a list of all audit settings with the command line: auditpol.exe /get /category:* (source)

Simple audit settings are located in: Computer Configuration / Policies / Windows Settings / Security Settings / Local Policies / Audit Policy. Simple audit settings are named [Simple Audit].

Advanced audit settings are located in: Computer Configuration / Policies / Windows Settings / Security Settings / Advanced Audit Policy Configuration. There category is displayed below.

+
+
+ + + + + +
Policy NameCategorySettingValue
+
+
+ + + + +
+

Privileges

+
+

Giving privileges in a GPO is a way to become administrator without being part of a group.
For example, SeTcbPriviledge give the right to act as SYSTEM, which has more privileges than the administrator account.

+
+
+ + + + + +
GPO NamePrivilegeMembers
Default Domain Controllers Policy ?SeAssignPrimaryTokenPrivilegeNT AUTHORITY\NETWORK SERVICE
Default Domain Controllers Policy ?SeAssignPrimaryTokenPrivilegeNT AUTHORITY\LOCAL SERVICE
Default Domain Controllers Policy ?SeBackupPrivilegeBUILTIN\Server Operators
Default Domain Controllers Policy ?SeBackupPrivilegeBUILTIN\Backup Operators
Default Domain Controllers Policy ?SeBackupPrivilegeAdministrators
Default Domain Controllers Policy ?SeDebugPrivilegeAdministrators
Default Domain Controllers Policy ?SeLoadDriverPrivilegeBUILTIN\Print Operators
Default Domain Controllers Policy ?SeLoadDriverPrivilegeAdministrators
Default Domain Controllers Policy ?SeMachineAccountPrivilegeAuthenticated Users
Default Domain Controllers Policy ?SeRestorePrivilegeBUILTIN\Server Operators
Default Domain Controllers Policy ?SeRestorePrivilegeBUILTIN\Backup Operators
Default Domain Controllers Policy ?SeRestorePrivilegeAdministrators
Default Domain Controllers Policy ?SeSecurityPrivilegeAdministrators
Default Domain Controllers Policy ?SeTakeOwnershipPrivilegeAdministrators
Default Domain Controllers Policy ?SeEnableDelegationPrivilegeAdministrators
+
+
+ + + + +
+

Login

+
+

Login authorization and restriction can be set by GPO. Indeed, by default, everyone is allowed to login on every computer except domain controllers. Defining login restriction is a way to have different isolated tiers. Here are the settings found in GPO.

+
+
+ + + + + +
GPO NamePrivilegeMembers
Default Domain Controllers Policy ?Log on as a batch job ?BUILTIN\Performance Log Users
Default Domain Controllers Policy ?Log on as a batch job ?BUILTIN\Backup Operators
Default Domain Controllers Policy ?Log on as a batch job ?Administrators
Default Domain Controllers Policy ?Allow log on locally ?NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS
Default Domain Controllers Policy ?Allow log on locally ?BUILTIN\Print Operators
Default Domain Controllers Policy ?Allow log on locally ?BUILTIN\Server Operators
Default Domain Controllers Policy ?Allow log on locally ?BUILTIN\Account Operators
Default Domain Controllers Policy ?Allow log on locally ?BUILTIN\Backup Operators
Default Domain Controllers Policy ?Allow log on locally ?Administrators
Default Domain Controllers Policy ?Access this computer from the network ?BUILTIN\Pre-Windows 2000 Compatible Access
Default Domain Controllers Policy ?Access this computer from the network ?NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS
Default Domain Controllers Policy ?Access this computer from the network ?Authenticated Users
Default Domain Controllers Policy ?Access this computer from the network ?Administrators
Default Domain Controllers Policy ?Access this computer from the network ?Everyone
+
+
+ + + + +
+

GPO Login script

+
+

A GPO login script is a way to force the execution of data on behalf of users. Only enabled users are analyzed.

+ + + +
+

GPO Deployed Files

+
+

A GPO can be used to deploy applications or copy files. These files may be controlled by a third party to control the execution of local programs.

+
+
+
+
+
+
+
+ + +
+ + + + + + + + + + + + + diff --git a/scanners/pingcastle/parser/__testFiles__/ad_hc_test.domain.com.xml b/scanners/pingcastle/parser/__testFiles__/ad_hc_test.domain.com.xml new file mode 100644 index 0000000000..5ac9af55a0 --- /dev/null +++ b/scanners/pingcastle/parser/__testFiles__/ad_hc_test.domain.com.xml @@ -0,0 +1 @@ +2.9.2.02021-08-04T05:39:31.0086734-07:00Normal2test.domain.comTESTtest.domain.com2021-08-04T19:42:19S-1-5-21-1095718994-4082106100-373731749166690false0001-01-01T00:00:001602560050WIN-GH3R6KE1P1Q2021-08-04T19:43:562021-08-04T05:36:41.2598935-07:002021-08-04T12:44:37.135389-07:00CN=WIN-GH3R6KE1P1Q,OU=Domain Controllers,DC=test,DC=testuser,DC=comWindows 2012S-1-5-21-1095718994-4082106100-3737317491-512TEST\Domain AdminsfalsetrueNonetrueSmbSigningEnabled SmbSigningRequiredtruefe80::84d6:8f3b:9897:4e21%1210.0.2.15PDCRID pool managerInfrastructure masterSchema masterDomain naming Master2021-08-04T05:36:51.3255312-07:00falsefalseDefault-First-Site-Namefalsefalsefalsefalsefalsefalsefalse20PrivilegedAccountsAdminControlP-AdminLoginThe native administrator account has been used recently: 0 day(s) ago20PrivilegedAccountsAccountTakeOverP-DelegatedPresence of Admin accounts which have not the flag "this account is sensitive and cannot be delegated": 115AnomaliesPassTheCredentialA-LAPS-Not-InstalledLAPS doesn't seem to be installed10StaleObjectsOldAuthenticationProtocolsS-SMB-v1SMB v1 activated on 1 DC10PrivilegedAccountsIrreversibleChangeP-SchemaAdminThe group Schema Admins is not empty: 1 account(s)10PrivilegedAccountsIrreversibleChangeP-RecycleBinThe Recycle Bin is not enabled10StaleObjectsProvisioningS-ADRegistrationNon-admin users can add up to 10 computer(s) to a domain10AnomaliesAuditA-AuditDCThe audit policy on domain controllers does not collect key events.10AnomaliesWeakPasswordA-MinPwdLenPolicy where the password length is less than 8 characters: 110AnomaliesPassTheCredentialA-DC-SpoolerThe spooler service is remotely accessible from 1 DC5StaleObjectsNetworkTopographyS-DC-SubnetMissingThe subnet declaration is incomplete [1 IP of DC not found in declared subnets]5AnomaliesBackupA-NotEnoughDCThe number of DCs is too small to provide redundancy: 1 DC0AnomaliesWeakPasswordA-NoServicePolicyNo password policy for service account found (MinimumPasswordLength>=20)0AnomaliesNetworkSniffingA-NoGPOLLMNRNo GPO has been found which disables LLMNR or at least one GPO does enable it explicitly0AnomaliesReconnaissanceA-NoNetSessionHardeningNo GPO has been found which implements NetCease0AnomaliesAuditA-AuditPowershellThe powershell audit configuration is not fully enabled.211100000000000110100000001000Windows 20121110100000001000Default Domain Policy{31B2F340-016D-11D2-945F-00C04FB984F9}falseDC=test,DC=testuser,DC=com1Default Domain Controllers Policy{6AC1786C-016F-11D2-945F-00C04fB984F9}falseOU=Domain Controllers,DC=test,DC=testuser,DC=com1None19999-12-31T23:59:59.99999999999-12-31T23:59:59.99999992021-08-04T12:43:57.3854318-07:002false2021-08-04T12:49:50.7446834-07:00MinimumPasswordAge1MaximumPasswordAge42MinimumPasswordLength7PasswordComplexity1PasswordHistorySize24LockoutBadCount0ClearTextPassword0Default Domain Policy{31B2F340-016D-11D2-945F-00C04FB984F9}Account OperatorsCN=Account Operators,CN=Builtin,DC=test,DC=testuser,DC=com0000000000000AdministratorsCN=Administrators,CN=Builtin,DC=test,DC=testuser,DC=com1000001110000Backup OperatorsCN=Backup Operators,CN=Builtin,DC=test,DC=testuser,DC=com0000000000000Certificate OperatorsCN=Cryptographic Operators,CN=Builtin,DC=test,DC=testuser,DC=com0000000000000Certificate PublishersCN=Cert Publishers,CN=Users,DC=test,DC=testuser,DC=com0000000000000Dns AdminsCN=DnsAdmins,CN=Users,DC=test,DC=testuser,DC=com0000000000000Domain AdministratorsCN=Domain Admins,CN=Users,DC=test,DC=testuser,DC=com1000001110000Enterprise AdministratorsCN=Enterprise Admins,CN=Users,DC=test,DC=testuser,DC=com1000001110000Print OperatorsCN=Print Operators,CN=Builtin,DC=test,DC=testuser,DC=com0000000000000ReplicatorCN=Replicator,CN=Builtin,DC=test,DC=testuser,DC=com0000000000000Schema AdministratorsCN=Schema Admins,CN=Users,DC=test,DC=testuser,DC=com1000001110000Server OperatorsCN=Server Operators,CN=Builtin,DC=test,DC=testuser,DC=com00000000000000000false10test.domain.comfalseRootDNSServersfalse0001-01-01T00:00:000000000001000000000000000000000000000100001000000100000001000000000000000000010000000000000000 diff --git a/scanners/pingcastle/parser/package-lock.json b/scanners/pingcastle/parser/package-lock.json new file mode 100644 index 0000000000..04ea7f81ff --- /dev/null +++ b/scanners/pingcastle/parser/package-lock.json @@ -0,0 +1,32 @@ +{ + "name": "@securecodebox/parser-pingcastle", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + } + } +} diff --git a/scanners/pingcastle/parser/package-lock.json.license b/scanners/pingcastle/parser/package-lock.json.license new file mode 100644 index 0000000000..c59b85a5b5 --- /dev/null +++ b/scanners/pingcastle/parser/package-lock.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021 iteratec GmbH + +SPDX-License-Identifier: Apache-2.0 diff --git a/scanners/pingcastle/parser/package.json b/scanners/pingcastle/parser/package.json new file mode 100644 index 0000000000..b5589e1032 --- /dev/null +++ b/scanners/pingcastle/parser/package.json @@ -0,0 +1,17 @@ +{ + "name": "@securecodebox/parser-pingcastle", + "version": "1.0.0", + "description": "Parses result files for the type: 'ad-hc-xml'", + "main": "", + "scripts": { + "test": "jest" + }, + "keywords": [], + "author": "iteratec GmbH", + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21", + "xml2js": "^0.4.23" + }, + "devDependencies": {} +} diff --git a/scanners/pingcastle/parser/package.json.license b/scanners/pingcastle/parser/package.json.license new file mode 100644 index 0000000000..c59b85a5b5 --- /dev/null +++ b/scanners/pingcastle/parser/package.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021 iteratec GmbH + +SPDX-License-Identifier: Apache-2.0 diff --git a/scanners/pingcastle/parser/parser.js b/scanners/pingcastle/parser/parser.js new file mode 100644 index 0000000000..126ec9c72f --- /dev/null +++ b/scanners/pingcastle/parser/parser.js @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: 2021 iteratec GmbH +// +// SPDX-License-Identifier: Apache-2.0 + +const xml2js = require('xml2js'); +const { get } = require('lodash'); + +async function parse(fileContent) { + const hosts = await parseResultFile(fileContent); + return transformToFindings(hosts); +} + +function transformToFindings(risks) { + + const riskFindings = risks.map(risk => { + let severity = null; + if (risk.points > 30) + severity = 'HIGH' + else if (risk.points <= 30 && risk.points > 10) + severity = 'MEDIUM' + else if (risk.points <= 10 && risk.points > 0) + severity = 'LOW' + else + severity = 'INFORMATIONAL' + + return { + name: risk.model, + category: risk.category, + description: risk.rationale, + location: risk.domain, + osi_layer: 'Application', + severity: severity, + attributes: { + riskID: risk.riskID + } + } + }); + + return [...riskFindings]; +} + +/** + * Parses a given PingCastle XML file to a smaller JSON represenation with the following object: + * { + * points: rule.Points, + * category: rule.Category, + * model: rule.Model, + * riskID: rule.RiskId, + * rationale: rule.Rationale, + * domain: domain from healthcheck + * } + * @param {*} fileContent + */ +function parseResultFile(fileContent) { + return new Promise((resolve, reject) => { + xml2js.parseString(fileContent, (err, xmlInput) => { + if (err) { + reject(new Error('Error converting XML to JSON in xml2js: ' + err)); + } else { + let tempRiskList = []; + + const domain = xmlInput.HealthcheckData.DomainFQDN[0]; + + tempRiskList = xmlInput.HealthcheckData.RiskRules[0].HealthcheckRiskRule.map(rule => { + const newRisk = { + points: parseInt(rule.Points[0]), + category: rule.Category[0], + model: rule.Model[0], + riskID: rule.RiskId[0], + rationale: rule.Rationale[0], + domain: domain + }; + + return newRisk; + }); + + resolve(tempRiskList); + } + }); + }); +} + +module.exports.parse = parse; diff --git a/scanners/pingcastle/parser/parser.test.js b/scanners/pingcastle/parser/parser.test.js new file mode 100644 index 0000000000..af977b9845 --- /dev/null +++ b/scanners/pingcastle/parser/parser.test.js @@ -0,0 +1,209 @@ +// SPDX-FileCopyrightText: 2021 iteratec GmbH +// +// SPDX-License-Identifier: Apache-2.0 + +const fs = require("fs"); +const util = require("util"); +const { + validateParser, +} = require("@securecodebox/parser-sdk-nodejs/parser-utils"); + +// eslint-disable-next-line security/detect-non-literal-fs-filename +const readFile = util.promisify(fs.readFile); + +const { parse } = require("./parser"); + +// test valid xml file +// ad_hc_test.domain.com.xml/html has been generated by running pingcastle against a fresh active directory +// on a Windows Server 2012 R2 VM in VirtualBox +test("should properly parse ping castle xml file", async () => { + const xmlContent = await readFile( + __dirname + "/__testFiles__/ad_hc_test.domain.com.xml", + { + encoding: "utf8", + } + ); + const findings = await parse(xmlContent); + // validate findings + await expect(validateParser(findings)).resolves.toBeUndefined(); + expect(findings).toMatchInlineSnapshot(` +Array [ + Object { + "attributes": Object { + "riskID": "P-AdminLogin", + }, + "category": "PrivilegedAccounts", + "description": "The native administrator account has been used recently: 0 day(s) ago", + "location": "test.domain.com", + "name": "AdminControl", + "osi_layer": "Application", + "severity": "MEDIUM", + }, + Object { + "attributes": Object { + "riskID": "P-Delegated", + }, + "category": "PrivilegedAccounts", + "description": "Presence of Admin accounts which have not the flag \\"this account is sensitive and cannot be delegated\\": 1", + "location": "test.domain.com", + "name": "AccountTakeOver", + "osi_layer": "Application", + "severity": "MEDIUM", + }, + Object { + "attributes": Object { + "riskID": "A-LAPS-Not-Installed", + }, + "category": "Anomalies", + "description": "LAPS doesn't seem to be installed", + "location": "test.domain.com", + "name": "PassTheCredential", + "osi_layer": "Application", + "severity": "MEDIUM", + }, + Object { + "attributes": Object { + "riskID": "S-SMB-v1", + }, + "category": "StaleObjects", + "description": "SMB v1 activated on 1 DC", + "location": "test.domain.com", + "name": "OldAuthenticationProtocols", + "osi_layer": "Application", + "severity": "LOW", + }, + Object { + "attributes": Object { + "riskID": "P-SchemaAdmin", + }, + "category": "PrivilegedAccounts", + "description": "The group Schema Admins is not empty: 1 account(s)", + "location": "test.domain.com", + "name": "IrreversibleChange", + "osi_layer": "Application", + "severity": "LOW", + }, + Object { + "attributes": Object { + "riskID": "P-RecycleBin", + }, + "category": "PrivilegedAccounts", + "description": "The Recycle Bin is not enabled", + "location": "test.domain.com", + "name": "IrreversibleChange", + "osi_layer": "Application", + "severity": "LOW", + }, + Object { + "attributes": Object { + "riskID": "S-ADRegistration", + }, + "category": "StaleObjects", + "description": "Non-admin users can add up to 10 computer(s) to a domain", + "location": "test.domain.com", + "name": "Provisioning", + "osi_layer": "Application", + "severity": "LOW", + }, + Object { + "attributes": Object { + "riskID": "A-AuditDC", + }, + "category": "Anomalies", + "description": "The audit policy on domain controllers does not collect key events.", + "location": "test.domain.com", + "name": "Audit", + "osi_layer": "Application", + "severity": "LOW", + }, + Object { + "attributes": Object { + "riskID": "A-MinPwdLen", + }, + "category": "Anomalies", + "description": "Policy where the password length is less than 8 characters: 1", + "location": "test.domain.com", + "name": "WeakPassword", + "osi_layer": "Application", + "severity": "LOW", + }, + Object { + "attributes": Object { + "riskID": "A-DC-Spooler", + }, + "category": "Anomalies", + "description": "The spooler service is remotely accessible from 1 DC", + "location": "test.domain.com", + "name": "PassTheCredential", + "osi_layer": "Application", + "severity": "LOW", + }, + Object { + "attributes": Object { + "riskID": "S-DC-SubnetMissing", + }, + "category": "StaleObjects", + "description": "The subnet declaration is incomplete [1 IP of DC not found in declared subnets]", + "location": "test.domain.com", + "name": "NetworkTopography", + "osi_layer": "Application", + "severity": "LOW", + }, + Object { + "attributes": Object { + "riskID": "A-NotEnoughDC", + }, + "category": "Anomalies", + "description": "The number of DCs is too small to provide redundancy: 1 DC", + "location": "test.domain.com", + "name": "Backup", + "osi_layer": "Application", + "severity": "LOW", + }, + Object { + "attributes": Object { + "riskID": "A-NoServicePolicy", + }, + "category": "Anomalies", + "description": "No password policy for service account found (MinimumPasswordLength>=20)", + "location": "test.domain.com", + "name": "WeakPassword", + "osi_layer": "Application", + "severity": "INFORMATIONAL", + }, + Object { + "attributes": Object { + "riskID": "A-NoGPOLLMNR", + }, + "category": "Anomalies", + "description": "No GPO has been found which disables LLMNR or at least one GPO does enable it explicitly", + "location": "test.domain.com", + "name": "NetworkSniffing", + "osi_layer": "Application", + "severity": "INFORMATIONAL", + }, + Object { + "attributes": Object { + "riskID": "A-NoNetSessionHardening", + }, + "category": "Anomalies", + "description": "No GPO has been found which implements NetCease", + "location": "test.domain.com", + "name": "Reconnaissance", + "osi_layer": "Application", + "severity": "INFORMATIONAL", + }, + Object { + "attributes": Object { + "riskID": "A-AuditPowershell", + }, + "category": "Anomalies", + "description": "The powershell audit configuration is not fully enabled.", + "location": "test.domain.com", + "name": "Audit", + "osi_layer": "Application", + "severity": "INFORMATIONAL", + }, +] +`); +}); From 1164759615ece2ca8fb22fb77a6c1cebffd4efcf Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 4 Aug 2021 15:01:05 +0200 Subject: [PATCH 02/16] Adding helm files Signed-off-by: Sebastian --- scanners/pingcastle/.helm-docs.gotmpl | 52 ++++++ scanners/pingcastle/Chart.yaml | 28 ++++ scanners/pingcastle/README.md | 154 ++++++++++++++++++ .../pingcastle-parse-definition.yaml | 13 ++ .../templates/pingcastle-scan-type.yaml | 38 +++++ scanners/pingcastle/values.yaml | 72 ++++++++ 6 files changed, 357 insertions(+) create mode 100644 scanners/pingcastle/.helm-docs.gotmpl create mode 100644 scanners/pingcastle/Chart.yaml create mode 100644 scanners/pingcastle/README.md create mode 100644 scanners/pingcastle/templates/pingcastle-parse-definition.yaml create mode 100644 scanners/pingcastle/templates/pingcastle-scan-type.yaml create mode 100644 scanners/pingcastle/values.yaml diff --git a/scanners/pingcastle/.helm-docs.gotmpl b/scanners/pingcastle/.helm-docs.gotmpl new file mode 100644 index 0000000000..52bf8459cf --- /dev/null +++ b/scanners/pingcastle/.helm-docs.gotmpl @@ -0,0 +1,52 @@ +{{- /* +SPDX-FileCopyrightText: 2021 iteratec GmbH + +SPDX-License-Identifier: Apache-2.0 +*/ -}} + +{{- define "extra.docsSection" -}} +--- +title: "PingCastle" +category: "scanner" +type: "Application" +state: "template" +appVersion: "2.9.2.1" +usecase: "Active Directory scanning" +--- + +![Pingcastle logo](https://www.pingcastle.com/wp/wp-content/uploads/2018/09/pingcastle_big.png) + +{{- end }} + +{{- define "extra.communitySection" -}} +PingCastle is a Windows application. The secureCodeBox, however, operates with linux containers only to date. +That is why we only provide a template for the scanner implementation and the parser to convert pingcastle results to +secureCodeBox [findings](https://docs.securecodebox.io/docs/api/finding). +Furthermore, we also provide a tutorial (scanner/Tutorial.md) that describes one way to make it work. +Unfortunately the resulting docker image cannot be provided due to licensing. + +You can find more information about our process to integrate Windows security scanners in this [blog post](TODO). +If you have any suggestions or requests regarding the implementation of PingCastle or any other windows scanner, +please let us know! + +{{- end }} + +{{- define "extra.chartAboutSection" -}} +## What is PingCastle? +PingCastle is an open-source tool to scan a company's active directory. It is able to identify potential security +risks and anomalies, regarding password settings, account privileges and much more. It is free to use for non-commercial +use, otherwise a commercial license has to be purchased. + +To learn more about the PingCastle itself visit [pingcastle.com]. +{{- end }} + +{{- define "extra.scannerConfigurationSection" -}} +## Scanner Configuration + +At the moment we only provide support for "healthchecks" that check the security issues mentioned above. + +- `--healthcheck`: Basic command to run pingcastle in healthcheck mode +- `--server` xx: Replace xx with the domain name to scan. +{{- end }} + + diff --git a/scanners/pingcastle/Chart.yaml b/scanners/pingcastle/Chart.yaml new file mode 100644 index 0000000000..14f75aa5cf --- /dev/null +++ b/scanners/pingcastle/Chart.yaml @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: 2021 iteratec GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: v2 +name: pingcastle +description: A Helm chart for the pingcastle security Scanner that integrates with the secureCodeBox. + +type: application +# version - gets automatically set to the secureCodeBox release version when the helm charts gets published +version: v2.7.0-alpha1 +appVersion: v2.9.2.1 +kubeVersion: ">=v1.11.0-0" + +keywords: + - security + - pingcastle + - scanner + - active directory + - windows + - secureCodeBox +home: https://docs.securecodebox.io/docs/scanners/pingcastle +icon: https://docs.securecodebox.io/img/integrationIcons/pingcastle.svg +sources: + - https://github.com/secureCodeBox/secureCodeBox +maintainers: + - name: iteratec GmbH + email: secureCodeBox@iteratec.com diff --git a/scanners/pingcastle/README.md b/scanners/pingcastle/README.md new file mode 100644 index 0000000000..ff1af91392 --- /dev/null +++ b/scanners/pingcastle/README.md @@ -0,0 +1,154 @@ +--- +title: "PingCastle" +category: "scanner" +type: "Application" +state: "template" +appVersion: "2.9.2.1" +usecase: "Active Directory scanning" +--- + +![Pingcastle logo](https://www.pingcastle.com/wp/wp-content/uploads/2018/09/pingcastle_big.png) + + + + +

+ License Apache-2.0 + GitHub release (latest SemVer) + OWASP Incubator Project + Artifact HUB + GitHub Repo stars + Twitter Follower +

+ +## What is NMAP? +Nmap ("Network Mapper") is a free and open source (license) utility for network discovery and security auditing. Many systems and network administrators also find it useful for tasks such as network inventory, managing service upgrade schedules, and monitoring host or service uptime. + +To learn more about the Nmap scanner itself visit [nmap.org]. + +## Deployment +The nmap chart can be deployed via helm: + +```bash +# Install HelmChart (use -n to configure another namespace) +helm upgrade --install nmap secureCodeBox/nmap +``` + +## Scanner Configuration + +The Nmap scan targets are specified as the last parameter. The target should be a hostname, an IP address or an IP range. See [Nmap Docs](https://nmap.org/book/man-target-specification.html) for details. + +Additional Nmap scan features can be configured via the parameter attribute. For a detailed explanation to which parameters are available refer to the [Nmap Reference Guide](https://nmap.org/book/man.html). All parameters are supported, but be careful with parameters that require root level rights, as these require additional configuration on the ScanType to be supported. + +Some useful example parameters listed below: + +- `-p` xx: Scan ports of the target. Replace xx with a single port number or a range of ports. +- `-PS`, `-PA`, `-PU` xx: Replace xx with the ports to scan. TCP SYN/ACK or + UDP discovery. +- `-sV`: Determine service and version info. +- `-O`: Determine OS info. **Note:** This requires that Nmap is run as root, or that the user has the system capabilities to be extended to allow Nmap to send raw sockets. See more information on [how to deploy the secureCodeBox nmap container to allow this](https://github.com/secureCodeBox/scanner-infrastructure-nmap/pull/20) and the [nmap docs about privileged scans](https://secwiki.org/w/Running_nmap_as_an_unprivileged_user) +- `-A`: Determine service/version and OS info. +- `-script` xx: Replace xx with the script name. Start the scan with the given script. +- `--script` xx: Replace xx with a coma-separated list of scripts. Start the scan with the given scripts. + +## Requirements + +Kubernetes: `>=v1.11.0-0` + +## Additional Chart Configurations +### Operating System Scans + +:::caution +Warning! This is currently not tested and might require additional testing to work 😕 +::: + +If you want to use Nmap to identify operating systems of hosts you'll need to weaken the securityContext config, as Nmap requires the capability to send raw sockets to identify operating systems. See [Nmap Docs](https://secwiki.org/w/Running_nmap_as_an_unprivileged_user) + +You can deploy the ScanType with the config like this: + +```bash +cat < Date: Wed, 4 Aug 2021 15:01:15 +0200 Subject: [PATCH 03/16] Adding scan example Signed-off-by: Sebastian --- scanners/pingcastle/examples/scan.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 scanners/pingcastle/examples/scan.yaml diff --git a/scanners/pingcastle/examples/scan.yaml b/scanners/pingcastle/examples/scan.yaml new file mode 100644 index 0000000000..1cd477553b --- /dev/null +++ b/scanners/pingcastle/examples/scan.yaml @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2021 iteratec GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: "execution.securecodebox.io/v1" +kind: Scan +metadata: + name: "pingcastle-healthcheck-demo" +spec: + scanType: "pingcastle-scan" + parameters: + - "--healthcheck" + - "--server domain.com" From 4b3cf822d3132735bccbdde210d56800a4eb9f76 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 4 Aug 2021 15:03:46 +0200 Subject: [PATCH 04/16] Adding scanner set up tutorial Signed-off-by: Sebastian --- scanners/pingcastle/scanner/Tutorial.md | 225 ++++++++++++++++++ .../scanner/run_pingcastle_healthcheck.py | 101 ++++++++ 2 files changed, 326 insertions(+) create mode 100644 scanners/pingcastle/scanner/Tutorial.md create mode 100644 scanners/pingcastle/scanner/run_pingcastle_healthcheck.py diff --git a/scanners/pingcastle/scanner/Tutorial.md b/scanners/pingcastle/scanner/Tutorial.md new file mode 100644 index 0000000000..0c24928e97 --- /dev/null +++ b/scanners/pingcastle/scanner/Tutorial.md @@ -0,0 +1,225 @@ + + +# Tutorial: Integrating PingCastle into the secureCodeBox + +## Preface + +PingCastle is an open-source tool to scan a company's active directory. It is able to identify potential security +risks and anomalies, regarding password settings, account privileges and much more. However, as active directory +has emerged as a tool from microsoft, PingCastle is also a tool that runs only on Windows. +You can read more about our struggle to make it work on linux in this blog post(TODO). +This tutorial is directed towards a solution that uses a virtual machine inside an ubuntu container to run +PingCastle in this machine. Sounds like inception? It pretty much is, but it is the only solution known to date that +enables us to run it on a linux container. + +## General architecture of the solution + +Docker <- Ubuntu <- VirtualBox <- Windows VM <- PingCastle + +That means that we run PingCastle in our Windows VM that runs in a virtualbox inside an ubuntu container. + +More specifically: +* Ubuntu 18 with systemd enabled (FROM jrei/systemd-ubuntu) +* Virtual Box (tested version: 6.1.16_Ubuntur140961, use latest version) +* Windows 10 VM +If you use it for non-commercial usages and want to test our solution, you can use a trial version (Expires in 90 days): +[Windows 10 VM Trial](https://developer.microsoft.com/de-de/windows/downloads/virtual-machines/) (Choose VirtualBox image) +* PingCastle 2.9.2.1 (latest) + +## Step-By-Step Walkthrough + +Now let's dive into the crazy inception and have our system run a linux docker with windows! +All you need is a Linux base system (preferably Ubuntu, we did not test any other linux distro!) where **Virtual Box +is installed.** + +### 1. Setting up the Windows 10 VM +In the first step we will set up our Windows VM. In order to do that you need to run it as a virtual machine in +Virtual Box. If you have downloaded the trial version mentioned above, you simply have to import it in Virtual Box +and start the VM. +Our goal is to have a Windows VM that logs in automatically on start-up, is connected to the network where the active +directory is running and is able to run a PingCastle scan. + +
+ WindowsVM Setup +0. Install your specific language & keyboard Settings (optional, but can be useful) + +1. Allow login without password for VirtualBox: + [Source Stackoverflow](https://stackoverflow.com/questions/35372516/vboxmanage-error-the-specified-user-was-not-able-to-logon-on-guest) + +"Run" -> "gpedit.msc". +Windows Settings -> Security Settings -> Local Policies -> Security Options -> Accounts: +Limit local account use of blank passwords to console logon only -> set it to DISABLED. + +2. Establish VPN Connection to the network where the AD is located (if not used in the network anyway) + +If the container is always running in the company's network, this step should not be necessary. +
+Otherwise you have to automatically connect to the VPN on startup + +Automatically connect to VPN on startup: +- Create a file "autoConnectVPN.bat" +- Add the following line to the file: + c:\windows\system32\rasdial.exe "domain" [/domain:domain.de] +- Go To: C:\Users\USER\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup +- Create shortlink to the autoConnectVPN.bat file + +**Unfortunately, we experienced that this does not always work with PingCastle. The connection was established, +but PingCastle refused to find the network. We provide a very dirty workaround that is not by any means error-prove. +It should only be used if all other possibilities failed, and you want to test if the docker container is working at all.** +``` +Dirtiest workaround: Use python to automatically click on the connection symbol: +1. Install python 3.x and pip, add python to path, then (python -m) pip install pywin32 + +2. Create a script that just clicks "manually" on the connection symbols. (Read the mouse coordinates and click them) +``` +
+ +3. Hang VM into the domain: + + 3.1 Open Powershell.exe as Administrator(!) + + 3.2 Type in the following command: Add-Computer -DomainName domain.de -NewName PingCastleVM + + 3.3 Type in your credentials (Username is the domain shortcut, e.g. pschmidt; Password is your regular PW) + + 3.4 If you are succesfull, this message shows: + WARNING: The changes will take effect after you restart the computer (your computer name). + + 3.5 Restart VM + + 3.6 Check date&time, maybe the timezone has to be set manually to have a correct system time + +4. Download necessary tools: + + 4.1 [Download PingCastle](https://github.com/vletoux/pingcastle/releases/download/2.9.2.1/PingCastle_2.9.2.1.zip) + + 4.2 Unzip to path: *C:\PingCastle* + + 4.3 We found it most useful and the easiest way not to call PingCastle directly but via a script. + So create healthcheck.cmd in *C:\PingCastle* : +``` +cd C:\PingCastle +PingCastle.exe --healthcheck --server domain.com +``` +*cd* necessary because otherwise guestcontrol will use a wrong default path. + + 4.4 Check if you can successfully scan your domain via the script! + +5. Install Guest Additions for Virtual Box + +6. Set Auto-Login: + [Source: Tech-Faq](https://www.tech-faq.net/windows-10-autologin-einrichten/) + +Create file and execute: +``` +Windows Registry Editor Version 5.00 + + [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Passwordless\Device] +"DevicePasswordLessBuildVersion"=dword:00000000 +``` + +7. Disable recovery modes to avoid that the VM gets stuck upon startup. (This step is optional and can for certain +be further improved) + + 7.1 Open cmd as administrator + + 7.2 + ``` + reagentc /info + reagentc /disable + ``` + +8. Now check if you can run your VM in headless mode and execute a scan: +``` + vboxmanage startvm WinVM --type headless + vboxmanage showvminfo WinVM | grep "State" # should be "Running" + vboxmanage guestcontrol WinVM run --exe "c:\\PingCastle\\healthcheck.cmd" --username USER +``` + +9. Finally, you must export the modified appliance using VirtualBox (.ova) +
+ +### 2. Docker Set-Up for Ubuntu with WindowsVM +Next, we will integrate our created WindowsVM into an Ubuntu docker container. +We hereby use an already existing Ubuntu18 container that has *systemd* enabled, +which is crucial for virtual box to function. + +
+Docker Setup + +Dockerfile: +``` +FROM jrei/systemd-ubuntu + +# VirtualBox +RUN apt-get update \ + && apt-get -y install wget \ + && apt-get -y install gnupg2 \ + && apt-get -y install systemd \ + && apt-get -y install python3 \ + && apt-get -y install software-properties-common \ + && apt-get -y install unzip \ + && wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | apt-key add - \ + && wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | apt-key add - \ + && add-apt-repository "deb https://download.virtualbox.org/virtualbox/debian bionic contrib" \ + && apt-get -y update \ + && apt-get -y install linux-headers-generic \ + && mkdir WindowsVM \ + && apt-get -y install virtualbox + + +# Add run pingcastle script +ADD run_pingcastle_healthcheck.py run_pingcastle_healthcheck.py +``` + +Now we have to do some manual configurations, so we must run the container. In --device, you have to provide the +path where vboxdrv on your base system is located. +``` +docker run -d --privileged \ + --name windocvm --network=host \ + --device /dev/vboxdrv:/dev/vboxdrv \ + -v /sys/fs/cgroup:/sys/fs/cgroup:ro \ + -v /tmp:/tmp -it windocvm +``` + + +Next, copy the WindowsVM to the created container: +``` +docker cp WindowsVM/WinVM.ova windocvm:WindowsVM/WinVM.ova +``` + +Change to the running container and import and start the VM: +``` + docker exec -it windocvm /bin/bash + + cd WindowsVM \ + && vboxmanage import WinVM.ova \ + && vboxmanage list vms \ + && vboxmanage startvm WinVM --type headless \ + && vboxmanage showvminfo WinVM | grep "State" +``` + +After that you can push the docker image to your own docker repository or proceed with the local image. +
+ +### 3. Create docker container to handle the scan +From the now created docker container, we can create a new one that has all the attributes from the one above and is +able to execute our scan with a python script. This container can finally be added to the cluster and perform the +automated scans. + +
+Dockerfile + +``` +FROM docker.yourrepo.com/windocvm:latest + +CMD python3 run_pingcastle_healthcheck.py +``` +
+ + +And that's it! You can now add your docker container to the securecodebox cluster and apply a scan.yaml. diff --git a/scanners/pingcastle/scanner/run_pingcastle_healthcheck.py b/scanners/pingcastle/scanner/run_pingcastle_healthcheck.py new file mode 100644 index 0000000000..2cd0d67427 --- /dev/null +++ b/scanners/pingcastle/scanner/run_pingcastle_healthcheck.py @@ -0,0 +1,101 @@ +""" +SPDX-FileCopyrightText: 2021 iteratec GmbH + +SPDX-License-Identifier: Apache-2.0 +""" + +""" +This script starts a pingcastle healthcheck scan in the docker container, that has virtual box running a windows vm with +pingcastle. If the VM is not running, it tries to start it. Otherwise, it will directly call the script in the VM to +run the scan. In the end, it will transfer the created result file to the host container. +""" + +import os +import time +import pathlib +import subprocess + +# Check if Windows VM is already running + +running_vm = subprocess.Popen("vboxmanage showvminfo WinVM | grep 'State'", shell=True, stdout=subprocess.PIPE) + +state_output = str(running_vm.stdout.read()) +running_vm.stdout.close() + +if "running" in state_output: + print("Windows VM already running, skipping start.") +else: + # Start Windows VM + print("Starting WindowsVM..!") + start_vm = subprocess.Popen("vboxmanage startvm WinVM --type headless ", shell=True, stdout=subprocess.PIPE) + start_vm.wait() + start_output = str(start_vm.stdout.read()) + + if start_vm.returncode == 0 and "successfully started" in start_output: + print("Windows VM successfully started!") + print("Waiting for VM to be running..") + while "running" not in state_output: + time.sleep(1) + running_vm = subprocess.Popen("vboxmanage showvminfo WinVM | grep 'State'", shell=True, + stdout=subprocess.PIPE) + state_output = str(running_vm.stdout.read()) + + print("Windows VM is running!") + for i in range(90): + print("Waiting until VM is all set up:", 90-i) + time.sleep(1) + +# Start PingCastle Scan: +print("Waiting for scan to start..") +time.sleep(5) + +print("Running PingCastle Healthcheck for domain.com") +pingcastle_scan = subprocess.Popen("vboxmanage guestcontrol WinVM run --exe " + "'c:\\PingCastle\\healthcheck.cmd' --username USER", + shell=True, + stdout=subprocess.PIPE, + bufsize=1) +lines = [] +for line in iter(pingcastle_scan.stdout.readline, b''): + print(line) + lines.append(str(line)) +pingcastle_scan.stdout.close() +pingcastle_scan.wait() + +success_message = "Task Perform analysis for domain.com completed" +if len(lines) == 0 or success_message not in lines[-1]: + print("Something went wrong with the scan.. See lines:", lines) +else: + print("PingCastle Healthcheck successfully finished!") + + print("Grapping generated .xml and .html files..") + # Remove all files if scan directory already exists: + if os.path.isdir("PingCastleReports/"): + for file in os.listdir("PingCastleReports/"): + os.remove("PingCastleReports/" + file) + else: + os.mkdir("PingCastleReports/") + + vbox_xml_transfer = subprocess.Popen("vboxmanage guestcontrol WinVM copyfrom --target-directory PingCastleReports/ " + "'C:\\PingCastle\\ad_hc_domain.com.xml' --username USER", + shell=True, + stdout=subprocess.PIPE) + vbox_xml_transfer.wait() + + vbox_html_transfer = subprocess.Popen( + "vboxmanage guestcontrol WinVM copyfrom --target-directory PingCastleReports/ " + "'C:\\PingCastle\\ad_hc_domain.com.html' --username USER", + shell=True, + stdout=subprocess.PIPE) + vbox_html_transfer.wait() + + if vbox_html_transfer.returncode == 0 and vbox_xml_transfer.returncode == 0: + # Verify that files have been transferred: + for file in os.listdir("PingCastleReports"): + fname = pathlib.Path("PingCastleReports/" + file) + assert fname.exists(), f'No such file: {fname}' # check that the file exists + + print("All scan files have been successfully transferred, quitting now.") + else: + print("Files have not been successfully transferred.. Exit codes: (xml), (html)", + vbox_xml_transfer.returncode, vbox_html_transfer.returncode) From 0cc973a8424ed288c890874c4911f11b07b077c1 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 4 Aug 2021 15:20:45 +0200 Subject: [PATCH 05/16] Adding build pingcastle parser to ci Signed-off-by: Sebastian --- .github/workflows/ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b0ea97111b..f4756d6f42 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -464,6 +464,7 @@ jobs: - ncrack - nikto - nmap + - pingcastle - screenshooter - ssh-scan - sslyze From 2c34375f6cb8d30e7f71e34de721b2ba28993fee Mon Sep 17 00:00:00 2001 From: Sebastian Franz <32578476+SebieF@users.noreply.github.com> Date: Wed, 4 Aug 2021 15:23:59 +0200 Subject: [PATCH 06/16] Adding build pingcastle parser to ci --- .github/workflows/ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b0ea97111b..f4756d6f42 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -464,6 +464,7 @@ jobs: - ncrack - nikto - nmap + - pingcastle - screenshooter - ssh-scan - sslyze From e375dc0875b08fc4be57fbde9f3d199367195db1 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 10 Aug 2021 13:25:51 +0200 Subject: [PATCH 07/16] Adding docs folder Signed-off-by: Sebastian --- scanners/pingcastle/docs/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 scanners/pingcastle/docs/.gitkeep diff --git a/scanners/pingcastle/docs/.gitkeep b/scanners/pingcastle/docs/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 From e4d00a70615c41af0db6f0bf53887320dcfe98ac Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 30 Aug 2021 11:19:02 +0200 Subject: [PATCH 08/16] Removing redundant parser dependency Signed-off-by: Sebastian --- scanners/pingcastle/parser/package-lock.json | 5 ----- scanners/pingcastle/parser/package.json | 1 - scanners/pingcastle/parser/parser.js | 1 - 3 files changed, 7 deletions(-) diff --git a/scanners/pingcastle/parser/package-lock.json b/scanners/pingcastle/parser/package-lock.json index 04ea7f81ff..d7fe154719 100644 --- a/scanners/pingcastle/parser/package-lock.json +++ b/scanners/pingcastle/parser/package-lock.json @@ -4,11 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", diff --git a/scanners/pingcastle/parser/package.json b/scanners/pingcastle/parser/package.json index b5589e1032..e903bba8bb 100644 --- a/scanners/pingcastle/parser/package.json +++ b/scanners/pingcastle/parser/package.json @@ -10,7 +10,6 @@ "author": "iteratec GmbH", "license": "Apache-2.0", "dependencies": { - "lodash": "^4.17.21", "xml2js": "^0.4.23" }, "devDependencies": {} diff --git a/scanners/pingcastle/parser/parser.js b/scanners/pingcastle/parser/parser.js index 126ec9c72f..0e0fc9ace7 100644 --- a/scanners/pingcastle/parser/parser.js +++ b/scanners/pingcastle/parser/parser.js @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 const xml2js = require('xml2js'); -const { get } = require('lodash'); async function parse(fileContent) { const hosts = await parseResultFile(fileContent); From ff5598b41579b434bf0e6099c08edcc30619da52 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 30 Aug 2021 11:32:51 +0200 Subject: [PATCH 09/16] Adjusting script and scantype to match scb standard Signed-off-by: Sebastian --- scanners/pingcastle/scanner/run_pingcastle_healthcheck.py | 4 ++++ scanners/pingcastle/templates/pingcastle-scan-type.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/scanners/pingcastle/scanner/run_pingcastle_healthcheck.py b/scanners/pingcastle/scanner/run_pingcastle_healthcheck.py index 2cd0d67427..ce2ba5460d 100644 --- a/scanners/pingcastle/scanner/run_pingcastle_healthcheck.py +++ b/scanners/pingcastle/scanner/run_pingcastle_healthcheck.py @@ -14,6 +14,7 @@ import time import pathlib import subprocess +from shutil import copyfile # Check if Windows VM is already running @@ -94,6 +95,9 @@ for file in os.listdir("PingCastleReports"): fname = pathlib.Path("PingCastleReports/" + file) assert fname.exists(), f'No such file: {fname}' # check that the file exists + if "xml" in file: + # Copy to standard scb location + copyfile(fname, "/home/securecodebox/pingcastle-results.xml") print("All scan files have been successfully transferred, quitting now.") else: diff --git a/scanners/pingcastle/templates/pingcastle-scan-type.yaml b/scanners/pingcastle/templates/pingcastle-scan-type.yaml index 0a5c633b7b..18966c1927 100644 --- a/scanners/pingcastle/templates/pingcastle-scan-type.yaml +++ b/scanners/pingcastle/templates/pingcastle-scan-type.yaml @@ -22,7 +22,7 @@ spec: containers: - name: pingcastle image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" - command: ["python3", "run_pingcastle_healthcheck.py", "/home/securecodebox/pingcastle-results.xml"] #TODO + command: ["python3", "run_pingcastle_healthcheck.py"] resources: {{- toYaml .Values.scanner.resources | nindent 16 }} securityContext: From 800fa6e34f9dc6d080188b66867e96d23bbf788c Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 30 Aug 2021 11:33:06 +0200 Subject: [PATCH 10/16] Updating scb version Signed-off-by: Sebastian --- scanners/pingcastle/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scanners/pingcastle/Chart.yaml b/scanners/pingcastle/Chart.yaml index 14f75aa5cf..33303174d0 100644 --- a/scanners/pingcastle/Chart.yaml +++ b/scanners/pingcastle/Chart.yaml @@ -8,7 +8,7 @@ description: A Helm chart for the pingcastle security Scanner that integrates wi type: application # version - gets automatically set to the secureCodeBox release version when the helm charts gets published -version: v2.7.0-alpha1 +version: v3.1.0-alpha1 appVersion: v2.9.2.1 kubeVersion: ">=v1.11.0-0" From a508aa926b15eb461e39ac81b626afa2e37d1b3c Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 30 Aug 2021 11:33:31 +0200 Subject: [PATCH 11/16] Updating blog links Signed-off-by: Sebastian --- scanners/pingcastle/.helm-docs.gotmpl | 3 ++- scanners/pingcastle/scanner/Tutorial.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scanners/pingcastle/.helm-docs.gotmpl b/scanners/pingcastle/.helm-docs.gotmpl index 52bf8459cf..2999b6355f 100644 --- a/scanners/pingcastle/.helm-docs.gotmpl +++ b/scanners/pingcastle/.helm-docs.gotmpl @@ -25,7 +25,8 @@ secureCodeBox [findings](https://docs.securecodebox.io/docs/api/finding). Furthermore, we also provide a tutorial (scanner/Tutorial.md) that describes one way to make it work. Unfortunately the resulting docker image cannot be provided due to licensing. -You can find more information about our process to integrate Windows security scanners in this [blog post](TODO). +You can find more information about our process to integrate Windows security scanners in this +[blog post](https://docs.securecodebox.io/blog/2021/08/09/integrating-windows-scanners). If you have any suggestions or requests regarding the implementation of PingCastle or any other windows scanner, please let us know! diff --git a/scanners/pingcastle/scanner/Tutorial.md b/scanners/pingcastle/scanner/Tutorial.md index 0c24928e97..a3bb5a225b 100644 --- a/scanners/pingcastle/scanner/Tutorial.md +++ b/scanners/pingcastle/scanner/Tutorial.md @@ -11,7 +11,8 @@ SPDX-License-Identifier: Apache-2.0 PingCastle is an open-source tool to scan a company's active directory. It is able to identify potential security risks and anomalies, regarding password settings, account privileges and much more. However, as active directory has emerged as a tool from microsoft, PingCastle is also a tool that runs only on Windows. -You can read more about our struggle to make it work on linux in this blog post(TODO). +You can read more about our struggle to make it work on linux in this +[blog post](https://docs.securecodebox.io/blog/2021/08/09/integrating-windows-scanners). This tutorial is directed towards a solution that uses a virtual machine inside an ubuntu container to run PingCastle in this machine. Sounds like inception? It pretty much is, but it is the only solution known to date that enables us to run it on a linux container. From 01e6f7cc4303595f0ce010992611d5a669326ace Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 30 Aug 2021 11:33:46 +0200 Subject: [PATCH 12/16] Changing to Entrypoint Signed-off-by: Sebastian --- scanners/pingcastle/scanner/Tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scanners/pingcastle/scanner/Tutorial.md b/scanners/pingcastle/scanner/Tutorial.md index a3bb5a225b..83b154b168 100644 --- a/scanners/pingcastle/scanner/Tutorial.md +++ b/scanners/pingcastle/scanner/Tutorial.md @@ -218,7 +218,7 @@ automated scans. ``` FROM docker.yourrepo.com/windocvm:latest -CMD python3 run_pingcastle_healthcheck.py +ENTRYPOINT ["python3", "run_pingcastle_healthcheck.py"] ``` From 6791d1e962ef7290e90c7031eeb482579b3c49c3 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 30 Aug 2021 11:34:13 +0200 Subject: [PATCH 13/16] Making scanner image instructions more clear Signed-off-by: Sebastian --- scanners/pingcastle/values.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scanners/pingcastle/values.yaml b/scanners/pingcastle/values.yaml index 47daa0bd66..68e9cd3b5e 100644 --- a/scanners/pingcastle/values.yaml +++ b/scanners/pingcastle/values.yaml @@ -17,7 +17,7 @@ parser: scanner: image: # scanner.image.repository -- Container Image to run the scan - repository: # docker.io/securecodebox/scanner-pingcastle TODO + repository: # your-repo/scanner-pingcastle: Use your created PingCastle Scanner Container here. # scanner.image.tag -- defaults to the charts version tag: null @@ -61,6 +61,7 @@ scanner: # scanner.securityContext.allowPrivilegeEscalation -- Ensure that users privileges cannot be escalated allowPrivilegeEscalation: false # scanner.securityContext.privileged -- Ensures that the scanner container is not run in privileged mode + # VirtualBox in a docker container needs privileged mode privileged: true capabilities: drop: From ad51217bd8819e72afd7aa39e49c374e7bd479d0 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 30 Sep 2021 12:08:19 +0200 Subject: [PATCH 14/16] Making scan-type.yaml files consistent 1. Replacing all ' with " 2. Replacing incorrect scanner image ".Chart.Version" with ".Chart.AppVersion" 3. Replacing array command for ncrack, nmap, test-scan, whatweb with single lines for each parameter 4. Removing redundant comments 5. Adding missing empty lines 6. Make order of variables consistent for all scanners Signed-off-by: Sebastian --- scanners/amass/templates/amass-scan-type.yaml | 3 +-- .../templates/git-repo-scanner-scan-type.yaml | 2 +- .../templates/kubehunter-scan-type.yaml | 14 +++++++------- .../templates/kubeaudit-scan-type.yaml | 2 +- scanners/ncrack/templates/ncrack-scan-type.yaml | 5 ++++- scanners/nikto/templates/nikto-scan-type.yaml | 16 +++++++--------- scanners/nmap/templates/nmap-scan-type.yaml | 5 ++++- scanners/nuclei/templates/nuclei-scan-type.yaml | 17 ++++++++--------- .../templates/screenshooter-scan-type.yaml | 4 ++-- scanners/sslyze/templates/sslyze-scan-type.yaml | 12 ++++++------ .../templates/test-scan-scan-type.yaml | 6 ++++-- .../templates/typo3scan-scan-type.yaml | 2 ++ .../whatweb/templates/whatweb-scan-type.yaml | 4 +++- .../templates/zap-advanced-scan-type.yaml | 2 +- 14 files changed, 51 insertions(+), 43 deletions(-) diff --git a/scanners/amass/templates/amass-scan-type.yaml b/scanners/amass/templates/amass-scan-type.yaml index ba009893ca..149578fb1a 100644 --- a/scanners/amass/templates/amass-scan-type.yaml +++ b/scanners/amass/templates/amass-scan-type.yaml @@ -1,14 +1,13 @@ # SPDX-FileCopyrightText: 2021 iteratec GmbH # # SPDX-License-Identifier: Apache-2.0 + apiVersion: "execution.securecodebox.io/v1" kind: ScanType metadata: name: "amass{{ .Values.scanner.nameAppend | default ""}}" spec: extractResults: - # amass saves it's result now in json but in "json lines" format - # http://jsonlines.org/ type: amass-jsonl location: "/home/securecodebox/amass-results.jsonl" jobTemplate: diff --git a/scanners/git-repo-scanner/templates/git-repo-scanner-scan-type.yaml b/scanners/git-repo-scanner/templates/git-repo-scanner-scan-type.yaml index f587c4d6ba..b598d4ed0c 100644 --- a/scanners/git-repo-scanner/templates/git-repo-scanner-scan-type.yaml +++ b/scanners/git-repo-scanner/templates/git-repo-scanner-scan-type.yaml @@ -24,7 +24,7 @@ spec: restartPolicy: OnFailure containers: - name: git-repo-scanner - image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.Version }}" + image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} command: - "python" diff --git a/scanners/kube-hunter/templates/kubehunter-scan-type.yaml b/scanners/kube-hunter/templates/kubehunter-scan-type.yaml index 7a2025e669..431ed28126 100644 --- a/scanners/kube-hunter/templates/kubehunter-scan-type.yaml +++ b/scanners/kube-hunter/templates/kubehunter-scan-type.yaml @@ -2,14 +2,14 @@ # # SPDX-License-Identifier: Apache-2.0 -apiVersion: 'execution.securecodebox.io/v1' +apiVersion: "execution.securecodebox.io/v1" kind: ScanType metadata: - name: 'kube-hunter{{ .Values.scanner.nameAppend | default ""}}' + name: "kube-hunter{{ .Values.scanner.nameAppend | default ""}}" spec: extractResults: type: kube-hunter-json - location: '/home/securecodebox/kube-hunter-results.json' + location: "/home/securecodebox/kube-hunter-results.json" jobTemplate: spec: {{- if .Values.scanner.ttlSecondsAfterFinished }} @@ -27,10 +27,10 @@ spec: image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} command: - - 'sh' - - '/wrapper.sh' - - '--report' - - 'json' + - "sh" + - "/wrapper.sh" + - "--report" + - "json" resources: {{- toYaml .Values.scanner.resources | nindent 16 }} securityContext: diff --git a/scanners/kubeaudit/templates/kubeaudit-scan-type.yaml b/scanners/kubeaudit/templates/kubeaudit-scan-type.yaml index 62efc84c64..ab2a34403d 100644 --- a/scanners/kubeaudit/templates/kubeaudit-scan-type.yaml +++ b/scanners/kubeaudit/templates/kubeaudit-scan-type.yaml @@ -46,5 +46,5 @@ spec: {{- toYaml .Values.scanner.extraContainers | nindent 12 }} {{- end }} volumes: - {{- toYaml .Values.scanner.extraVolumeMounts | nindent 12 }} + {{- toYaml .Values.scanner.extraVolumes | nindent 12 }} serviceAccountName: kubeaudit diff --git a/scanners/ncrack/templates/ncrack-scan-type.yaml b/scanners/ncrack/templates/ncrack-scan-type.yaml index 7515e3c720..8f389cc8ed 100644 --- a/scanners/ncrack/templates/ncrack-scan-type.yaml +++ b/scanners/ncrack/templates/ncrack-scan-type.yaml @@ -26,7 +26,10 @@ spec: - name: ncrack image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} - command: ["ncrack", "-oX", "/home/securecodebox/ncrack-results.xml"] + command: + - "ncrack" + - "-oX" + - "/home/securecodebox/ncrack-results.xml" resources: {{- toYaml .Values.scanner.resources | nindent 16 }} securityContext: diff --git a/scanners/nikto/templates/nikto-scan-type.yaml b/scanners/nikto/templates/nikto-scan-type.yaml index 0f2c447baa..e63ba0e16f 100644 --- a/scanners/nikto/templates/nikto-scan-type.yaml +++ b/scanners/nikto/templates/nikto-scan-type.yaml @@ -2,14 +2,14 @@ # # SPDX-License-Identifier: Apache-2.0 -apiVersion: 'execution.securecodebox.io/v1' +apiVersion: "execution.securecodebox.io/v1" kind: ScanType metadata: - name: 'nikto{{ .Values.scanner.nameAppend | default ""}}' + name: "nikto{{ .Values.scanner.nameAppend | default ""}}" spec: extractResults: type: nikto-json - location: '/home/securecodebox/nikto-results.json' + location: "/home/securecodebox/nikto-results.json" jobTemplate: spec: {{- if .Values.scanner.ttlSecondsAfterFinished }} @@ -27,12 +27,10 @@ spec: image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} command: - # Nikto Entrypoint Script to avoid problems nikto exiting with a non zero exit code - # This would cause the kubernetes job to fail no matter what - - 'sh' - - '/wrapper.sh' - - '-o' - - '/home/securecodebox/nikto-results.json' + - "sh" + - "/wrapper.sh" + - "-o" + - "/home/securecodebox/nikto-results.json" resources: {{- toYaml .Values.scanner.resources | nindent 16 }} securityContext: diff --git a/scanners/nmap/templates/nmap-scan-type.yaml b/scanners/nmap/templates/nmap-scan-type.yaml index 9559c67f9c..a033042075 100644 --- a/scanners/nmap/templates/nmap-scan-type.yaml +++ b/scanners/nmap/templates/nmap-scan-type.yaml @@ -26,7 +26,10 @@ spec: - name: nmap image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} - command: ["nmap", "-oX", "/home/securecodebox/nmap-results.xml"] + command: + - "nmap" + - "-oX" + - "/home/securecodebox/nmap-results.xml" resources: {{- toYaml .Values.scanner.resources | nindent 16 }} securityContext: diff --git a/scanners/nuclei/templates/nuclei-scan-type.yaml b/scanners/nuclei/templates/nuclei-scan-type.yaml index b6cbfd95a3..5b06813508 100644 --- a/scanners/nuclei/templates/nuclei-scan-type.yaml +++ b/scanners/nuclei/templates/nuclei-scan-type.yaml @@ -2,14 +2,14 @@ # # SPDX-License-Identifier: Apache-2.0 -apiVersion: 'execution.securecodebox.io/v1' +apiVersion: "execution.securecodebox.io/v1" kind: ScanType metadata: - name: 'nuclei{{ .Values.scanner.nameAppend | default ""}}' + name: "nuclei{{ .Values.scanner.nameAppend | default ""}}" spec: extractResults: type: nuclei-json - location: '/home/securecodebox/nuclei-results.jsonl' + location: "/home/securecodebox/nuclei-results.jsonl" jobTemplate: spec: {{- if .Values.scanner.ttlSecondsAfterFinished }} @@ -27,12 +27,11 @@ spec: image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} command: - - 'nuclei' - - '-no-update-templates' - - '-json' - # nuclei writes json lines: https://jsonlines.org/ - - '-output' - - '/home/securecodebox/nuclei-results.jsonl' + - "nuclei" + - "-no-update-templates" + - "-json" + - "-output" + - "/home/securecodebox/nuclei-results.jsonl" resources: {{- toYaml .Values.scanner.resources | nindent 16 }} securityContext: diff --git a/scanners/screenshooter/templates/screenshooter-scan-type.yaml b/scanners/screenshooter/templates/screenshooter-scan-type.yaml index a7f93ad93b..d014873d06 100644 --- a/scanners/screenshooter/templates/screenshooter-scan-type.yaml +++ b/scanners/screenshooter/templates/screenshooter-scan-type.yaml @@ -27,8 +27,8 @@ spec: image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.Version }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} command: - - 'sh' - - '/wrapper.sh' + - "sh" + - "/wrapper.sh" - "-screenshot" - "/home/securecodebox/screenshot.png" resources: diff --git a/scanners/sslyze/templates/sslyze-scan-type.yaml b/scanners/sslyze/templates/sslyze-scan-type.yaml index 085b34f334..65880dcd76 100644 --- a/scanners/sslyze/templates/sslyze-scan-type.yaml +++ b/scanners/sslyze/templates/sslyze-scan-type.yaml @@ -2,14 +2,14 @@ # # SPDX-License-Identifier: Apache-2.0 -apiVersion: 'execution.securecodebox.io/v1' +apiVersion: "execution.securecodebox.io/v1" kind: ScanType metadata: - name: 'sslyze{{ .Values.scanner.nameAppend | default ""}}' + name: "sslyze{{ .Values.scanner.nameAppend | default ""}}" spec: extractResults: type: sslyze-json - location: '/home/securecodebox/sslyze-results.json' + location: "/home/securecodebox/sslyze-results.json" jobTemplate: spec: {{- if .Values.scanner.ttlSecondsAfterFinished }} @@ -27,9 +27,9 @@ spec: image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} command: - - 'sslyze' - - '--json_out' - - '/home/securecodebox/sslyze-results.json' + - "sslyze" + - "--json_out" + - "/home/securecodebox/sslyze-results.json" resources: {{- toYaml .Values.scanner.resources | nindent 16 }} securityContext: diff --git a/scanners/test-scan/templates/test-scan-scan-type.yaml b/scanners/test-scan/templates/test-scan-scan-type.yaml index 9f5242993a..c8a9f91019 100644 --- a/scanners/test-scan/templates/test-scan-scan-type.yaml +++ b/scanners/test-scan/templates/test-scan-scan-type.yaml @@ -24,9 +24,11 @@ spec: restartPolicy: OnFailure containers: - name: test-scan - image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.Version }}" - command: ["touch", "/home/securecodebox/hello-world.txt"] + image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} + command: + - "touch" + - "/home/securecodebox/hello-world.txt" resources: {{- toYaml .Values.scanner.resources | nindent 16 }} securityContext: diff --git a/scanners/typo3scan/templates/typo3scan-scan-type.yaml b/scanners/typo3scan/templates/typo3scan-scan-type.yaml index a7cf4c45f1..66e97f6164 100644 --- a/scanners/typo3scan/templates/typo3scan-scan-type.yaml +++ b/scanners/typo3scan/templates/typo3scan-scan-type.yaml @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2021 iteratec GmbH # # SPDX-License-Identifier: Apache-2.0 + apiVersion: "execution.securecodebox.io/v1" kind: ScanType metadata: @@ -24,6 +25,7 @@ spec: containers: - name: typo3scan image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} command: - "python3" - "/home/typo3scan/typo3scan.py" diff --git a/scanners/whatweb/templates/whatweb-scan-type.yaml b/scanners/whatweb/templates/whatweb-scan-type.yaml index 08fcfbffb4..a575bf3f09 100644 --- a/scanners/whatweb/templates/whatweb-scan-type.yaml +++ b/scanners/whatweb/templates/whatweb-scan-type.yaml @@ -26,7 +26,9 @@ spec: - name: whatweb image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} - command: ["whatweb", "--log-json=/home/securecodebox/whatweb-results.json"] + command: + - "whatweb" + - "--log-json=/home/securecodebox/whatweb-results.json" resources: {{- toYaml .Values.scanner.resources | nindent 16 }} securityContext: diff --git a/scanners/zap-advanced/templates/zap-advanced-scan-type.yaml b/scanners/zap-advanced/templates/zap-advanced-scan-type.yaml index 1c1853f68f..fec86687a9 100644 --- a/scanners/zap-advanced/templates/zap-advanced-scan-type.yaml +++ b/scanners/zap-advanced/templates/zap-advanced-scan-type.yaml @@ -39,7 +39,7 @@ spec: restartPolicy: Never containers: - name: zap-advanced-scan - image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.Version }}" + image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} command: - "python3" From 411db641fcf81729fa6b5cd99749a4f43ae0c3cc Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 11 Oct 2021 14:23:20 +0200 Subject: [PATCH 15/16] Setting back to image: ".. | default .Chart.Version }}" This is done because these are our own scanners (SCB scanners) that follow our release versioning system. Regarding consistency, an issue was created to keep this in mind. Signed-off-by: Sebastian --- .../git-repo-scanner/templates/git-repo-scanner-scan-type.yaml | 2 +- scanners/test-scan/templates/test-scan-scan-type.yaml | 2 +- scanners/zap-advanced/templates/zap-advanced-scan-type.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scanners/git-repo-scanner/templates/git-repo-scanner-scan-type.yaml b/scanners/git-repo-scanner/templates/git-repo-scanner-scan-type.yaml index b598d4ed0c..f587c4d6ba 100644 --- a/scanners/git-repo-scanner/templates/git-repo-scanner-scan-type.yaml +++ b/scanners/git-repo-scanner/templates/git-repo-scanner-scan-type.yaml @@ -24,7 +24,7 @@ spec: restartPolicy: OnFailure containers: - name: git-repo-scanner - image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" + image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.Version }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} command: - "python" diff --git a/scanners/test-scan/templates/test-scan-scan-type.yaml b/scanners/test-scan/templates/test-scan-scan-type.yaml index c8a9f91019..3a4dcd16b5 100644 --- a/scanners/test-scan/templates/test-scan-scan-type.yaml +++ b/scanners/test-scan/templates/test-scan-scan-type.yaml @@ -24,7 +24,7 @@ spec: restartPolicy: OnFailure containers: - name: test-scan - image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" + image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.Version }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} command: - "touch" diff --git a/scanners/zap-advanced/templates/zap-advanced-scan-type.yaml b/scanners/zap-advanced/templates/zap-advanced-scan-type.yaml index bbc8f43cc9..2799d2a496 100644 --- a/scanners/zap-advanced/templates/zap-advanced-scan-type.yaml +++ b/scanners/zap-advanced/templates/zap-advanced-scan-type.yaml @@ -46,7 +46,7 @@ spec: restartPolicy: Never containers: - name: zap-advanced-scan - image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" + image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.Version }}" imagePullPolicy: {{ .Values.scanner.image.pullPolicy }} command: - "python3" From a4d7002a445eed2dc867564f75f33d4e27ab8fda Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 12 Oct 2021 12:01:22 +0200 Subject: [PATCH 16/16] Applying new template rules to all template helm files Signed-off-by: Sebastian --- scanners/pingcastle/Chart.yaml | 2 +- .../templates/pingcastle-parse-definition.yaml | 3 ++- .../pingcastle/templates/pingcastle-scan-type.yaml | 9 +++++++-- scanners/pingcastle/values.yaml | 11 +++++++++-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/scanners/pingcastle/Chart.yaml b/scanners/pingcastle/Chart.yaml index 33303174d0..843d1fb8fa 100644 --- a/scanners/pingcastle/Chart.yaml +++ b/scanners/pingcastle/Chart.yaml @@ -9,7 +9,7 @@ description: A Helm chart for the pingcastle security Scanner that integrates wi type: application # version - gets automatically set to the secureCodeBox release version when the helm charts gets published version: v3.1.0-alpha1 -appVersion: v2.9.2.1 +appVersion: "v2.9.2.1" kubeVersion: ">=v1.11.0-0" keywords: diff --git a/scanners/pingcastle/templates/pingcastle-parse-definition.yaml b/scanners/pingcastle/templates/pingcastle-parse-definition.yaml index 8f8e03c9cc..ca172d8137 100644 --- a/scanners/pingcastle/templates/pingcastle-parse-definition.yaml +++ b/scanners/pingcastle/templates/pingcastle-parse-definition.yaml @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 iteratec GmbH +# SPDX-FileCopyrightText: 2021 iteratec GmbH # # SPDX-License-Identifier: Apache-2.0 @@ -8,6 +8,7 @@ metadata: name: "pingcastle-xml" spec: image: "{{ .Values.parser.image.repository }}:{{ .Values.parser.image.tag | default .Chart.Version }}" + imagePullPolicy: {{ .Values.parser.image.pullPolicy }} ttlSecondsAfterFinished: {{ .Values.parser.ttlSecondsAfterFinished }} env: {{- toYaml .Values.parser.env | nindent 4 }} diff --git a/scanners/pingcastle/templates/pingcastle-scan-type.yaml b/scanners/pingcastle/templates/pingcastle-scan-type.yaml index 18966c1927..aeb5c442f4 100644 --- a/scanners/pingcastle/templates/pingcastle-scan-type.yaml +++ b/scanners/pingcastle/templates/pingcastle-scan-type.yaml @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 iteratec GmbH +# SPDX-FileCopyrightText: 2021 iteratec GmbH # # SPDX-License-Identifier: Apache-2.0 @@ -16,13 +16,18 @@ spec: ttlSecondsAfterFinished: {{ .Values.scanner.ttlSecondsAfterFinished }} {{- end }} backoffLimit: {{ .Values.scanner.backoffLimit }} + {{- if .Values.scanner.activeDeadlineSeconds }} + activeDeadlineSeconds: {{ .Values.scanner.activeDeadlineSeconds }} + {{- end }} template: spec: restartPolicy: OnFailure containers: - name: pingcastle image: "{{ .Values.scanner.image.repository }}:{{ .Values.scanner.image.tag | default .Chart.AppVersion }}" - command: ["python3", "run_pingcastle_healthcheck.py"] + command: + - "python3" + - "run_pingcastle_healthcheck.py" resources: {{- toYaml .Values.scanner.resources | nindent 16 }} securityContext: diff --git a/scanners/pingcastle/values.yaml b/scanners/pingcastle/values.yaml index 68e9cd3b5e..3286ba74f5 100644 --- a/scanners/pingcastle/values.yaml +++ b/scanners/pingcastle/values.yaml @@ -9,6 +9,9 @@ parser: # parser.image.tag -- Parser image tag # @default -- defaults to the charts appVersion tag: null + # -- Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + pullPolicy: IfNotPresent + # parser.ttlSecondsAfterFinished -- seconds after which the kubernetes job for the parser will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ ttlSecondsAfterFinished: null # parser.env -- Optional environment variables mapped into each parseJob (see: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) @@ -20,13 +23,17 @@ scanner: repository: # your-repo/scanner-pingcastle: Use your created PingCastle Scanner Container here. # scanner.image.tag -- defaults to the charts version tag: null + # -- Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + pullPolicy: IfNotPresent # scanner.nameAppend -- append a string to the default scantype name. nameAppend: null - # scanner.ttlSecondsAfterFinished -- seconds after which the kubernetes job for the scanner will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ + # -- seconds after which the kubernetes job for the scanner will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ ttlSecondsAfterFinished: null - # scanner.backoffLimit -- There are situations where you want to fail a scan Job after some amount of retries due to a logical error in configuration etc. To do so, set backoffLimit to specify the number of retries before considering a scan Job as failed. (see: https://kubernetes.io/docs/concepts/workloads/controllers/job/#pod-backoff-failure-policy) + # -- There are situations where you want to fail a scan Job after some amount of time. To do so, set activeDeadlineSeconds to define an active deadline (in seconds) when considering a scan Job as failed. (see: https://kubernetes.io/docs/concepts/workloads/controllers/job/#job-termination-and-cleanup) + activeDeadlineSeconds: null + # -- There are situations where you want to fail a scan Job after some amount of retries due to a logical error in configuration etc. To do so, set backoffLimit to specify the number of retries before considering a scan Job as failed. (see: https://kubernetes.io/docs/concepts/workloads/controllers/job/#pod-backoff-failure-policy) # @default -- 3 backoffLimit: 3