如何以编程方式获取“强制密码历史记录”组策略设置?

时间:2015-06-22 21:13:35

标签: windows security winapi group-policy

我如何以编程方式获取Enforce Password History组策略设置?

研究工作

您可以在以下位置找到“组策略”选项:

  

**计算机配置\ Windows设置\安全设置\帐户策略\密码策略**

     

强制执行密码记录

     

此安全设置确定在重用旧密码之前必须与用户帐户关联的唯一新密码的数量。该值必须介于0到24个密码之间。

     

此策略使管理员可以通过确保不再重复使用旧密码来增强安全性。

与所有组策略选项一样,它存储在注册表中。不幸的是,它存储在一个未记录的注册表位置:

  

HKEY_LOCAL_MACHINE \ SAM \ SAM \域\帐户\˚F

undocumented binary blob format

一个WMI类RSOP_SecuritySettingBoolean,但没有任何上下文,它只是一个悬在那里的名字 - 我不知道如何阅读COM / native。

NetValidatePasswordPolicy

Windows确实提供NetValidatePasswordPolicy API,允许它验证您的密码,例如:

  • 太多不好的尝试
  • 帐户锁定
  • 锁定自动重置
  • 最短密码年龄
  • 最长密码年龄
  • 密码重用

它会在计算机上生效的组策略之后执行所有这些操作。除密码历史记录外,一切都很好。

该功能要求您传递密码哈希列表,例如:

  • $2a$14$mACnM5lzNigHMaf7O1py1OLCBgGL4tYUF0N/4rS9CwDsI7ytwL4D6
  • $2a$14$mACnM5lzNigHMaf7O1py1O3vlf6.BA8k8x3IoJ.Tq3IB/2e7g61Km
  • $2a$12$.TtQJ4Jr6isd4Hp.mVfZeuh6Gws4rOQ/vdBczhDx.19NFK0Y84Dle
  • $2a$12$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm

以及新候选密码的哈希值,例如:

  • $2a$10$1JsBs47iuMNsV166PKV.u.56hlT5/tRe9V5t5FIdfA0axpDSQuNN

这将导致 NetValidatePasswordPolicy 检查您当前的哈希值是否与任何现有哈希值匹配。不幸的是,检查以前的密码哈希的整个概念仅在您使用弱密码算法(such as PBKDF2 that Windows uses)时有效。

因为我使用现代的昂贵的盐渍,密码哈希算法(BCrypt / SCrypt),所以无法仅通过密码确定性地生成哈希 - 我可以&# 39;只需检查旧列表即可。我必须针对之前存储的 来重新扫描用户的新密码。

  • 这不仅是一项昂贵的操作;可能需要12秒才能检查所有24个存储的哈希值
  • 我不知道何时停止,因为我不知道密码历史记录组策略值(例如,我将检查所有24个存储的哈希值,当我只需要检查零时)。

我考虑过使用24个存储密码哈希的虚拟列表调用NetValidatePasswordPolicy,例如:

  • a
  • b
  • c
  • d
  • ...
  • v
  • w
  • x

然后,API会告诉我密码与n历史记录中的密码不匹配。但API也旨在为您提供必须保留的内容。 可能然后返回:

  • $2a$10$1JsBs47iuMNsV166PKV.u.56hlT5/tRe9V5t5FIdfA0axpDSQuNN
  • a
  • b
  • c

从中我可以推断出密码历史记录长度

但我还没到那儿。

我已经三天了,并且失去了耐心。

  • 为什么微软会混淆群组政策?
  • 为什么微软不允许人们阅读它?
  • 为什么没有证件?
  • 我如何得到它?

1 个答案:

答案 0 :(得分:1)

事实证明,使用 RSOP_SecuritySettingBoolean (结果策略集)是一个坏主意;因为它只适用于加入域的机器。

同样查询Active Directory仅适用于加入域的计算机;以及能够查询域控制器的用户的工作(可以取消授权)。

真正的解决方案是使用NetUserModalsGet,它可以返回以下结构:

struct USER_MODALS_INFO_0
{
    DWORD usrmod0_min_passwd_len;
    DWORD usrmod0_max_passwd_age;
    DWORD usrmod0_min_passwd_age
    DWORD usrmod0_force_logoff; 
    DWORD usrmod0_password_hist_len; //Specifies the length of password history maintained. 
          //A new password cannot match any of the previous usrmod0_password_hist_len passwords. 
          //Valid values for this element are zero through DEF_MAX_PWHIST.
}

struct USER_MODALS_INFO_3 
{
   DWORD usrmod3_lockout_duration;
   DWORD usrmod3_lockout_observation_window;
   DWORD usrmod3_lockout_threshold;
}

示例代码为:

Int32 GetPasswordHistoryLength()
{
   PUSER_MODALS_INFO_0 info0;

   NET_API_STATUS res = NetUserModalsGet(nil, 0,  out info0);

   if (res <> NERR_Success)
      RaiseWin32Error(res);
   try
   {
      return info0.usrmod0_password_hist_len;
   }
   finally
   {
      NetApiBufferFree(info0);
   }
}

文档说最大值为DEF_MAX_PWHIST,在Lmaccess.h中定义为:

//
// user modals related defaults
//

#define MAX_PASSWD_LEN      PWLEN
#define DEF_MIN_PWLEN       6
#define DEF_PWUNIQUENESS    5
#define DEF_MAX_PWHIST      8

#define DEF_MAX_PWAGE       TIMEQ_FOREVER               // forever
#define DEF_MIN_PWAGE       (unsigned long) 0L          // 0 days
#define DEF_FORCE_LOGOFF    (unsigned long) 0xffffffff  // never
#define DEF_MAX_BADPW       0                           // no limit
#define ONE_DAY             (unsigned long) 01*24*3600  // 01 day

但事实并非如此。该策略允许用户设置最多24个。

  

注意:任何已发布到公共领域的代码。无需归属。