什么是 EFS
加密文件系统(英语:Encrypting File System,缩写 EFS)是微软在 NTFS 3.0 中引入的一个功能,它提供文件系统级加密。此技术使文件支持透明加密以保护机密数据免受具有物理访问权限的攻击者侵害。详见维基百科:加密文件系统
EFS 加解密流程
1、EFS使用对称密钥加密文件,这被称为文件加密密钥(File Encryption Key),简称FEK。使用对称加密算法是因为加密和解密大量数据时这比使用非对称密钥密码本消耗更少的时间。在不同的操作系统版本和配置上将使用不同的对称加密算法。
2、然后会使用一个与加密文件的**用户相关联的公钥**加密,加密的 FEK 将被存储在加密文件的 $EFS 属性中
3、解密时,只需拿到对应用户的私钥,解密出 FEK,再使用 FEK 对文件进行解密即可。
EFS 破解
了解完 EFS 的加解密流程,下面就直奔主题:破解 EFS。流程大致如下:
想要解开 EFS 加密文件,用户私钥 RSA.PrivateKey 是关键。上图是通过用户明文密码的方式去获取的用户私钥,如果你没有用户明文密码,也可以通过解析 pfx 文件等方式去获取。
MasterKey File
主密钥文件位置:C:\Users\【用户名】\AppData\Roaming\Microsoft\Protect\【用户SID】
RSA.PrivateKey File
用户私钥文件位置:C:\Users\【用户名】\AppData\Roaming\Microsoft\Crypto\RSA\【用户SID】
$EFS Attribute
常规读取文件的方式,是无法读取到 EFS 加密文件的 $EFS 属性部分的,需要基于 NTFS 系统去读取该属性的数据。
当 NTFS 加密文件时,会为文件创建一个 $EFS 属性。该属性的 ID=0x100,也叫 LOGGED_UTILITY_STREAM (100h)。
其结构体如下:
typedef struct {
UINT32 AttributeLength; /* Length of EFS attribute in bytes. */
UINT32 State; /* Always 0? */
UINT32 Version; /* Efs version. Always 2? */
UINT32 CryptoAPIVersion; /* Always 0? */
UINT8 Checksum[16]; /* MD5 hash of decrypted FEK? This field is
created with a call to UuidCreate() so is
unlikely to be an MD5 hash and is more
likely to be GUID of this encrytped file
or something like that. */
UINT8 ChecksumDDF[16]; /* MD5 hash of DDFs? */
UINT8 ChecksumDRF[16]; /* MD5 hash of DRFs? */
UINT32 OffsetToDDF; /* Offset in bytes to the array of data
decryption fields (DDF), see below. Zero if
no DDFs are present. */
UINT32 OffsetToDRF;/* Offset in bytes to the array of data
recovery fields (DRF), see below. Zero if
no DRFs are present. */
UINT32 Reserved;
} EFS_HEADER;
typedef struct {
UINT32 Count; /* Number of data decryption/recovery fields in the array. */
} EFS_ARRAY_HEADER;
typedef struct {
UINT32 DFLength; /* Length of this data decryption/recovery field in bytes. */
UINT32 CredHeaderOffset; /* Offset in bytes to the credential header. */
UINT32 FEKSize; /* Size in bytes of the encrypted file encryption key (FEK). */
UINT32 FEKOffset; /* Offset in bytes to the FEK from the start of the data
decryption/recovery field. */
UINT32 Reserved; /* always 0? Might be just padding. */
} EFS_DF_HEADER;
typedef struct {
UINT32 CredLength; /* Length of this credential in bytes. */
UINT32 SIDOffset; /* Offset in bytes to the user's sid from start
of this structure. Zero if no sid is present. */
UINT32 Type; /* Type of this credential:
1 = CryptoAPI container.
2 = Unexpected type.
3 = Certificate thumbprint.
other = Unknown type. */
union {
/* CryptoAPI container. */
struct {
UINT32 ContainerNameOffset; /* Offset in bytes to
the name of the container from start of this
structure (may not be zero). */
UINT32 ProviderNameOffset; /* Offset in bytes to the name of the provider from start of this
structure (may not be zero). */
UINT32 PublicKeyBlobOffset; /* Offset in bytes to the public key blob from start of this
structure. */
UINT32 PublicKeyBlobSize; /* Size in bytes of public key blob. */
};
/* Certificate thumbprint. */
struct {
UINT32 CertThumbprintHeaderSize; /* Size in
bytes of the header of the certificate
thumbprint. */
UINT32 CertThumbprintHeaderOffset; /* Offset in
bytes to the header of the certificate
thumbprint from start of this structure. */
UINT32 Unknown1; /* Always 0? Might be padding... */
UINT32 Unknown2; /* Always 0? Might be padding... */
};
};
} EFS_DF_CREDENTIAL_HEADER;
typedef struct {
UINT8 Revision;
UINT8 SubAuthorityCount;
UINT8 IdentifierAuthority[6];
UINT32 SubAuthority;
UINT32 Sid[4];
} EFS_SID;
到这里就非常明确了,只需从 EFS 加密文件的 $EFS Attribute中读取 FEK 密文,再通过用户私钥对其进行解密,得到 FEK明文,再通过对称加密算法,将文件内容进行解密,即可。
参考资料:
[1] EFS 加密文件系统:ntfs.com/attribute-e…
[2] wikipedia:zh.wikipedia.org/wiki/%E5%8A…