Password Algorithms: Internet Explorer 7, 8, 9

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

PasswordAlgorithms: Internet Explorer 7, 8, 9

IE7、8、9中的密码算法

                                               原文链接:Password Algorithms: Internet Explorer 7, 8, 9


一,介绍

在Windows8系统下,IE10 采用了不同于之前的加密算法和存放方案,所以我可能会在以后单独分析它。现在我将分析Windows7下9.0.9版本的IE

这里的一切都与传统的IE7,8完全一致。

考虑到客户可能会避免将系统升级到Windows8,所以我认为这种保护措施还是值得细细讨论。


二,存储

用户所有的自动完成表单都存放在NTUSER.DAT文件中,并且这个文件是由SHA-1散列和DPAPI的大二进制对象(BLOB)组成。

下面是我系统的一些hash散列

C:\>regquery "HKCU\Software\Microsoft\InternetExplorer\IntelliForms\Storage2"

HKEY_CURRENT_USER\Software\Microsoft\InternetExplorer\IntelliForms\Storage2

    6FBD22A243E7F5A0D660199683F52543E80CEB99EC    REG_BINARY    01000000D08C9DDF0115D1118. . .

   DF11F9BE8F0049A2FBFF29C6D49FE77383C2A6783A    REG_BINARY    01000000D08C9DDF0115D1118. . .

   E4CE6B2B79515319A7360D97E3B217F2FC843CC019    REG_BINARY    01000000D08C9DDF0115D1118. . .


为了防止离线破解,这些BLOB已经被截断。当IE连接到一个网站时,它需要凭据(指账户)来自动登录,它将

1,  导出URL的SHA-1的校验和

2,  在自动完成表单中搜索这个校验和

3,  如果发现校验和,就使用URL解密DPAPI保护的BLOB,并自动填充登录字段。


三,生成

先拿到第二个哈希值(上面展示的三个哈希值中的第二个,老外应该是要对那个hash散列开始分析)

DF11F9BE8F0049A2FBFF29C6D49FE77383C2A678 3A

这个是采用Unicode编码的字符串https://accounts.google.com/servicelogin 使用SHA-1产生的校验和

最后一个字节0x3A 是每个字节采用SHA-1散列后的校验和

以下函数使用Windowscrypto API演示了这个过程。


bool GetUrlHash(std::wstring url, std::wstring &result) {
  HCRYPTPROV hProv;
  HCRYPTHASH hHash;
  bool bResult = false;
  std::transform(url.begin(), url.end(), url.begin(), ::tolower); 
  if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 
      CRYPT_VERIFYCONTEXT)) {
    if (CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash)) {
      if (CryptHashData(hHash, (PBYTE)url.c_str(), 
          url.length() * sizeof(wchar_t) + 2, 0)) {

        BYTE bHash[20];
        DWORD dwHashLen = sizeof(bHash);
        if ((bResult = CryptGetHashParam(hHash, HP_HASHVAL, bHash, 
            &dwHashLen, 0))) {
          BYTE chksum = 0;
          wchar_t ch[4];
          for (size_t i = 0;i < 20 + 1;i++) {
            BYTE x;

            if (i < 20) {
              x = bHash[i];
              chksum += x;
            } else {
              x = chksum;
            }
            wsprintf(ch, L"%02X", x);
            result.push_back(ch[0]);
            result.push_back(ch[1]);
          }
        }
      }
      CryptDestroyHash(hHash);      
    }
    CryptReleaseContext(hProv, 0);
  }
  return bResult;
}


每一个用户名和密码都采用Unicode格式存储

如果存在相同的URL的表单凭据,新的账户信息会被添加在现有的表单凭据中

 

问题在于,并没有正式的文档准确的描述了凭据表单的结构,幸而,网上有一个文档描叙了它的旧版结构,这对我帮助很大。

enum { MAX_STRINGS = 200 };   
enum { INDEX_SIGNATURE=0x4B434957 };
enum { INIT_BUF_SIZE=1024 };
enum { LIST_DATA_PASSWORD = 1 };

struct StringIndex {
  DWORD   dwSignature;
  DWORD   cbStringSize;   // up to not including first StringEntry
  DWORD   dwNumStrings;   // Num of StringEntry present
  INT64   iData;          // Extra data for string list user

  struct tagStringEntry {
    union
    {
      DWORD_PTR   dwStringPtr;    // When written to store
      LPWSTR      pwszString;     // When loaded in memory
    };
    FILETIME    ftLastSubmitted;
    DWORD       dwStringLen;        // Length of this string
  }StringEntry[];
};


使用这个结构来解析一个已经解密的BLOB以供参考引起了一些麻烦,并且需要一些小的改动。在IEFrame.dll中,CryptProtectData()使用URL 作为凭据(密钥)来加密StringIndex和凭据表单。

接下来的问题是发现被用做密钥的原始的URL,这也是为什么IE密码算法相当不错的原因。




四,获取登录网址

有许多方法可以获取URL用于解析IE7-IE9密码。缓冲中通常有一个访问网站的列表,这个列表可以列举出我们想要的URL。

下面是使用COM的老获取URL的一种方式


void EnumCache1() {
  HRESULT hr = CoInitialize(NULL);
  if (SUCCEEDED(hr)) {
    IUrlHistoryStg2 *pHistory = NULL;
    hr = CoCreateInstance(CLSID_CUrlHistory, NULL, 
        CLSCTX_INPROC_SERVER, 
        IID_IUrlHistoryStg2,(void**)(&pHistory));
    if (SUCCEEDED(hr)) {
      IEnumSTATURL *pUrls = NULL;
      hr = pHistory->EnumUrls(&pUrls);
      if (SUCCEEDED(hr)) {
        while (TRUE) {
          STATURL st;
          ULONG result;
          hr = pUrls->Next(1, &st, &result);
          
          if (SUCCEEDED(hr) && result == 1) {
            AddUrl(st.pwcsUrl);
          } else {
            break;
          }
        }
        pUrls->Release();
      }
      pHistory->Release();
    }
    CoUninitialize();
  }  
}


另一种方法是使用WININET API

void EnumCache2()   
{   
  HANDLE hEntry;   
  DWORD dwSize;
  BYTE buffer[8192];
  LPINTERNET_CACHE_ENTRY_INFO info = (LPINTERNET_CACHE_ENTRY_INFO) buffer;
  dwSize = 8192;
  hEntry = FindFirstUrlCacheEntry(NULL, info, &dwSize);
  if (hEntry != NULL) {
    do {
      if (info->CacheEntryType != COOKIE_CACHE_ENTRY) {
        AddUrl(info->lpszSourceUrlName);
      }
      dwSize = 8192;    
    } while (FindNextUrlCacheEntry(hEntry, info, &dwSize));   
    FindCloseUrlCache(hEntry);
  }
}


从更高的角度来看,你也可以解析index.dat文件,但我这里并不打算那么做,因为它是在取证的高度。

 

一个更好的方法可能是阅读从互联网上收集的URL列表。

五,恢复账户

恢复账户,即IE7-IE9的解密表单过程,它迫使我们使用URL表来解密,以下过程可以收集到自动完成表单的列表

#define MAX_URL_HASH 255

#define MAX_URL_DATA 8192

 

typedef struct _IE_STORAGE_ENTRY {

  std::wstring UrlHash;

  DWORD cbData;

  BYTE pbData[MAX_URL_DATA];

} IE_STORAGE_ENTRY, *PIE_STORAGE_ENTRY;


DWORD GetAutocompleteEntries() {
  HKEY hKey;
  DWORD dwResult;
  dwResult = RegOpenKeyEx(HKEY_CURRENT_USER, 
      L"Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2",
      0, KEY_QUERY_VALUE, &hKey);
  if (dwResult == ERROR_SUCCESS) {
    DWORD dwIndex = 0;
    while (TRUE) {
      IE_STORAGE_ENTRY entry;
      DWORD cbUrl = MAX_URL_HASH;
      wchar_t UrlHash[MAX_URL_HASH];
      entry.cbData = MAX_URL_DATA;
      dwResult = RegEnumValue(hKey, dwIndex, UrlHash, &cbUrl, 
          NULL, 0, entry.pbData, &entry.cbData);
      if (dwResult == ERROR_SUCCESS) {
        entry.UrlHash = UrlHash;
        ac_entries.push_back(entry);
      } else if (dwResult == ERROR_NO_MORE_ITEMS) {
        break;
      }
      dwIndex++;
    }
    RegCloseKey(hKey);
  }  
  return ac_entries.size();
}



现在,有了URL字符串和自动完成表单,我们可以尝试使用CryptUnprotectData()去解密那些数据。然后使用StringIndex结构解析解密后的数据。

void ParseBlob(PBYTE pInfo, const wchar_t *url) {
  StringIndex* pBlob = (StringIndex*)pInfo;
  // get offset of data
  PBYTE pse = (PBYTE)&pInfo[pBlob->cbHdrSize + pBlob->cbStringSize1] ;
  // process 2 entries for each login
  for (DWORD i = 0;i < pBlob->dwNumStrings;i += 2) {
    // get username and password
    wchar_t *username = (wchar_t*)&pse[pBlob->StringEntry[i + 0].dwStringPtr];
    wchar_t *password = (wchar_t*)&pse[pBlob->StringEntry[i + 1].dwStringPtr];
    bool bTime;
    wchar_t last_logon[MAX_PATH];
    if (lstrlen(password) > 0) {
      // get last time this was used
      FILETIME ft;
      SYSTEMTIME st;
      FileTimeToLocalFileTime(&pBlob->StringEntry[i].ftLastSubmitted, &ft);
      FileTimeToSystemTime(&ft, &st);
      bTime = (GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &st, L"MM/dd/yyyy", last_logon, MAX_PATH) > 0);
    } else {
      bTime = false;
    }
    wprintf(L"\n%-30s  %-20s  %-15s %s", username, password, bTime ? last_logon : L"NEVER", url);
  }
}


六,总结

由于URL作为entropy()来使用,因为可以恢复自动完成表单的所有条目。

这仅仅可以恢复当前流行的网页的凭据表单,诸如Facebook, Gmail, Instagram, Hotmail.

但少为人知的将是问题,除非网址被存储被高速缓存中。


动态密码算法介绍与实现 动态密码,亦称一次性密码(One Time Password, 简称 OTP),是一种高效简单又比较安全的密码生成算法,在我们的生活以及工作中随处可见,身为开发者,也或多或少在自己的业务系统中集成了二步验证机制,那么,技术运用,既要知其然,更要知其所以然,动态密码算法是怎样的? 读前指引 通过这篇文章,你可以了解以下知识: 动态密码... 阅读详情

相关推荐

在CentOS 6.5上安装OpenLDAP并配置LDAP方式用户登录

在CentOS 6.5上安装OpenLDAP并配置LDAP方式用户登录

云原生社区博客分享 5299

【U8】存货核算查询凭证条件界面,会计年度看不到当前的年度。

【问题现象】 用友U8+,在【存货核算】--【查询凭证】功能下, 查询条件中【会计年度】选择不到当前年度。 例如: 21年总账已经开账结转了。并且存货核算1月份已经制单。 在存货核算--查询凭证 的会计年度,选择不到21年...

努力不懈的为广大客户提供优质的产品与真诚、贴心、专业的服务! 2万+

VC编程实现IE7 IE8 IE9自动完成口令获取

/**************************************************************************************************** 都是网上的代码,自己组合起来的,刚开始报很多错误,花了很多时间终于搞定了 环境:VC6.0+SDK(SDK必须) 简单说明:IE7 IE8将网站的URL保存于历史文件中,将自动完成的密码保存

blackbean的专栏 662

windows下IE等软件密码口令保存地址

首先推荐一个网站: http://www.nirsoft.net 这里各种抓密码的工具和说明很全。 以下文字转自http://upx8.com/article.asp?id=563 一.Windows Network Passwords (XP/Vista/2003): 当您连接到另一个网络上的计算机(如一些文件系统\\MyComp\MyFolder),Windows允许您保存的密码。如果

海阔天空 6883

IE7自动完成口令获取

前一阵子自己邮箱的口令忘记了,为了找回邮箱口令到网上找了好多密码找回的工具,发现在IE7下都不好使,迫于无奈,只好自己研究了,通过Google和OllyDbg,用了1整天时间终于弄清楚了IE7下的自动完成口令获取方法,不敢独享,特公布如下,希望能对大家有帮助。自Internet Explorer 7.0开始,微软完全改变了密码保存的方式,将网站的URL保存于历史文件中,将自动完成的密码保存于注册表

老K的笔记 903

Password Algorithms: Internet Explorer 10 (Windows Vault)

Password Algorithms: Internet Explorer 10 (Windows Vault) IE10中的密码算法(Windows Vault) 本文介绍了IE10对自动完成表单数据的加密原理,并且附有原作者对IE10加密数据的读取,可以用来获取自动保存的账户信息等。

xutengaaa的专栏 2407

基于Java的家政服务管理系统的设计与实现-计算机毕设 【课程设计】 05300

前端顾客用户模块: (1)注册登陆:用户可以通过注册功能创建一个新账户,输入必要的信息如用户名、密码、邮箱等。登录功能允许用户输入已注册的凭证来访问他们的个人账户。系统会提供忘记密码和密码重置的选项,以帮助用户恢复账户访问权限。 (2)首页:用户进入系统后,首页展示了轮播图、新闻资讯以及推荐服务。用户可以浏览信息,并查看平台最新动态和推荐内容,快速获取相关信息。 (3)通知公告:用户可以查看平台发布的公告信息,包括网站的公告、关于我们、联系方式以及网站介绍等内容,帮助用户了解平台的基本信息和运营情况。 (4

WeiXin_DZbishe的博客 735

Java 枚举(enum) 详解7种常见的用法

JDK1.5引入了新的类型——枚举。在 Java 中它虽然算个“小”功能,却给我的开发带来了“大”方便。 大师兄我又加上自己的理解,来帮助各位理解一下。 用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。  Java代码 

Jerry的一亩三分地 1578

枚举enum的使用方式

一 直接使用 public class Test {  /*  * enum很像特殊的class,实际上enum声明定义的类型就是一个类。  * 编译后有一个独立的months.class  * 两种方式 1是直接声明 然后使用 2是声明一个类  * */ public enum months{JANUARY, FEBRUARY};   /**  * @param args  */ publi...

zz_xyz的博客 248

认识IE浏览器

本篇文章收集了一些IE的基本知识点,以丰富自己的知识库。 Engine Status

反粒子的博客 648

浏览器密码存储原理和渗透中的利用

一、引言 我之前的文章中介绍了名为dumpmon的推特机器人,它监控着众多“贴码网站”的账户转储、配置文件和其他信息。自那以后,我一直留意着监测到的信息。接下来会有关于dumpmon的一系列文章,而本文则关注浏览器是如何存储密码的。 这里提到dumpmon,是因为我偶然发现一些贴码,比如这篇, 应该是感染在计算机上的恶意软件的日志。我便想:我总是认为最好不要让浏览器直接存储密码,但

hpp24的专栏 4536

Linux用户密码管理

Linux用户密码管理修改密码:passwd非交互式修改密码修改帐号和密码的有效期限chage使用-l参数列出用户密码过期的设置:使密码立即失效 修改密码:passwd # 当前用户修改密码,直接使用passwd passwd # 为其他用户修改密码 passwd 用户名 非交互式修改密码 # 用echo写入新密码到passwd中 ## passwd --stdin:从标准输入(比如管道)写入密码 # echo方式不要使用特殊字符,比如!,会被转义 echo "新密码"|passwd --stdin

教Linux的李老师 4575

Internet Explorer编程简述(二)

  Internet Explorer 编程简述(二)在IE中编辑OLE嵌入文档  除了打开Internet上的网页,Internet Explorer还能够浏览本地文件夹及文件。如果浏览的是PDF文档或Office文档,有时候你会发现当调用Navigate("xxx.doc")的时候,Adobe Reader/Acrobat或Office等Document Servers会在IE中嵌入自己的一

The key to .Net 529

您保存的Internet Explorer密码的安全性如何?

One of the most convenient tools browsers offer is the ability to save and automatically prefill your passwords on login forms. Because so many sites require accounts and it is well known (or should b...

culunxun2863的博客 286

enum 枚举的使用

g value, String desc) { this.name = name; this.value = value; this.desc= desc; } }

aa_moon的专栏 245
上一篇: Password Algorithms: Cisco Unified Personal Communicator
下一篇: 设计模式-结构型02-桥接模式
18的小小鸟
博客等级 码龄15年 3粉丝 13原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值