Quest KACE K1000 (Former Dell Product), allows you to create “customized” inventory rules that provide flexibility to run commands, whether through standard command prompt, or other methods.
For this particular use case, we’re trying to identify what Chrome extensions are installed in our non-domain endpoints that we’re managing. If you are dealing with domain-joined systems, I’d recommend managing these extensions via Google Chrome’s GPO which can be found in my past article.
If you don’t use KACE K1000 in your environment, you can still follow the article and later skip to the “For non-KACE users” section to accomplish the same thing.
Within KACE we’re going to create a custom inventory rule to return the extensions found under my user appdata directory: C:\Users\pdelgado\AppData\Local\Google\Chrome\User Data\Default\Extensions
I found the easiest way to do this is to use the dir command within command prompt, with the /b syntax.
dir /b “C:\Users\pdelgado\AppData\Local\Google\Chrome\User Data\Default\Extensions” which returns the following:
Reference for Dir:
/b | Use this option to show the dir results using “bare” format, which removes the typical header and footer information, as well as all the details on each item, leaving only the directory name or file name and extension. |
The equivalent of powershell is this:
Get-ChildItem -Path “$($env:LOCALAPPDATA)\Google\Chrome\User Data\Default\Extensions” -Name
Within Kace, create a custom inventory rule and call it “Google Chrome Extensions”
Navigate to Inventory > Software > Choose Action > New
provide a script name: Google Chrome Extensions
Highlight all of your Windows OS under Supported Operating Systems
Enter the following as the custom inventory rule:
ShellCommandTextReturn(dir /b “C:\Users\pdelgado\AppData\Local\Google\Chrome\User Data\Default\Extensions”)
Save it!
This will run that command on each endpoint that matches that path and will save the output to the KACE database. Note: This is assuming that your non-domain systems are using the same username. If your usernames are all different throughout the environment, I don’t think this will work. I played around with dir /b “%LOCALAPPDATA%\Google\Chrome\User Data\Default\Extensions” but this did not work. I’m assuming it’s because the KACE agent is running as SYSTEM user context.
Moving on, you should see the list of extensions when you look at custom inventory rules results when looking up an endpoint.
Identifying Extensions:
Google chrome comes with certain extensions by default, in addition there are legitimate extensions such as Adobe PDF readers, or anti-virus extensions added by legitimate products. I spent some time identifying the known extensions via Google Chrome Extensions site; Although some extensions follow an old ID convention or the Google URL store has changed.
Here they are:
Extension Name | Extension ID |
Google Slides | aapocclcgogkmnckokdopfmhonfmgoek |
Google Docs | aohghmighlieiainnegkcijnfilokake |
Google Calendar #old extension | ejjicmeblgpmajnghnpcppodonldlgfn |
Google Docs | ghbmnnjooekpmoecnnnilnnbdlolhkhi |
Google Drive | apdfllckaahabafndbhieahigkjlhalf |
Youtube | blpcfgokakmgnkcojhhkbfbldkacnbeo |
Google Sheets | felcaaldnbdncclmgdcncolpebgiejap |
Google Chrome Web Store | nmmhkkegccagdldgiimedpiccmgmieda |
Gmail | pjkljhegncpnkpknbcohdijeoejaedia |
Chromecast | pkedcjkdefgpdelpbcmbmeomcjbeemfm |
Google Search | coobgpohoikkiipiblmjeljniedjpjpf |
Google Translate | aapbdbdomjkkjkaonfhkkikfgjllcleb |
I like interacting with the KACE database directly via Mysql Workbench; therefore, I created a SQL script to easily identify the known extensions when creating reports. This made it easy to identify the unknown extensions and also spotting nefarious extensions that shouldn’t be running in the environment:
Note: this assumes that you created the custom inventory software rule and named it “Google Chrome Extensions”.
Here’s the SQL script which will allow you to create an easy-to-read report:
SELECT MACHINE.NAME, MACHINE.IP,MACHINE.CS_DOMAIN,MACHINE.USER,MACHINE.OS_NAME,MACHINE.LAST_INVENTORY, REPLACE (REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE (REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE (REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE (REPLACE(REPLACE(REPLACE(REPLACE (REPLACE(STR_FIELD_VALUE, '<DIR>','') ,'<br/>', ',') ,'aapocclcgogkmnckokdopfmhonfmgoek', 'Google Slides') ,'aohghmighlieiainnegkcijnfilokake', 'Google Docs') ,'ejjicmeblgpmajnghnpcppodonldlgfn', 'Google Calendar') #old extension ,'ghbmnnjooekpmoecnnnilnnbdlolhkhi', 'Google Docs') ,'apdfllckaahabafndbhieahigkjlhalf', 'Google Drive') ,'blpcfgokakmgnkcojhhkbfbldkacnbeo', 'Youtube') ,'felcaaldnbdncclmgdcncolpebgiejap', 'Google Sheets') ,'nmmhkkegccagdldgiimedpiccmgmieda', 'Google Chrome Web Store') ,'pjkljhegncpnkpknbcohdijeoejaedia', 'Gmail') ,'pkedcjkdefgpdelpbcmbmeomcjbeemfm', 'Chromecast') ,'coobgpohoikkiipiblmjeljniedjpjpf', 'Google Search') ,'aapbdbdomjkkjkaonfhkkikfgjllcleb', 'Google Translate') #Password Managers ,'fdjamakpfbbddfjaooikfcpapjohcfmg', 'Dashlane Password Manager') ,'hdokiejnpimakedhajhdlcegeplioahd', 'LastPass Password Manager') ,'lpdfbkehegfmedglgemnhbnpmfmioggj', 'ThinkVantage Password Manager') #Other 3rd Party Extensions ,'efaidnbmnnnibpcajpcglclefindmkaj', 'Adobe Acrobat') ,'jlhmfgmfgeifomenelglieieghnjghma', 'Cisco Webex') ,'fceempjejlfaadkgdacpfhheknndlcjl', 'Cisco Webex App for Chrome') ,'ceopoaldcnmhechacafgagdkklcogkgd', 'OnlineMapFinder') ,'menkifleemblimdogmoihpfopnplikde', 'Line - Instant Messaging') #https://chrome.google.com/webstore/detail/line/menkifleemblimdogmoihpfopnplikde?hl=en ,'njabckikapfpffapmjgojcnbfjonfjfg', 'Cookies.txt by Genuinous') # https://chrome.google.com/webstore/detail/cookiestxt/njabckikapfpffapmjgojcnbfjonfjfg ,'hpfmedbkgaakgagknibnonpkimkibkla', 'CRM For Gmail') # https://chrome.google.com/webstore/detail/crm-for-gmail/hpfmedbkgaakgagknibnonpkimkibkla?hl=en ,'jadhamcfimejpbemfkgoeijaimpciehj', 'YourTemplateFinder') # https://chrome.google.com/webstore/detail/yourtemplatefinder/jadhamcfimejpbemfkgoeijaimpciehj?hl=en ,'bkfmkomnkbkkdehmnmabbgbdpcolmddh', 'New Tab Redirect') # https://chrome.google.com/webstore/detail/new-tab-redirect/icpgjfneehieebagbmdbhnlpiopdcmna?hl=en #Potential Unwanted Extensions ,'bmnlcjabgnpnenekpadlanbbkooimhnj', 'Honey - Shopping Extension') ,'gihfmmedoddijgnhkgfgnkeohkpbipol', 'Yahoo Web') ,'commhkacjheiacaopdonmodahaoadoln', 'Yahoo Partner') ,'mgkjffcdjblaipglnmhanakilfbniihj', 'Earbits') ,'jafmombbhklnagadfbfplohhgljimdjg', 'Convert to PDF now') ,'aaaaigmelgfmkfjicbbgbkcbagedejhj', 'Ask Networks') ,'aeaeigaepbpgiodmifdpnpdcbelfbmhg', 'Monster Math Flash Cards') ,'boeajhmfdjldchidhphikilcgdacljfm', 'Facebook') ,'dnflpnhpbffehddplcdlohealbgbbamk', 'PDFConverterHQ Toolbar') ,'djlgdeklopcjagknhlchbdjekgpgenad', 'DarkTheme') # https://chrome.google.com/webstore/detail/dark-theme-v3/djlgdeklopcjagknhlchbdjekgpgenad ,'mallpejgeafdahhflmliiahjdpgbegpk', 'FromDocToPDF') # https://chrome.google.com/webstore/detail/fromdoctopdf/mallpejgeafdahhflmliiahjdpgbegpk?hl=en-US #Unwanted Extensions & Hijackers ,'lmjegmlicamnimmfhcmpkclmigmmcbeh', 'PUP- Google Drive App Launcher *Double check*') ,'ldhkdaoikclkecocioipjifepiiceeai', 'PUP- Searchpdf.com') ,'oehmgogbegigifcdjcalpcbcjbjfaiee', 'PUP- Spigot') ,'bddikhbjcannknadmcmeikpeiabhfbgl', 'PUP- Mindspark SearchFromOnline') ,'bhfhojbhbnajajgihpicejdalbjlpcep', 'PUP- WebExpEnhanced') ,'dofoafnmdocgkdphpkdooahjkhpmakjd', 'PUP- Dragonboost?') ,'bonccgihhlgaimmpbjfciihkgkoaplkb', 'PUP- Mindspark?') ,'cnllofdfhghjaomdikdlhmkoknfhjdga', 'PUP- Mindspark?') ,'klkbeieajgjehlcnoiflockodlbibaep', 'PUP- Search Encrypt') ,'heiihkmbceipememjjpggkaenngfkkjp', 'PUP- Search Encrypt') ,'fkgedicakildehepikeopegehmojomfk', 'PUP- Free Maps') ,'okkolgldfknecfjnhhglfopimelbaceh', 'PUP- BrowserAir') ,'kgfgkmglngfjihijajckoidgoglmajan', 'PUP- MapBeast by SaferBrowser') ,'panlddknfikdcilhdheajcdlcjndnpcp', 'PUP- ZipFileTab Browser Hijacker') ,'agijeemohccmknhbgdjokbeekmijlbee', 'PUP- search.hwatchtvnow.co') ,'ahigpjeolkfgjdaeodlmaceggigbpeoh', 'PUP - FB Unfriend Finder') ,'aaffhmecfaelkngcbnfdkcckmillnoki', 'PUP- Conduit?') ,'bepbmhgboaologfdajaanbcjmnhjmhfn', 'PUP- bepbmhgboa') ,'apgmlmclgkeaciocpcinelmgaenpobae', 'PUP- Searchpluspro') ,'fhkmacopackahlbnpcfijgphgoimpggb', 'PUP- MapsFrontier') AS Extensions from MACHINE INNER JOIN MACHINE_CUSTOM_INVENTORY CI ON MACHINE.ID = CI.ID INNER JOIN SOFTWARE ON SOFTWARE.ID = CI.SOFTWARE_ID WHERE SOFTWARE.DISPLAY_NAME LIKE 'Google Chrome Extensions' ORDER BY MACHINE.LAST_INVENTORY DESC
Creating KACE Report for Google Chrome Extensions
Navigate to Reporting > Reports > Select the Drop down menu and select New (SQL)
Provide a title and paste the SQL code provided earlier:
Save it.
Next, run the Report
You should see a report of your endpoints along with the extensions:
As you can see, it’ll be easy to identify unknown extensions.
Although it’s nice that we have visibility over our endpoints, this doesn’t stop the malicious extensions installed from running. The next step is to eradicate those extensions.
Removing unwanted Google Chrome Extensions
Now that we have a good idea of the known good extensions, we can remove all unwanted extensions. To accomplish this, I wrote a Powershell Script and also briefly modified a well known extension written by “bellows” at Spiceworks that removes Google Chrome extensions.
The first Powershell script “GoogleChromeExtensions.ps1” will query the Extensions directory and will exclude the “known expected” extensions and will return only the extensions not found under this list. The list of “unknown or unwanted” extensions will then be passed on to the “Get-ChromeExtensions.ps1” Powershell Script that will start removing each one at a time. This script will remove the extension folder contents for this path, and will also remove registry entries under HKCU\SOFTWARE for those extensions.
$list = Get-ChildItem "C:\Users\pdelgado\AppData\Local\Google\Chrome\User Data\Default\Extensions" -Name ` -Exclude ("aapocclcgogkmnckokdopfmhonfmgoek","aohghmighlieiainnegkcijnfilokake","ghbmnnjooekpmoecnnnilnnbdlolhkhi", "apdfllckaahabafndbhieahigkjlhalf","blpcfgokakmgnkcojhhkbfbldkacnbeo","felcaaldnbdncclmgdcncolpebgiejap","nmmhkkegccagdldgiimedpiccmgmieda", "pjkljhegncpnkpknbcohdijeoejaedia","pkedcjkdefgpdelpbcmbmeomcjbeemfm","coobgpohoikkiipiblmjeljniedjpjpf","aapbdbdomjkkjkaonfhkkikfgjllcleb", "hdokiejnpimakedhajhdlcegeplioahd", #Password Managers "fdjamakpfbbddfjaooikfcpapjohcfmg","hdokiejnpimakedhajhdlcegeplioahd","lpdfbkehegfmedglgemnhbnpmfmioggj") # Loops through $list items and removes each chrome extension foreach ($item in $list) { .\Get-ChromeExtensions.ps1 -ExtensionId $item -Remove }
Here’s the “Get-ChromeExtensions.ps1” script. The only thing I modified was the path to the extensions as Dell KACE will run as SYSTEM and the script won’t work if you don’t deploy it this way. (Note: You may also run scripts as the user context, but I didn’t test this route).
The Modified line is this one: $extension_folders = Get-ChildItem -Path “C:\Users\pdelgado\AppData\Local\Google\Chrome\User Data\Default\Extensions”
param([String]$OutputFolder=$null,[String]$ExtensionId=$null,[Switch]$Remove, [Switch]$WhatIf) ##: Globals $retval = $false ##: If OutputFolder param wasn't given, output the audit file to the desktop if(!$OutputFolder -or !(Test-Path -Path $OutputFolder)) { $auditfolderpath = "$($env:USERPROFILE)\Desktop" } else { $auditfolderpath = $OutputFolder } ##: This is the file we will write the extension list to $auditfilepath = "$($auditfolderpath)\$($env:USERNAME)-$($env:COMPUTERNAME).txt" if( !(Test-Path -Path $auditfilepath) ) { echo "Creating: [$auditfilepath]" if(!($WhatIf)) { echo "" | Out-File -FilePath $auditfilepath } } if(!($WhatIf)) { Clear-Content $auditfilepath } ##: The extensions folder is in local appdata $extension_folders = Get-ChildItem -Path "C:\Users\pdelgado\AppData\Local\Google\Chrome\User Data\Default\Extensions" ##: Loop through each extension folder foreach ($extension_folder in $extension_folders ) { ##: Get the version specific folder within this extension folder $version_folders = Get-ChildItem -Path "$($extension_folder.FullName)" ##: Loop through the version folders found foreach ($version_folder in $version_folders) { ##: The extension folder name is the app id in the Chrome web store $appid = $extension_folder.BaseName ##: First check the manifest for a name $name = "" if( (Test-Path -Path "$($version_folder.FullName)\manifest.json") ) { try { $json = Get-Content -Raw -Path "$($version_folder.FullName)\manifest.json" | ConvertFrom-Json $name = $json.name } catch { #$_ $name = "" } } ##: If we find _MSG_ in the manifest it's probably an app if( $name -like "*MSG*" ) { ##: Sometimes the folder is en if( Test-Path -Path "$($version_folder.FullName)\_locales\en\messages.json" ) { try { $json = Get-Content -Raw -Path "$($version_folder.FullName)\_locales\en\messages.json" | ConvertFrom-Json $name = $json.appName.message ##: Try a lot of different ways to get the name if(!$name) { $name = $json.extName.message } if(!$name) { $name = $json.extensionName.message } if(!$name) { $name = $json.app_name.message } if(!$name) { $name = $json.application_title.message } } catch { #$_ $name = "" } } ##: Sometimes the folder is en_US if( Test-Path -Path "$($version_folder.FullName)\_locales\en_US\messages.json" ) { try { $json = Get-Content -Raw -Path "$($version_folder.FullName)\_locales\en_US\messages.json" | ConvertFrom-Json $name = $json.appName.message ##: Try a lot of different ways to get the name if(!$name) { $name = $json.extName.message } if(!$name) { $name = $json.extensionName.message } if(!$name) { $name = $json.app_name.message } if(!$name) { $name = $json.application_title.message } } catch { #$_ $name = "" } } } ##: If we can't get a name from the extension use the app id instead if( !$name ) { $name = "[$($appid)]" } ##: App id given on command line and this one matched it if( $ExtensionId -and ($appid -eq $ExtensionId) ) { if( $Remove ) { echo "Removing item: [$appid] at path: [$($extension_folder.FullName)]" if(!($WhatIf)) { ##: Remove the extension folder if (Test-Path -Path $extension_folder.FullName) { Remove-Item -Path $extension_folder.FullName -Recurse -Force } ##: Remove the extension registry key if (Test-Path -Path "HKCU:\SOFTWARE\Google\Chrome\PreferenceMACs\Default\extensions.settings") { if( Get-ItemProperty -Name "$appid" -Path "HKCU:\SOFTWARE\Google\Chrome\PreferenceMACs\Default\extensions.settings" ) { Remove-ItemProperty -Name "$appid" -Path "HKCU:\SOFTWARE\Google\Chrome\PreferenceMACs\Default\extensions.settings" } } } } else { ##: Dump to a file echo "Appending: [$name ($($version_folder)) - $appid] to audit file: [$auditfilepath]" if(!($WhatIf)) { echo "$name ($($version_folder)) - $appid" | Out-File -Append $auditfilepath } ##: Exit with a TRUE value if the given extension id was found $retval = $true } ##: App id given on command line and this did NOT match it } elseif( $ExtensionId -and ($appid -ne $ExtensionId) ) { ##: NOP #echo "Skipping: [$appid] output" ##: App id not given on command line } else { ##: Dump to audit file echo "Appending: [$name ($($version_folder)) - $appid] to audit file: [$auditfilepath]" if(!($WhatIf)) { echo "$name ($($version_folder)) - $appid" | Out-File -Append $auditfilepath } } } } exit($retval)
Deploying the script via KACE
Navigate to Scripts > Choose Action > New
Provide a name for the script and make sure you “enable” it.
- Select the Operating system to “Microsoft Windows”.
- Windows run As “Local System”
- Check box for “Allow run without a logged-in user”
- Upload dependencies (GoogleChromeExtensions.ps1) & (Get-ChromeExtensions.ps1)
Under the Tasks section:
On Success : Run a batch file
Provide a script name and paste the following:
powershell.exe powershell.exe -ExecutionPolicy UnRestricted -File .\GoogleChromeExtensions.ps1
Save changes, and deploy!
For non-KACE users
You can run these Powershell scripts without specifying a user, and just grabbing the current logged in user via the %LOCALAPPDATA% variable. Ensure you modify the script with other expected extensions or just remove them all!
Here’s the scripts:
$list = Get-ChildItem -Path "$($env:LOCALAPPDATA)\Google\Chrome\User Data\Default\Extensions" -Name ` -Exclude ("aapocclcgogkmnckokdopfmhonfmgoek","aohghmighlieiainnegkcijnfilokake","ghbmnnjooekpmoecnnnilnnbdlolhkhi", "apdfllckaahabafndbhieahigkjlhalf","blpcfgokakmgnkcojhhkbfbldkacnbeo","felcaaldnbdncclmgdcncolpebgiejap","nmmhkkegccagdldgiimedpiccmgmieda", "pjkljhegncpnkpknbcohdijeoejaedia","pkedcjkdefgpdelpbcmbmeomcjbeemfm","coobgpohoikkiipiblmjeljniedjpjpf","aapbdbdomjkkjkaonfhkkikfgjllcleb", "hdokiejnpimakedhajhdlcegeplioahd", #Password Managers "fdjamakpfbbddfjaooikfcpapjohcfmg","hdokiejnpimakedhajhdlcegeplioahd","lpdfbkehegfmedglgemnhbnpmfmioggj") # Loops through $list items and removes each chrome extension foreach ($item in $list) { .\Get-ChromeExtensions.ps1 -ExtensionId $item -Remove }
and you may use the original “Get-ChromeExtensions.ps1” script along with the one I created which should accomplish the same thing. Easy as 1,2,3.
Conclusion
As mentioned earlier, the scripts deployed will remove unwanted extensions from the provided file path and registry keys; however the extension itself WILL NOT be removed from the Google Chrome browser. When you re-launch the web browser, the folders will re-appear; however, they wont’ have any content and the extension will not be functional. If you browse to the extensions section of Chrome, you will see the extensions with a status of “This extension may have been corrupted” and thus will not be functional as seen in the image below:
Although we’d like to have the extension completely removed from the user’s visibility, this is the next best thing. To my knowledge there isn’t a way to remove the extensions besides having the user do it manually (correct me if I’m wrong, as there might be a better way). The user may always re-install the extensions; however, you can always have an ongoing-job to continue deleting them.
Thanks for reading! Constructive feedback is always appreciated!
[…] In addition, I wrote another article on Identifying and removing unwanted Google Chrome extensions through powershell which may be accessed here. […]