Google Chrome protects its user preferences using a hashing (HMAC SHA256) mechanism. However, there’s a way to bypass it and it’s quite used by malware in the wild.
We will first study the way Chrome protects its user settings (Secure Preferences), then we will see how it can be defeated by rewriting the needed hashes. In the end, we will study a malware that uses that technique and we will see how RogueKiller Anti-malware can defeat it using that technique as well.
Secure Preferences
Each user profile (located in %localappdata%/Google/Chrome/User Data/ProfileName) has a bunch of configuration files for storing bookmarks, history, and preferences. Among those files, two of them (Preferences, Secure Preferences) are storing the user settings like homepage, search engine, etc…
Secure Preferences implements (as its name suggests) some securing mechanism to ensure no malware comes to modify the file manually. This is achieved by hashing some of the json nodes with a custom hashing protocol, based on HMAC SHA256, each time a setting is modified by Google Chrome.
At startup, Chrome then verifies all the hashes and if something doesn’t match it asks for a restore.
This is how (an infected) Secure Preferences file looks like:
{
"browser": {
"show_home_button": true
},
"default_search_provider": {
"enabled": true,
"encodings": "UTF-8",
"prepopulate_id": 0
},
"default_search_provider_data": {
"template_url_data": {
"keyword": "trotux",
"url": "http:\/\/www.trotux.com\/search\/?q={searchTerms}&z=63239075972bb5d9d70da35g4zdm9zdeacac3q6oct&from=icb&uid=VBOXXHARDDISK_VB3d33e4ab-f149eb42&type=sp",
...
}
},
"extensions": {
"known_disabled": [
],
"settings": {
...
}
},
"homepage": "http:\/\/www.trotux.com\/?z=63239075972bb5d9d70da35g4zdm9zdeacac3q6oct&from=icb&uid=VBOXXHARDDISK_VB3d33e4ab-f149eb42&type=hp",
"homepage_changed": true,
"homepage_is_newtabpage": false,
"pinned_tabs": [
],
"protection": {
"macs": {
"browser": {
"show_home_button": "D72D3A4AE301492E30C5840566DCCD9EE5F2066E792805D5F59B7DFC056B2F83"
},
"default_search_provider": {
"keyword": "4E70E531D9FE35B77433ED7CBB36F9A72701C928679E49F64F71E63D3813EF86",
"name": "2C12B4EE800F1C223FDF8B2D24967192C55841015DBE6F3602538E75B2209075",
"search_url": "7AB9E5FCF7FF91530B1F36B3D593EA9D48DE74BB228B8F566BBC4E74C4E97705"
},
"default_search_provider_data": {
"template_url_data": "14C800C1FB62974BB653070FEABEC06A4F91ED01773354C03B5C2456DCC3B78A"
},
"extensions": {
"known_disabled": "3B2D6F2EE0DE5BB99976E4DE120B6C6E9E8AE6D50BA6665CF4D7A617783CA5B9",
"settings": {
...
}
},
"google": {
"services": {
"account_id": "B06F39E76B49B24DE765021EBB621EC88FD029F86F4FE2A588360110A7DF4EA1",
"last_account_id": "2CE2762DD69EB763602E6D67F063A9A3302909B0080C6962F7E4BBE1F3AC1861",
"last_username": "C1E45A7D2667A3CFE15B5F1BA572E51554F5BB35AC5ABB709DC3EC0E83596FC3",
"username": "C9139E29A994D7131018AF8C6520A3EFBE59BB3555D3CE5B6F07906CCD10456D"
}
},
"homepage": "6D5A2725E3385B12610051F2019FDC7452CFF7863DF5C4A202CFACF5AE166ACF",
"homepage_changed": true,
"homepage_is_newtabpage": "8CD33E8A34AD6F5F8341702ED482FD16020BBBA37972D958168D8334945CA533",
"pinned_tabs": "6443846DA531F6BDFFE87F17E1AFF9739D4A816CABCAAAF35C0A0EF0E81D9162",
"prefs": {
"preference_reset_time": "DE6810A8F6703E3EDEABD407E27612F88E9DBA3B0318692F57A71005142C2B69"
},
"profile": {
"reset_prompt_memento": "7122E3BBEDDBEC92FDBBD0899A15E3D0B6F8C546195045E571405DFB99C8B82D"
},
"safebrowsing": {
"incidents_sent": "DA02CC41A2157A273538A127A693AF1AB06329276766E7A0BFA1DCCED5720D4A"
},
"search_provider_overrides": "C623DCD793B7DE76BEE45387932E1D245150D190F5322680F0F0E88F73698487",
"session": {
"restore_on_startup": "F1AD6F4A7E65CBCA6683C30586F2F14B958729A1A2E89231DF300F245B5923DD",
"startup_urls": "CCFD36CED4675FF0817C0847AFE300476D804E7AAE437CB2B074F5E8477A4C2D"
},
"software_reporter": {
"prompt_seed": "FED73C26AAD4579B62F8793895CBEC2ECFBE59199C79AB68F486A29AAC51B220",
"prompt_version": "623DD568AFD8A981E71A63CD11663071E151C2B96171AD56D3C58558A6776133"
}
},
"super_mac": "3AA7590924852A9F2A55AC29641D603DDF1EAC8D96E72B0582770B5BC49CD47B"
},
"session": {
"restore_on_startup": 4,
"startup_urls": [
"http:\/\/www.trotux.com\/?z=63239075972bb5d9d70da35g4zdm9zdeacac3q6oct&from=icb&uid=VBOXXHARDDISK_VB3d33e4ab-f149eb42&type=hp"
]
},
"sync": {
}
}
We can see a few interesting fields regarding startup urls and homepage (highlighted). For each field, we have a corresponding entry in the « protection.macs » node. If some program modifies (manually) one of the settings above it will need to update the corresponding hash in the macs, as well as the « super_mac » entry.
Custom HMAC
The custom HMAC hash is fortunately documented from the Chromium sources. With a little bit of reverse, guesses and code reading, we’ve been able to reproduce the algorithm:
The HMAC SHA256 is a hashing mechanism that produces a SHA256 from a key (or seed) and a message. Let’s see how to obtain them:
HMAC Seed
The seed is unique to a machine where Chrome is installed (or per Chrome version?). It’s stored in Chrome’s installation path (C:\Program Files (x86)\Google\Chrome\Application\ChromeVersion\resources.pak). This format is quite known now, and well explained here.
All you need to do is to look for the first resource with a length of 64.
HMAC Message
To build the message, we first need to get a Machine ID (unique identifier per machine). We can follow the logic once again in the Chromium sources, but basically it looks like this:
Obtain machine SID
- Get machine name with GetComputerName (JOHN-PC)
- Get SID for machine name with LookupAccountName
- Convert SID to string with ConvertSidToStringSid (S-1-5-21-1650828501-840997873-2917006960)
Obtain volume ID
- Get system drive letter with GetSystemDirectory (C:)
- Get serial number with GetVolumeInformation (1551496638)
Create machine ID
The machine ID can then be obtained with the following pseudo-code (please note everything is performed as binary operations):
machine_id = SHA1(machine_sid) + volume_id
machine_id += CRC8(machine_id)
machine_id = ToString(machine_id)
Looks like: 6C91392A619A18390D101846C1656CC6812CA02D5C79F5BE89
Obtain the message
The message can be obtained using the following pseudo-code:
message = machine_id (6C91392A619A18390D101846C1656CC6812CA02D5C79F5BE89)
message += json_path (extensions.settings.aapocclcgogkmnckokdopfmhonfmgoek)
message += json_content ({"ack_external":true,"app_launcher_ordinal":"z",...,"was_installed_by_oem":false})
Looks like: 6C91392A619A18390D101846C1656CC6812CA02D5C79F5BE89extensions.settings.aapocclcgogkmnckokdopfmhonfmgoek{"ack_external":true,"app_launcher_ordinal":"z",...,"was_installed_by_oem":false}
Please note that the Json content needs to be modified a little bit by removing the empty arrays and objects, and that the « < » character (for some reason) needs to be replaced by its unicode hexadecimal representation.
Hashing the Message
Find below the code (shortened) we use to hash a json node, given its path and required machine ID and seed. It’s using a HMAC 256 method from cryptopp, but you can use any method you like (works with OpenSSL).
wstring Chrome::GetContentHmac( wstring const& json_path, JsonDB& db, json_t* node ) const
{
// We need to remove empty arrays and objects
json_t* clean = db.Clone( node );
if ( clean == NULL ) return L"";
JsonDB::RemoveEmpty( clean );
string json_content = db.StrAnsi( false, clean, true );
json_content = mstring::replacestr( json_content, "<", "\\u003C" );
JsonDB::Release( clean );
string key = mstring( hmac_seed ).to_utf8();
string path = mstring( json_path ).to_utf8();
string content_str = json_content;
string msg = mstring( machine_id ).to_utf8() + path + content_str;
Buffer key_buff = Buffer::FromHexString( mstring::from_utf8( key ) );
wstring hmac = Encrypt::HMACSHA256String( (const char*) key_buff.Data(), key_buff.Size(), msg );
return hmac;
}
Once you have that HMAC, it’s easy to replace the corresponding entry in the protection.macs node. After that, you need to get and replace the super_mac as well with the following information:
message = machine_id (6C91392A619A18390D101846C1656CC6812CA02D5C79F5BE89)
message += json_path (empty)
message += json_content (content of the protection.macs node)
We have developed a small script able to check and replace all the broken macs from the secure preferences, here’s some screenshots:
In the Wild
Some malware are using that trick to bypass Chrome protection and install themselves in the user settings.
This the case of the adware Trotux/Elex, which replaces the homepage, startup urls and the search engine. The infected secure preferences given as example comes from this malware.
RogueKiller is able to remove it, as well as cleanup the browser.
Detection and Removal
Starting with version 12.8.0, RogueKiller is able to detect infectious Chrome settings, and remove them. It’s also able to update the protection.macs settings so that the cleanup will be totally transparent for the Chrome browser, and it won’t restore the infected setup.
It’s really important, because any setting restored without updating the HMAC hashes will result in a restoration of the infectious state by the Chrome browser iteself.
Links
- https://kaimi.io/2015/04/google-chrome-and-secure-preferences
- https://cs.chromium.org/chromium/src/rlz/lib/machine_id.cc?sq=package:chromium
- http://stackoverflow.com/questions/10633357/how-to-unpack-resources-pak-from-google-chrome
- https://blog.malwarebytes.com/threat-analysis/2015/05/winyahoo-pup-modifies-chrome-secure-preferences/