# TPM survey ## Group Policy setting Windows10、Windows11中可以使用Group Policy Setting來設定Windows系統對於TPM的使用方式。 我們可以按下windows鍵+R,並輸入:gpedit.msc,即可打開Group Policy Setting。 ![](https://i.imgur.com/c7Iw3J6.png) 接著轉至:系統管理範本->系統->可信賴平台模組服務,便可設定windows系統對於TPM的原則。 ![](https://i.imgur.com/UJbhvPC.png) ### The Level of TPM owner authorization information available to the operating system ![](https://i.imgur.com/xIb5ZoH.png) 此設定可以調整Windows會使用TPM來進行哪些特定行為。越高的層級,允許使用TPM的行為就越多。例如: |TPM1.2|TPM2.0|Purpose|Can level 0 access?|Can level 2 access?|Can level 4 access?| | :-----:| :----: | :----: | :----: | :----: | :----: | |OwnerAuthAdmin|StorageOwnerAuth|建立SRK|No|Yes|Yes| |OwnerAuthEndorsement|EndorsementAuth|2.0:建立或使用EK 1.2:建立AIK|Yes|Yes|Yes| |OwnerAuthFull|LockoutAuth|重置、改變字典攻擊保護措施|No|No|Yes| 而能設定的level就是三種,分別為Full(level 4)、Delegated(level 2)、None(level 0)。 **從Windows 10 version 1607,,或是Windows 11開始,windows在初始化TPM時會將TPM owner密碼隨機生成並丟棄。TPM元件可以設定一組owner密碼,透過該密碼可以重置、清除TPM,或者定義TPM對字典攻擊的應對措施,以上操作甚至也可以遠端執行。Windows為了避免此種密碼存在系統registry裡面,便會初始設定TPM owner authorization Level為5,即會在初始化後立即拋棄owner password。在初始化前將此level設成4便可完全保留TPM的擁有權,即將這初始化密碼保存下來。** https://docs.microsoft.com/en-us/windows/security/information-protection/tpm/change-the-tpm-owner-password - Full(level 4) 會將TPM使用權留在本機registry,包括TPM owner password,使用者有完整操控TPM的權限。 - Delegated(level 2) 保留除了TPM owner password之外的其他東西,除了重置、清除TPM之類的行動之外不影響到功能(在version 1703之前預設值為此,之後預設值為5但意思與這個層級差不多)。 - None(level 0) 完全拋棄TPM的使用、擁有權,對於某些需要TPM的function會受其影響。 這個設定也可以在registry做修改: Registry key: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\TPM DWORD: OSManagedAuthLevel ### Standard User Lockout Duration ![](https://i.imgur.com/DwWEzKt.png) 當使用者傳送指令給TPM時若TPM回覆authorization failure便會使counter數+1,此數值可以設定在**多少**分鐘內超過某個閾值時,使用者將無法繼續傳送指令給TPM。算是由系統來輔助進行字典爆破攻擊。 預設值為480分鐘。 ### Standard User Individual Lockout Threshold 以及 Standard User Total Lockout Threshold ![](https://i.imgur.com/KdOvmuy.png) 前述指令定義的閾值。 ### Configure the system to use legacy Dictionary Attack Prevention Parameters setting for TPM 2.0 ![](https://i.imgur.com/xEbzwHE.png) 即啟用TPM本身帶有的字典防護功能。 ## Back up the TPM recovery information to AD DS Windows server2012 R2以上的AD server才適用。 Windows可以將TPM的所以權以及資訊backup到AD Domain service上,這樣AD的管理員需要重設某台電腦的TPM時便可以遠端來執行,當local使用者忘記TPM的密碼時也可以透過AD的管理員來進行TPM reset。每個TPM只有一組owner密碼,該密碼會以sha-1的方式加密後儲存在AD對於該台電腦的attribute上,common name(cn)為 ms-TPM-OwnerInformation,而真正的密碼並不會被以任何形式留下來。 ### On the AD DS #### Add-TPMSelfWriteACE.vbs 我們可以透過一個vb script來在AD DS上增加一個access control entry來記錄各電腦的TPM資料,可以讓local端把TPM資訊寫在上面。 Add-TPMSelfWriteACE.vbs: ``` '=============================================================================== ' ' This script demonstrates the addition of an Access Control Entry (ACE) ' to allow computers to write Trusted Platform Module (TPM) ' recovery information to Active Directory. ' ' This script creates a SELF ACE on the top-level domain object, and ' assumes that inheritance of ACL's from the top-level domain object to ' down-level computer objects are enabled. ' ' ' ' Last Updated: 12/05/2012 ' Last Reviewed: 12/05/2012 ' Microsoft Corporation ' ' Disclaimer ' ' The sample scripts are not supported under any Microsoft standard support program ' or service. The sample scripts are provided AS IS without warranty of any kind. ' Microsoft further disclaims all implied warranties including, without limitation, ' any implied warranties of merchantability or of fitness for a particular purpose. ' The entire risk arising out of the use or performance of the sample scripts and ' documentation remains with you. In no event shall Microsoft, its authors, or ' anyone else involved in the creation, production, or delivery of the scripts be ' liable for any damages whatsoever (including, without limitation, damages for loss ' of business profits, business interruption, loss of business information, or ' other pecuniary loss) arising out of the use of or inability to use the sample ' scripts or documentation, even if Microsoft has been advised of the possibility ' of such damages. ' ' Version 1.0.2 - Tested and re-released for Windows 8 and Windows Server 2012 ' '=============================================================================== ' -------------------------------------------------------------------------------- ' Access Control Entry (ACE) constants ' -------------------------------------------------------------------------------- '- From the ADS_ACETYPE_ENUM enumeration Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = &H5 'Allows an object to do something '- From the ADS_ACEFLAG_ENUM enumeration Const ADS_ACEFLAG_INHERIT_ACE = &H2 'ACE can be inherited to child objects Const ADS_ACEFLAG_INHERIT_ONLY_ACE = &H8 'ACE does NOT apply to target (parent) object '- From the ADS_RIGHTS_ENUM enumeration Const ADS_RIGHT_DS_WRITE_PROP = &H20 'The right to write object properties Const ADS_RIGHT_DS_CREATE_CHILD = &H1 'The right to create child objects '- From the ADS_FLAGTYPE_ENUM enumeration Const ADS_FLAG_OBJECT_TYPE_PRESENT = &H1 'Target object type is present in the ACE Const ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT = &H2 'Target inherited object type is present in the ACE ' -------------------------------------------------------------------------------- ' TPM and FVE schema object GUID's ' -------------------------------------------------------------------------------- '- ms-TPM-OwnerInformation attribute SCHEMA_GUID_MS_TPM_OWNERINFORMATION = "{AA4E1A6D-550D-4E05-8C35-4AFCB917A9FE}" '- ms-FVE-RecoveryInformation object SCHEMA_GUID_MS_FVE_RECOVERYINFORMATION = "{EA715D30-8F53-40D0-BD1E-6109186D782C}" '- Computer object SCHEMA_GUID_COMPUTER = "{BF967A86-0DE6-11D0-A285-00AA003049E2}" 'Reference: "Platform SDK: Active Directory Schema" ' -------------------------------------------------------------------------------- ' Set up the ACE to allow write of TPM owner information ' -------------------------------------------------------------------------------- Set objAce1 = createObject("AccessControlEntry") objAce1.AceFlags = ADS_ACEFLAG_INHERIT_ACE + ADS_ACEFLAG_INHERIT_ONLY_ACE objAce1.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT objAce1.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT + ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT objAce1.Trustee = "SELF" objAce1.AccessMask = ADS_RIGHT_DS_WRITE_PROP objAce1.ObjectType = SCHEMA_GUID_MS_TPM_OWNERINFORMATION objAce1.InheritedObjectType = SCHEMA_GUID_COMPUTER ' -------------------------------------------------------------------------------- ' NOTE: BY default, the "SELF" computer account can create ' BitLocker recovery information objects and write BitLocker recovery properties ' ' No additional ACE's are needed. ' -------------------------------------------------------------------------------- ' -------------------------------------------------------------------------------- ' Connect to Discretional ACL (DACL) for domain object ' -------------------------------------------------------------------------------- Set objRootLDAP = GetObject("LDAP://rootDSE") strPathToDomain = "LDAP://" & objRootLDAP.Get("defaultNamingContext") ' e.g. string dc=fabrikam,dc=com Set objDomain = GetObject(strPathToDomain) WScript.Echo "Accessing object: " + objDomain.Get("distinguishedName") Set objDescriptor = objDomain.Get("ntSecurityDescriptor") Set objDacl = objDescriptor.DiscretionaryAcl ' -------------------------------------------------------------------------------- ' Add the ACEs to the Discretionary ACL (DACL) and set the DACL ' -------------------------------------------------------------------------------- objDacl.AddAce objAce1 objDescriptor.DiscretionaryAcl = objDacl objDomain.Put "ntSecurityDescriptor", Array(objDescriptor) objDomain.SetInfo WScript.Echo "SUCCESS!" ``` 必須將strPathToDomain改成自己的域名,並在cmd打上: ``` $ cscript Add-TPMSelfWriteACE.vbs ``` #### List-ACEs.vbs 這個script可以list或remove有關bitlocker或TPM的資訊的ACEs。 需要將**strPathToDomain**改為自己的domain,**If IsFilterActive ()** 則可以細部定義需要list或是remove哪些TPM或bitlocker的資訊。 使用: ``` $ cscript List-ACEs.vbs ``` 來執行。 List-ACEs.vbs: ``` '=============================================================================== ' ' This script lists the access control entries (ACE's) configured on ' Trusted Platform Module (TPM) and BitLocker Drive Encryption (BDE) schema objects ' for the top-level domain. ' ' You can use this script to check that the correct permissions have been set and ' to remove TPM and BitLocker ACE's from the top-level domain. ' ' ' Last Updated: 12/05/2012 ' Last Reviewed: 12/02/2012 ' ' Microsoft Corporation ' ' Disclaimer ' ' The sample scripts are not supported under any Microsoft standard support program ' or service. The sample scripts are provided AS IS without warranty of any kind. ' Microsoft further disclaims all implied warranties including, without limitation, ' any implied warranties of merchantability or of fitness for a particular purpose. ' The entire risk arising out of the use or performance of the sample scripts and ' documentation remains with you. In no event shall Microsoft, its authors, or ' anyone else involved in the creation, production, or delivery of the scripts be ' liable for any damages whatsoever (including, without limitation, damages for loss ' of business profits, business interruption, loss of business information, or ' other pecuniary loss) arising out of the use of or inability to use the sample ' scripts or documentation, even if Microsoft has been advised of the possibility ' of such damages. ' ' Version 1.0.2 - Tested and re-released for Windows 8 and Windows Server 2012 ' '=============================================================================== ' -------------------------------------------------------------------------------- ' Usage ' -------------------------------------------------------------------------------- Sub ShowUsage Wscript.Echo "USAGE: List-ACEs" Wscript.Echo "List access permissions for BitLocker and TPM schema objects" Wscript.Echo "" Wscript.Echo "USAGE: List-ACEs -remove" Wscript.Echo "Removes access permissions for BitLocker and TPM schema objects" WScript.Quit End Sub ' -------------------------------------------------------------------------------- ' Parse Arguments ' -------------------------------------------------------------------------------- Set args = WScript.Arguments Select Case args.Count Case 0 ' do nothing - checks for ACE's removeACE = False Case 1 If args(0) = "/?" Or args(0) = "-?" Then ShowUsage Else If UCase(args(0)) = "-REMOVE" Then removeACE = True End If End If Case Else ShowUsage End Select ' -------------------------------------------------------------------------------- ' Configuration of the filter to show/remove only ACE's for BDE and TPM objects ' -------------------------------------------------------------------------------- '- ms-TPM-OwnerInformation attribute SCHEMA_GUID_MS_TPM_OWNERINFORMATION = "{AA4E1A6D-550D-4E05-8C35-4AFCB917A9FE}" '- ms-FVE-RecoveryInformation object SCHEMA_GUID_MS_FVE_RECOVERYINFORMATION = "{EA715D30-8F53-40D0-BD1E-6109186D782C}" ' Use this filter to list/remove only ACEs related to TPM and BitLocker aceGuidFilter = Array(SCHEMA_GUID_MS_TPM_OWNERINFORMATION, _ SCHEMA_GUID_MS_FVE_RECOVERYINFORMATION) ' Note to script source reader: ' Uncomment the following line to turn off the filter and list all ACEs 'aceGuidFilter = Array() ' -------------------------------------------------------------------------------- ' Helper functions related to the list filter for listing or removing ACE's ' -------------------------------------------------------------------------------- Function IsFilterActive() If Join(aceGuidFilter) = "" Then IsFilterActive = False Else IsFilterActive = True End If End Function Function isAceWithinFilter(ace) aceWithinFilter = False ' assume first not pass the filter For Each guid In aceGuidFilter If ace.ObjectType = guid Or ace.InheritedObjectType = guid Then isAceWithinFilter = True End If Next End Function Sub displayFilter For Each guid In aceGuidFilter WScript.echo guid Next End Sub ' -------------------------------------------------------------------------------- ' Connect to Discretional ACL (DACL) for domain object ' -------------------------------------------------------------------------------- Set objRootLDAP = GetObject("LDAP://rootDSE") strPathToDomain = "LDAP://" & objRootLDAP.Get("defaultNamingContext") ' e.g. dc=fabrikam,dc=com Set domain = GetObject(strPathToDomain) WScript.Echo "Accessing object: " + domain.Get("distinguishedName") WScript.Echo "" Set descriptor = domain.Get("ntSecurityDescriptor") Set dacl = descriptor.DiscretionaryAcl ' -------------------------------------------------------------------------------- ' Show Access Control Entries (ACE's) ' -------------------------------------------------------------------------------- ' Loop through the existing ACEs, including all ACEs if the filter is not active i = 1 ' global index c = 0 ' found count - relevant if filter is active For Each ace In dacl If IsFilterActive() = False or isAceWithinFilter(ace) = True Then ' note to script source reader: ' echo i to show the index of the ACE WScript.echo "> AceFlags: " & ace.AceFlags WScript.echo "> AceType: " & ace.AceType WScript.echo "> Flags: " & ace.Flags WScript.echo "> AccessMask: " & ace.AccessMask WScript.echo "> ObjectType: " & ace.ObjectType WScript.echo "> InheritedObjectType: " & ace.InheritedObjectType WScript.echo "> Trustee: " & ace.Trustee WScript.echo "" if IsFilterActive() = True Then c = c + 1 ' optionally include this ACE in removal list if configured ' note that the filter being active is a requirement since we don't ' want to accidentally remove all ACEs If removeACE = True Then dacl.RemoveAce ace End If end if End If i = i + 1 Next ' Display number of ACEs found If IsFilterActive() = True Then WScript.echo c & " ACE(s) found in " & domain.Get("distinguishedName") _ & " related to BitLocker and TPM" 'note to script source reader: change this line if you configure your own filter ' note to script source reader: ' uncomment the following lines if you configure your own filter 'WScript.echo "" 'WScript.echo "The following filter was active: " 'displayFilter 'Wscript.echo "" Else i = i - 1 WScript.echo i & " total ACE(s) found in " & domain.Get("distinguishedName") End If ' -------------------------------------------------------------------------------- ' Optionally remove ACE's on a filtered list ' -------------------------------------------------------------------------------- if removeACE = True and IsFilterActive() = True then descriptor.DiscretionaryAcl = dacl domain.Put "ntSecurityDescriptor", Array(descriptor) domain.setInfo WScript.echo c & " ACE(s) removed from " & domain.Get("distinguishedName") else if removeACE = True then WScript.echo "You must specify a filter to remove ACEs from " & domain.Get("distinguishedName") end if end if ``` ### On the local machines https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-8.1-and-8/jj679889(v=ws.11) 接著用AD管理員的帳號登入local machine,並在group policy setting裡找到Computer Configuration\Administrative Templates\System->Trusted Platform Module Services->Turn on TPM backup to Active Directory Domain Services,將其打開。 ### Recover procedure 當我們的local machine需要recover時,我們可以利用一個script來將存放在ACE中的資料取出並建立一個密碼檔案。擁有該密碼檔案將讓我們可以對local端的TPM進行admin層級的操作(i.e.重置)。 ``` $ cscript Get-TPMOwnerInfo.vbs ``` 使用該script,Get-TPMOwnerInfo.vbs: ``` '================================================================================= ' ' This script demonstrates the retrieval of Trusted Platform Module (TPM) ' recovery information from Active Directory for a particular computer. ' ' It returns the TPM owner information stored as an attribute of a ' computer object. ' ' Last Updated: 12/05/2012 ' Last Reviewed: 12/05/2012 ' ' Microsoft Corporation ' ' Disclaimer ' ' The sample scripts are not supported under any Microsoft standard support program ' or service. The sample scripts are provided AS IS without warranty of any kind. ' Microsoft further disclaims all implied warranties including, without limitation, ' any implied warranties of merchantability or of fitness for a particular purpose. ' The entire risk arising out of the use or performance of the sample scripts and ' documentation remains with you. In no event shall Microsoft, its authors, or ' anyone else involved in the creation, production, or delivery of the scripts be ' liable for any damages whatsoever (including, without limitation, damages for loss ' of business profits, business interruption, loss of business information, or ' other pecuniary loss) arising out of the use of or inability to use the sample ' scripts or documentation, even if Microsoft has been advised of the possibility ' of such damages. ' ' Version 1.0 - Initial release ' Version 1.1 - Updated GetStrPathToComputer to search the global catalog. ' Version 1.1.2 - Tested and re-released for Windows 8 and Windows Server 2012 ' '================================================================================= ' -------------------------------------------------------------------------------- ' Usage ' -------------------------------------------------------------------------------- Sub ShowUsage Wscript.Echo "USAGE: Get-TpmOwnerInfo [Optional Computer Name]" Wscript.Echo "If no computer name is specified, the local computer is assumed." WScript.Quit End Sub ' -------------------------------------------------------------------------------- ' Parse Arguments ' -------------------------------------------------------------------------------- Set args = WScript.Arguments Select Case args.Count Case 0 ' Get the name of the local computer Set objNetwork = CreateObject("WScript.Network") strComputerName = objNetwork.ComputerName Case 1 If args(0) = "/?" Or args(0) = "-?" Then ShowUsage Else strComputerName = args(0) End If Case Else ShowUsage End Select ' -------------------------------------------------------------------------------- ' Get path to Active Directory computer object associated with the computer name ' -------------------------------------------------------------------------------- Function GetStrPathToComputer(strComputerName) ' Uses the global catalog to find the computer in the forest ' Search also includes deleted computers in the tombstone Set objRootLDAP = GetObject("LDAP://rootDSE") namingContext = objRootLDAP.Get("defaultNamingContext") ' e.g. string dc=fabrikam,dc=com strBase = "<GC://" & namingContext & ">" Set objConnection = CreateObject("ADODB.Connection") Set objCommand = CreateObject("ADODB.Command") objConnection.Provider = "ADsDSOOBject" objConnection.Open "Active Directory Provider" Set objCommand.ActiveConnection = objConnection strFilter = "(&(objectCategory=Computer)(cn=" & strComputerName & "))" strQuery = strBase & ";" & strFilter & ";distinguishedName;subtree" objCommand.CommandText = strQuery objCommand.Properties("Page Size") = 100 objCommand.Properties("Timeout") = 100 objCommand.Properties("Cache Results") = False ' Enumerate all objects found. Set objRecordSet = objCommand.Execute If objRecordSet.EOF Then WScript.echo "The computer name '" & strComputerName & "' cannot be found." WScript.Quit 1 End If ' Found object matching name Do Until objRecordSet.EOF dnFound = objRecordSet.Fields("distinguishedName") GetStrPathToComputer = "LDAP://" & dnFound objRecordSet.MoveNext Loop ' Clean up. Set objConnection = Nothing Set objCommand = Nothing Set objRecordSet = Nothing End Function ' -------------------------------------------------------------------------------- ' Securely access the Active Directory computer object using Kerberos ' -------------------------------------------------------------------------------- Set objDSO = GetObject("LDAP:") strPath = GetStrPathToComputer(strComputerName) WScript.Echo "Accessing object: " + strPath Const ADS_SECURE_AUTHENTICATION = 1 Const ADS_USE_SEALING = 64 '0x40 Const ADS_USE_SIGNING = 128 '0x80 Set objComputer = objDSO.OpenDSObject(strPath, vbNullString, vbNullString, _ ADS_SECURE_AUTHENTICATION + ADS_USE_SEALING + ADS_USE_SIGNING) ' -------------------------------------------------------------------------------- ' Get the TPM owner information from the Active Directory computer object ' -------------------------------------------------------------------------------- strOwnerInformation = objComputer.Get("msTPM-OwnerInformation") WScript.echo "msTPM-OwnerInformation: " + strOwnerInformation ``` 這個script執行完後會output出一個TPM密碼hash過後的字串。我們打開文字編輯器,將以下複製上去,並把該字串取代掉**TpmOwnerPasswordHash**: ``` <?xml version="1.0" encoding="UTF-8"?> <!-- This page is a backup of Trusted Platform Module (TPM) owner authorization information. Upon request, use the authorization information to prove ownership of the computer's TPM. IMPORTANT: Please keep this file in a secure location away from your computer's local hard drive. --> <tpmOwnerData version="1.0" softwareAuthor="Microsoft Windows [Version 6.1.7600]" creationDate="2009-11-11T14:39:29-08:00" creationUser="DOMAIN\username" machineName="mymachine">                 <tpmInfo manufacturerId="1096043852"/>                 <ownerAuth>TpmOwnerPasswordHash</ownerAuth> </tpmOwnerData> ``` 接著將他存成.tpm類型的檔案,如果要存許需要密碼的TPM功能,我們便可以利用這個檔案當作密碼。 ## PCR bank(待補) https://docs.microsoft.com/zh-tw/windows/security/information-protection/tpm/switch-pcr-banks-on-tpm-2-0-devices