http://www.iefans.net/liulanqi-chucun-mima/
一、引言 我之前的文章中介绍了名为dumpmon的推特机器人,它监控着众多“贴码网站”的账户转储、配置文件和其他信息。自那以后,我一直留意着监测到的信息。接下来会有关于dumpmon的一系列文章,而本文则关注浏览器是如何存储密码的。 这里提到dumpmon,是因为我偶然发现一些贴码,如下网址,应该是感染在计算机上的恶意软件的日志。我便想:我总是认为最好不要让浏览器直接存储密码,但是原因呢?恶意软件从感染的计算机中获得密码会有多轻松呢?因为从一处获得所有想要的资料有点困难,所以我决定在此文贴出结果以及一些从各个浏览器的密码管理器中提取密码的简单代码。 http://pastebin.com/raw.php?i=QMzNWqPF 二、浏览器 本文所述,是在windows 8系统上分析下述浏览器,此处链接列表是为了帮助读者直接跳到感兴趣的浏览器部分:
三、Chrome浏览器 获得密码难易程度:简单 我们从Chrome浏览器开始。令人失望的是,chrome浏览器是最容易被提取密码的。加密后的密钥存储于%APPDATA%..LocalGoogleChromeUser DataDefaultLogin Data"下的一个SQLite数据库中。但是是如何获转存并加密的呢?我从《谷歌Chrome浏览器是如何存储密码的》这篇文章中获得了Chrome存储密码的诸多信息,而这篇文章是4年前写得。虽然从那篇文章以后Chrome做了些改变,但是我将按照同样的方式,利用Chromium源码的一些片段向你展示密码是如何转储的。
- 存储加密密码
- 密码破译
from os import getenv import sqlite3 import win32crypt # Connect to the Database conn = sqlite3.connect(getenv("APPDATA") + "..LocalGoogleChromeUser DataDefaultLogin Data") cursor = conn.cursor() # Get the results cursor.execute('SELECT action_url, username_value, password_value FROM logins') for result in cursor.fetchall(): # Decrypt the Password password = win32crypt.CryptUnprotectData(result[2], None, None, None, 0)[1] if password: print 'Site: ' + result[0] print 'Username: ' + result[1] print 'Password: ' + password运行上述代码,可以看到已经成功了!虽然找到密码是如何存储的有点费事(也可以使用其他的动态方法,但是分析代码会更透彻),但是解密密码则几乎没费什么力气。唯一被保护起来的就是密码的部分,还仅仅保护当前用户。 四、IE浏览器 获得密码难易程度:简单/一般/困难(依版本而定) 本质上来讲,直到IE10之前,IE浏览器的密码管理与Chrome使用的是相同的技术,但有一些有趣的改变。为了全面的展示,我们先简单讨论一下IE7——IE9的密码存储,然后再讨论在IE10中的变革。
- IE7-9浏览器
注册表(基于表单的验证)——这类密码是提交给诸如Facebook、Gmail之类站点的。 证书文件——HTTP验证密码方式,类似于网上登陆证书。根据本篇文章需要,接下来讨论基于表单验证的证书,这也是大多数攻击者可能选择的攻击目标。这些证书存储于如下注册表键位置: HKEY_CURRENT_USERSoftwareMicrosoftInternet ExplorerIntelliFormsStorage2 用regedit(注册表编辑器)可以看到值,类似于下面这样:正如Chrome中的示例,这些证书使用Windows API中的CryptProtectData函数加密后储存。不同之处是该函数添加了额外的熵(译者注:熵,熵就是混乱的程度,用来描述某个事件不断趋向混乱的过程)。这里的熵,就是这注册表键值,它是网站URL的SHA1的校验和,以供证书使用。 这非常有用,因为当用户访问网站时,IE能够迅速根据URL的哈希值判断是否已经有此证书,之后再用此哈希值完成证书解密。如果攻击者不知道此处使用了URL,解密证书就会变得很困难。 通常,攻击者能够通过历遍用户因特网访问历史,hash每个URL以及检查每个存储证书的方式,来降低此种保护方式的效果。 本文中没有贴出完整代码,你可以在这里处获得完整示例。现在,我们开始讨论IE10。
- IE10浏览器
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Windows.Security.Credentials; namespace PasswordVaultTest { class Program { static void Main(string[] args) { // Create a handle to the Widnows Password vault Windows.Security.Credentials.PasswordVault vault = new PasswordVault(); // Retrieve all the credentials from the vault IReadOnlyList credentials = vault.RetrieveAll(); // The list returned is an IReadOnlyList, so there is no enumerator. // No problem, we'll just see how many credentials there are and do it the // old fashioned way for (int i = 0; i < credentials.Count; i++) { // Obtain the credential PasswordCredential cred = credentials.ElementAt(i); // "Fill in the password" (I wish I knew more about what this was doing) cred.RetrievePassword(); // Print the result Console.WriteLine(cred.Resource + ':' + cred.UserName + ':' + cred.Password); } Console.ReadKey(); } } }执行该程序后,输出类似于下图所示:注意:我删除了一些我已经禁止IE储存的站点。除此之外,我也不是很清楚为什么有些凭据被储存了起来。 正如你所见,只要我们的程序在特定用户环境中执行,提取指定用户使用的所有密码略繁琐但还是挺简单的。下面我们继续。 五、Firefox浏览器 获得密码的难易程度:一般/非常困难 接下来谈谈比较棘手的Firefox。主要使用这些幻灯片中的方法获取关于用户数据存储位置的资料。 首先,透露下Firefox的密码管理的小秘密。为满足开发者创建满足各种安全标准的应用程序,Mozilla开发了一个叫做“Network Security Services”,或叫NSS的开源库。Firefox使用其中一个叫做”Security Decoder Ring”,或叫SDR的API来帮助实现账号证书的加密和解密函数。虽然名字很文艺,我们还是来看看firefox是如何使用它完成加密的: 当一个Firefox配置文件被首次创建时,一个叫做SDR的随机key和一个Salt(译者注:Salt,在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”)就会被创建并存储在一个名为“key3.db”的文件中。利用这个key和盐,使用3DES加密算法来加密用户名和密码。密文是Base64编码的,并存储在一个叫做signons.sqlite的sqlite数据库中。Signons.sqlite和key3.db文件均位于%APPDATA%MozillaFirefoxProfiles[random_profile]目录。 所以我们要做的就是得到SDR密钥。正如此处解释的,这个key被保存在一个叫PCKS#11软件“令牌”的容器中。该令牌被封装进入内部编号为PKCS#11的“槽位”中。因此需要访问该槽位来破译账户证书。 还有一个问题,这个SDR也是用3DES(DES-EDE-CBC)算法加密的。解密密钥是Mozilla叫做“主密码”的hash值,以及一个位于key3.db文件中对应的叫做“全局盐”的值。 Firefox用户可以在浏览器的设置中设定主密码,但关键是好多用户不知道这个特性。正如我们看到的,用户整个账号证书的完整性链条依赖于安全设置中选择的密码,它是攻击者唯一不知道的值。如果用户使用一个强健的主密码,那么攻击者想要恢复存储的证书是不太可能的。 那么——如果用户没有设置主密码,空密码就会被使用。这意味着攻击者可以提取全局盐,获得它与空密码做hash运算结果,然后使用该结果破译SDR密钥。再用破译的SDR密钥危害用户证书。 该过程看起来就是这样:想知道的更清楚,我们可以简单查下源代码。负责证书解密的主要函数是PK11SDR_Decrypt。此处不再展示整个函数,仅分别列出如下被调用的函数:
PK11_GetInternalKeySlot() //得到内部key槽 PK11_Authenticate() //使用主密码对slot鉴权PK11_FindFixedKey() //从slot中获得SDR密钥 Pk11_Decrypt() //使用SDR密钥破译Base64编码的数据至于破译密码的示例代码,过程有点复杂,此处就不再累述了。介绍两个可以完成此过程的开源工程:
- FireMaster - 暴力破解主密码
- ffpasscrack - 推荐的是Python的解决方案。这个方案使用libnss.so库做负载DLL。在Windows上使用的话,可以利用cygwin的DLL文件。
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
作者:
作者: