tis-audit-bitlocker

10.5.0-38
Audit BitLocker hard disk encryption
3826 downloads
Download
See build result See VirusTotal scan
tis-audit-bitlocker icon
  • package : tis-audit-bitlocker
  • name : Audit BitLocker
  • version : 10.5.0-38
  • categories : Security
  • maintainer : WAPT Team,Tranquil IT,Joffrey Le Piquet
  • editor :
  • licence : wapt_public
  • locale :
  • target_os : windows
  • impacted_process :
  • architecture : all
  • signature_date : 2024-09-24 08:01
  • size : 9.29 Ko
package           : tis-audit-bitlocker
version           : 10.5.0-38
architecture      : all
section           : base
priority          : optional
name              : Audit BitLocker
categories        : Security
maintainer        : WAPT Team,Tranquil IT,Joffrey Le Piquet
description       : Audit BitLocker hard disk encryption
depends           : 
conflicts         : 
maturity          : PROD
locale            : 
target_os         : windows
min_wapt_version  : 2.3
sources           : 
installed_size    : 
impacted_process  : 
description_fr    : Audit du chiffrement BitLocker des disques durs
description_pl    : Audyt szyfrowania dysków twardych BitLocker
description_de    : Audit der BitLocker-Verschlüsselung von Festplatten
description_es    : Auditoría del cifrado de discos duros BitLocker
description_pt    : Auditoria da encriptação do disco rígido BitLocker
description_it    : Controllo della crittografia del disco rigido BitLocker
description_nl    : Controle van BitLocker-encryptie van harde schijven
description_ru    : Аудит шифрования жестких дисков BitLocker
audit_schedule    : 1d
editor            : 
keywords          : 
licence           : wapt_public
homepage          : 
package_uuid      : 39a7ba6f-575a-4220-9fd5-b70872dcb542
valid_from        : 
valid_until       : 
forced_install_on : 
changelog         : 
min_os_version    : 10.0
max_os_version    : 
icon_sha256sum    : b895508a66d6cea028c2a7781604a358298ba9c8082602ab633e8bff7f2b844c
signer            : Tranquil IT
signer_fingerprint: 8c5127a75392be9cc9afd0dbae1222a673072c308c14d88ab246e23832e8c6bb
signature_date    : 2024-09-24T08:01:18.000000
signed_attributes : package,version,architecture,section,priority,name,categories,maintainer,description,depends,conflicts,maturity,locale,target_os,min_wapt_version,sources,installed_size,impacted_process,description_fr,description_pl,description_de,description_es,description_pt,description_it,description_nl,description_ru,audit_schedule,editor,keywords,licence,homepage,package_uuid,valid_from,valid_until,forced_install_on,changelog,min_os_version,max_os_version,icon_sha256sum,signer,signer_fingerprint,signature_date,signed_attributes
signature         : sAj1u32cedCIQUPrnaC54ciWytTdS4naZsHHYVw49dikI+oRzjBCEmgQ28DpYuu1AUeI7Dym5DpvqGw1xzW4/KSCQ0d3bMkgwTq8G8f5ECX4PyY64HQGUU78FciAE/yEtj0IJyXf62UaYCG4EmGAiWDXUwvjr6qZq4d9iTmoMDiCs33m8LoIQenolF3xWoQa+woiKZ/ePT60XK/tuSLUpAJKzgGLQjlqDNpx9YVd2R5gPn5V9pTEY+doMXIYNjblroKJc1KN+toiFcnVsDn0FJrdNecEErfT6eLGAnOuBi3vqwgsJ77yUsvBK0XbbduHAnj5X+9Ah6aXDrgIbKjXyg==
# -*- coding: utf-8 -*-
from setuphelpers import *

try:
    import waptcrypto

    if "encrypted_data_str" in dir(waptcrypto):
        from waptcrypto import encrypted_data_str as rsa_encrypted_data_str
except:
    pass


r"""
Sources:
https://learn.microsoft.com/windows/security/operating-system-security/data-protection/bitlocker/faq
https://learn.microsoft.com/windows/security/operating-system-security/data-protection/bitlocker/bitlocker-basic-deployment
https://learn.microsoft.com/powershell/module/bitlocker/get-bitlockervolume

https://learn.microsoft.com/en-us/windows/win32/secprov/getconversionstatus-win32-encryptablevolume#parameters


BitLocker Powershell informations:
PS C:\waptdev\enable-bitlocker\windows> Get-BitLockerVolume | Get-Member -Name *

   TypeName: Microsoft.BitLocker.Structures.BitLockerVolume

Name                 MemberType Definition
----                 ---------- ----------
Equals               Method     bool Equals(System.Object obj)
GetHashCode          Method     int GetHashCode()
GetType              Method     type GetType()
ToString             Method     string ToString()
AutoUnlockEnabled    Property   System.Nullable[bool] AutoUnlockEnabled {get;}
AutoUnlockKeyStored  Property   System.Nullable[bool] AutoUnlockKeyStored {get;}
CapacityGB           Property   float CapacityGB {get;}
ComputerName         Property   string ComputerName {get;}
EncryptionMethod     Property   Microsoft.BitLocker.Structures.BitLockerVolumeEncryptionMethodOnGet EncryptionMethod {…
EncryptionPercentage Property   System.Nullable[float] EncryptionPercentage {get;}
KeyProtector         Property   System.Collections.ObjectModel.ReadOnlyCollection[Microsoft.BitLocker.Structures.BitLo…
LockStatus           Property   Microsoft.BitLocker.Structures.BitLockerVolumeLockStatus LockStatus {get;}
MetadataVersion      Property   int MetadataVersion {get;}
MountPoint           Property   string MountPoint {get;}
ProtectionStatus     Property   Microsoft.BitLocker.Structures.BitLockerVolumeProtectionStatus ProtectionStatus {get;}
VolumeStatus         Property   System.Nullable[Microsoft.BitLocker.Structures.BitLockerVolumeStatus] VolumeStatus {ge…
VolumeType           Property   Microsoft.BitLocker.Structures.BitLockerVolumeType VolumeType {get;}
WipePercentage       Property   System.Nullable[float] WipePercentage {get;}


"""
volumestatus_dict = {
    0: "FullyDecrypted",
    1: "FullyEncrypted",
    2: "EncryptionInProgress",
    3: "DecryptionInProgress",
    4: "EncryptionPaused",
    5: "DecryptionPaused",
}
# https://learn.microsoft.com/en-us/windows/win32/secprov/getencryptionmethod-win32-encryptablevolume#parameters
# EncryptionMethod: XtsAes128 = 6; XtsAes256 = 7 #
encryptionmethod_dict = {
    0: "None",
    1: "AES_128_WITH_DIFFUSER",
    2: "AES_256_WITH_DIFFUSER",
    3: "Aes128",
    4: "Aes256",
    5: "HARDWARE_ENCRYPTION",
    6: "XtsAes128",
    7: "XtsAes256",
    -1: "(uint32)",
}
target_encryption_method = 7
allow_swap_encryption_method = False  # Not implemented yet
decrypt_cert_list = []


def install():
    # Adding certificates allowed to decrypt in WAPT
    for cert in decrypt_cert_list:
        cert_path = makepath(WAPT.wapt_base_dir, "ssl", cert)
        if not isfile(cert_path):
            print("Copying: %s" % cert_path)
            filecopyto(cert, cert_path)


def audit():
    audit_status = "OK"
    # audit_status = check_tpm_state()

    certs_path = []
    for cert in decrypt_cert_list:
        certs_path.append(makepath(WAPT.wapt_base_dir, "ssl", cert))

    mountpoint_list = ensure_list(run_powershell("(Get-BitLockerVolume).MountPoint"))

    # Cleaning mountpoints (unpartitionned devices and removal devices)
    for mountpoint in mountpoint_list:
        is_ignored = False
        if "?" in mountpoint:
            print("INFO: An unknow volume has been detected and will be skipped (%s)" % mountpoint)
            is_ignored = True
        if run_powershell("Get-Volume -DriveLetter %s | Where-Object DriveType -EQ Removable" % mountpoint.replace(":", "")):
            is_ignored = True
        if is_ignored:
            mountpoint_list.remove(mountpoint)

    for mountpoint in mountpoint_list:
        bitlockervolume = run_powershell(f"Get-BitLockerVolume -MountPoint {mountpoint}")
        protection_status = bitlockervolume.get("ProtectionStatus", 0)  # ProtectionStatus: Off = 0; On = 1
        volumetype = "OperatingSystem" if bitlockervolume.get("VolumeType", 1) == 0 else "Data"  # VolumeType: OperatingSystem = 0; Data = 1
        volumestatus = volumestatus_dict[bitlockervolume.get("VolumeStatus", 0)]
        lockstatus = bitlockervolume.get("LockStatus", 0) #LockStatus : Unlocked = 0; Locked = 1

        if lockstatus == 1:
            print(f"WARNING: Drive {mountpoint} {volumetype} is locked with Bitlocker, cannot retrieve the informations")
            audit_status = set_audit_status(audit_status, "WARNING")
            continue

        elif protection_status == 1 and volumestatus =="FullyEncrypted":
            if volumetype == "OperatingSystem":
                print(f"OK: {mountpoint} {volumetype} drive is encrypted and protection status is ON with BitLocker")
                audit_status = set_audit_status(audit_status, "OK")
            else:
                print(f"OK: {mountpoint} {volumetype} drive is encrypted and protection status is ON with BitLocker")
                audit_status = set_audit_status(audit_status, "OK")  # Warning for external drives?

            try:
                keyprotector_list = ensure_list(run_powershell(f'(Get-BitLockerVolume -MountPoint "{mountpoint}").KeyProtector'))
            except:
                print(f"Unable to get KeyProtector informations for: {mountpoint} drive.")

            for keyprotector in keyprotector_list:
                keyprotectorid = keyprotector["KeyProtectorId"]
                if keyprotector["KeyProtectorType"] in [1,2,4]:
                    # WAPT.delete_audit_data(
                    #     "enable-bitlocker", f"RecoveryPassword_{keyprotectorid}"
                    # )  # not possible from package, please delete from WAPT Console
                    # print("INFO: Skipping Backup-BitLockerKeyProtector for KeyProtectorType: Tpm")
                    continue

                try:
                    # Backuping RecoveryPassword to the AD
                    if registry_readstring(HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\History', 'NetworkName', None):
                        print(f"Backuping: RecoveryPassword {keyprotectorid} to the AD")
                        run_powershell(f'Backup-BitLockerKeyProtector -MountPoint "{mountpoint}" -KeyProtectorId "{keyprotectorid}"')
                except Exception as e:
                    print(e)
                    print(f"WARNING: Failed to backup RecoveryPassword {keyprotectorid} to the AD")
                    audit_status = set_audit_status(audit_status, "WARNING")

                if decrypt_cert_list:
                    try:
                        # Backuping RecoveryPassword to the WAPT Console (encrypted)
                        print(f"Backuping: RecoveryPassword {keyprotectorid} to the WAPT Console")
                        WAPT.write_audit_data_if_changed(
                            "enable-bitlocker",
                            f"RecoveryPassword_{keyprotectorid}",
                            rsa_encrypted_data_str(keyprotector["RecoveryPassword"], certs_path),
                        )
                    except Exception as e:
                        print(e)
                        print(f"WARNING: Failed to backup RecoveryPassword {keyprotectorid} to the WAPT Console")
                        audit_status = set_audit_status(audit_status, "WARNING")
                else:
                    print(
                        f'IMPORTANT: You did not provided "decrypt_cert_list", so the RecoveryPassword {keyprotectorid} cannot be encrypted, so it will not be saved to the WAPT Console'
                    )

            keyprotectortype_list = ",".join(
                run('powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -OutputFormat text -Command "&{(Get-BitLockerVolume -MountPoint "{mountpoint}").KeyProtector.KeyProtectorType}"').splitlines()
            )
            WAPT.write_audit_data_if_changed(
                "enable-bitlocker",
                "keyprotectortype_list_%s_drive" % mountpoint.split(":")[0],
                keyprotectortype_list,
            )
            continue

        elif volumestatus == "EncryptionInProgress":
            encryptpercent = bitlockervolume.get("EncryptionPercentage", 0)
            if volumetype == "OperatingSystem":
                print(f"WARNING: Encryption in progress : {encryptpercent}% on {mountpoint} {volumetype} drive")
                audit_status = set_audit_status(audit_status, "WARNING")
            else:
                print(f"WARNING: Encryption in progress : {encryptpercent}% on {mountpoint} {volumetype} drive")
                audit_status = set_audit_status(audit_status, "WARNING")  # Warning for external drives?
            continue

        elif volumestatus == "DecryptionInProgress":
            encryptpercent = bitlockervolume.get("EncryptionPercentage", 0)
            if volumetype == "OperatingSystem":
                print(f"WARNING: Decryption in progress : {encryptpercent}%  on {mountpoint} {volumetype} drive")
                audit_status = set_audit_status(audit_status, "WARNING")
            else:
                print(f"WARNING: Decryption in progress : {encryptpercent}%  on {mountpoint} {volumetype} drive")
                audit_status = set_audit_status(audit_status, "WARNING")  # Warning for external drives?
            continue

        elif protection_status == 0 and volumestatus =="FullyEncrypted":
            if volumetype == "OperatingSystem":
                print(f"ERROR: {mountpoint} {volumetype} drive is encrypted but protection status is OFF with BitLocker")
                audit_status = set_audit_status(audit_status, "ERROR")
            else:
                print(f"WARNING: {mountpoint} {volumetype} drive is encrypted but protection status is OFF with BitLocker")
                audit_status = set_audit_status(audit_status, "WARNING")  # Warning for external drives?
            continue

        else:
            print(f"ERROR: {mountpoint} {volumetype} drive is not encrypted with BitLocker")
            audit_status = set_audit_status(audit_status, "ERROR")

            # Checking EncryptionMethod
            drive_encryption_method = bitlockervolume.get("EncryptionMethod", 0)
            print(f"INFO: {mountpoint} {volumetype} drive BitLocker EncryptionMethod is: {encryptionmethod_dict[drive_encryption_method]}")


            WAPT.write_audit_data_if_changed(
                "enable-bitlocker",
                "encryptionmethod_%s_drive" % mountpoint.split(":")[0],
                encryptionmethod_dict[drive_encryption_method],
            )

    return audit_status


def set_audit_status(old_audit_status, new_audit_status):
    """Maintain higher criticality for audit status."""
    audit_level = {"OK": 0, "WARNING": 1, "ERROR": 2}

    old_status = old_audit_status.upper().strip()
    new_status = new_audit_status.upper().strip()

    if audit_level.get(new_status, -1) > audit_level.get(old_status, -1):
        return new_status
    else:
        return old_audit_status


def check_tpm_state():
    audit_status = "OK"
    get_tpm = run_powershell("Get-Tpm")
    if get_tpm["TpmPresent"] == False:
        print("ERROR: No TPM chip found on this system")
        audit_status = "ERROR"
    else:
        print("OK: TPM chip found on this system")
        if get_tpm["TpmReady"] == False:
            print("WARNING: TPM chip not ready")
            audit_status = "WARNING"
        else:
            print("OK: TPM chip ready")
    WAPT.write_audit_data_if_changed("enable-bitlocker", "TpmPresent", get_tpm["TpmPresent"])
    WAPT.write_audit_data_if_changed("enable-bitlocker", "TpmReady", get_tpm["TpmReady"])
    if get_tpm["ManufacturerVersion"]:
        WAPT.write_audit_data_if_changed("enable-bitlocker", "ManufacturerVersion", get_tpm["ManufacturerVersion"].split("\x00")[0].strip())
    return audit_status
38d056ab130f7bf7c481c12636a4e9959de36561d3dfcbe54c6e3571bc0c1dc3 : WAPT/certificate.crt
f37247a041dc510291a6a867697b224aa337bdf30adf0901d70defbd94fb7538 : WAPT/control
b895508a66d6cea028c2a7781604a358298ba9c8082602ab633e8bff7f2b844c : WAPT/icon.png
b7b2ff641061ffdc8e5f99f2ea241bac475603c373a67f82be31a2cd3a3f00bf : luti.json
e886c9181e715700c6fa511e19b9e7753e3d93f0c7fc750a67fde6dedbe59f83 : setup.py