---
# System prepended metadata

title: TPM survey

---

# 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