转载自:https://www.passcape.com/index.php?section=docsys&cmd=details&id=23
What are LSA secrets?
What is stored in LSA secrets?
Where are LSA secrets stored?
LSA Secrets in detail
CurrVal and OldVal data structure
Encrypting LSA secrets in Windows 2000, XP, 2003
Encrypting secrets in Windows Vista, Windows 7
Reading and editing secrets
Appendix
What are LSA secrets?
LSA secrets is a special protected storage for important data used by the Local Security Authority (LSA) in Windows. LSA is designed for managing a system's local security policy, auditing, authenticating, logging users on to the system, storing private data. Users' and system's sensitive data is stored in secrets. Access to all secret data is available to system only. However, as shown below, some programs, in particular Windows Password Recovery, allow to override this restriction.
What is stored in LSA secrets?
Originally, the secrets contained cached domain records. Later, Windows developers expanded the application area for the storage. At this moment, they can store PC users' text passwords, service account passwords (for example, those that must be run by a certain user to perform certain tasks), Internet Explorer passwords, RAS connection passwords, SQL and CISCO passwords, SYSTEM account passwords, private user data like EFS encryption keys, and a lot more. For example, the NL$KM secret contains the cached domain password encryption key. L$RTMTIMEBOMB stores the amount of time left until the expiration of an inactivated copy of Windows. L$HYDRAENCKEY stores the public RSA2 key used in the Remote Desktop Protocol. Incidentally, even despite the fact that the automatic login is not set, in certain versions of Windows 7 secrets can contain the text of the administrator account password, thus compromising the entire target system.
Where are LSA secrets stored?
LSA secrets are stored in an encrypted form in the Windows registry, in the HKEY_LOCAL_MACHINE/Security/Policy/Secrets key. The parent key, HKEY_LOCAL_MACHINE/Security/Policy, contains the additional data, necessary for accessing and decrypting the secrets. Here are the descriptions of some values of this key.
Key: HKEY_LOCAL_MACHINE/Security/Policy/SecDesc Value name: Data type: REG_BINARY Description: security descriptor for accessing the registry branch with secrets.
Key: HKEY_LOCAL_MACHINE/Security/Policy/PolState Value name: Data type: REG_BINARY Description: current state of the secrets subsystem.
Key: HKEY_LOCAL_MACHINE/Security/Policy/PolRevesion Value name: Data type: REG_BINARY Description: contains the version of the subsystem.
Key: HKEY_LOCAL_MACHINE/Security/Policy/PolPrDmS Value name: Data type: REG_BINARY Description: domain SID.
Key: HKEY_LOCAL_MACHINE/Security/Policy/PolPrDmN Value name: Data type: REG_BINARY Description: domain name.
Key: HKEY_LOCAL_MACHINE/Security/Policy/PolEKList Value name: Data type: REG_BINARY Description: contains the list of encryption keys for LSA secrets.
The value 1.1 in PolRevesion matches the NT operation system, 1.5 – Windows 2000, 1.7 – Windows XP and Win2K3, 1.9 – Windows Vista, 1.10 – Windows 7. Before Windows Vista, only one encryption key was stored in the registry, in the PolSecretEncryptionKey value. Beginning with Windows Vista, PolEKList can contain several encryption keys.
LSA Secrets in detail
On the physical level, secrets are stored in a binary registry file SECURITY with the secret name for the key. For example, SecurityPolicySecrets$MACHINE.ACC. Each secret in the registry is represented by five values:
- CurrVal - current encrypted value of the secret.
- CupdTime - last update time, as an 8-byte FILETIME structure.
- OldVal - previous value of the secret.
- OupdTime - previous update time.
- SecDesc - – security descriptor, i.e. which users can access the secret, and which are banned from accessing it.
If the system is unable to read/decrypt one of the secrets, it writes the sixth value in it, PolMod, which indicates that the secret is damaged. For example, if a transaction to the LSA database was not completed due to a power outage or registry file damage.
CurrVal and OldVal data structure
Beginning with version 1.9, the structure of secrets has changed dramatically; therefore, we are not going to cover the old format. Instead of a single encryption key, now you can bind each secret to any value on the encryption key list (PolEKList). There is also an option to select an encryption algorithm! So, the first 4 bytes in the data structure is the version of the data; then there follows a 16-byte encryption key identifier for locating the necessary key on the list. That is followed by a DWORD with an identifier for a list of encryption algorithms the secret is encrypted with. For example, the value 3 matches a bundle of the SHA-256 hashing algorithm and the AES-256 block encryption algorithm. The algorithm identifier is followed by a 4-byte value with different flags used during the decryption. And, finally, there goes the encrypted data. See the figure.
Encrypting LSA secrets in Windows 2000, XP, 2003
Up to Windows Vista, the decryption of the secrets looked rather trivial. First, one needed to decrypt the secrets encryption key. Here is what it looked like:
BOOL CSecrets::DecryptPrimaryKey() { BYTE rc4key[0x10]; MD5Init(); MD5Update(m_pSyskey,0x10); for ( int i=0; i<1000; i++) MD5Update(((LPBYTE)m_pCypherKey)+0x3C,0x10); MD5Final(rc4key); RC4SetKey(rc4key,0x10); RC4Decrypt(((LPBYTE)m_pCypherKey)+0xC,0x30); return ( memcmp(((LPBYTE)m_pCypherKey)+0xC,CYPHERKEY_AUTHENTIFICATOR,0x10)==0 ); }
Where m_pSyskey - 16-byte SYSKEY value
m_pCypherKey - value from the registry key HKEY_LOCAL_MACHINE/Security/Policy/PolSecretEncryptionKey
Once the secrets encryption key was obtained, one could proceed to the decryption of the secrets. The secrets were encrypted using DES algorithm.
Encrypting secrets in Windows Vista, Windows 7
Beginning with Windows Vista, the encryption algorithm, as it was mentioned, has become much more sophisticated. First, one still needs to decrypt the list of the encryption keys (yes, now multiple keys are allowed), stored in HKEY_LOCAL_MACHINE/Security/Policy/PolEKList. Then proceed to the actual secrets. Each secret now stores a key identifier, encryption algorithm identifier and the actual encrypted data. A working algorithm for decrypting the key looks like:
- Read the key value and find the encryption key identifier.
- On the list of encryption keys (PolEKList)), find the necessary key using the identifier you obtained earlier.
- Decrypt the secret using the algorithm identifier and the found key.
Thus, secrets in the LSA database can now be not only encrypted with different algorithms, but also have different original context. For example, use SYSKEY from other PC.
Reading and editing secrets
There is a set of API for handling secrets available to software developers. Thus, any Windows application can create and read its own secrets, but only within the boundaries of current user context. See application 1 with the source code for reading secrets. If you require viewing or editing LSA secrets, for instance, to delete your account's text password, you can take advantage of Windows Password Recover, which has a convenient plugin for handling LSA secrets. By the way, this plugin works with both current operating system's secrets and with external registry files.
Appendix
1. Source code of the program for reading LSA Secrets. Note that not all secrets can be read under user context. Besides, the Administrator privileges are required. The executable of the program can be downloaded at the following link.
// LsaSecretReader.cpp : Defines the entry point for the console application. #include "stdafx.h" #include <windows.h> #include <stdio.h> #include <ntsecapi.h> #pragma comment (lib, "Advapi32") PLSA_UNICODE_STRING InitLsaString(IN LPWSTR wszString, OUT PLSA_UNICODE_STRING lsastr) { if ( !lsastr ) return NULL; if ( wszString ) { lsastr->Buffer=wszString; lsastr->Length=(USHORT)lstrlenW(wszString)*sizeof(WCHAR); lsastr->MaximumLength=lsastr->Length+2; } else { lsastr->Buffer=L""; lsastr->Length=0; lsastr->MaximumLength=2; } return lsastr; } int _tmain(int argc, _TCHAR* argv[]) { NTSTATUS status; LSA_OBJECT_ATTRIBUTES att; LSA_HANDLE pol; LSA_UNICODE_STRING secret, *data=NULL; if ( argc!=2 ) { _tprintf(TEXT("Syntax: %s secretnamen"),argv[0]); return 1; } memset(&att,0,sizeof(att)); status=LsaOpenPolicy(NULL,&att,0,&pol); if ( status!=ERROR_SUCCESS ) { _tprintf(TEXT("LsaOpenPolicy error: %lXn"),status); return 2; } InitLsaString(argv[1],&secret); status=LsaRetrievePrivateData(pol,&secret,&data); if ( status!=ERROR_SUCCESS ) { _tprintf(TEXT("LsaRetrievePrivateData error: %lXn"),status); return 3; } LsaClose(pol); if ( data && data->Buffer && data->Length ) { for ( USHORT i=0; i<data->Length; i+=16 ) { _tprintf(TEXT("%04X: "),i); LPBYTE ptr=(LPBYTE)data->Buffer; ptr+=i; for ( int j=0; j<min(16,data->Length-i); j++ ) _tprintf(TEXT("%02X "),ptr[j]); _tprintf(TEXT("n")); } } else { _tprintf(TEXT("No datan")); } return 0; }
Example of the output
C:>LsaSecretReader.exe DPAPI_SYSTEM 0000: 01 00 00 00 73 4F 19 CF 6B B7 6C 8A BC 6D 35 EF 0010: 19 9C A6 3E 9A 80 A7 0C 9D D4 FD B1 20 C6 B1 A5 0020: 7A 87 5F 2B 51 3E 1D E0 45 9B 99 B2