New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Querying safari_extensions
returns nothing since macOS 10.15
#6498
Comments
Apple changed the way that Safari handles extensions in macOS Mojave deprecating their old legacy extension platform and instead requiring all extensions to go through the App Store and be registered as Apps. (https://9to5mac.com/2018/06/09/safari-12-extensions-more/) We can use predictable installation path patterns to approximate the previous functionality by using a query like so: WITH extensions_flat AS (SELECT * FROM plist WHERE path LIKE '/Applications/%.app/Contents/PlugIns/%SafariAppExtension.appex/Contents/Info.plist')
SELECT
SPLIT(path, '/', 1) AS extension_parent_app,
MAX(CASE WHEN key = 'CFBundleIdentifier' THEN value END) AS bundle_identifier,
MAX(CASE WHEN key = 'CFBundleDisplayName' THEN value END) AS display_name,
MAX(CASE WHEN key = 'NSHumanReadableDescription' THEN value END) AS description,
MAX(CASE WHEN key = 'CFBundleShortVersionString' THEN value END) AS bundle_short_version,
MAX(CASE WHEN key = 'CFBundleVersion' THEN value END) AS bundle_version,
MAX(CASE WHEN key = 'NSHumanReadableCopyright' THEN value END) AS copyright
FROM extensions_flat
GROUP BY path;
extension_parent_app = 1Password 7.app
bundle_identifier = com.agilebits.onepassword7.1PasswordSafariAppExtension
display_name = 1Password
description = Easy Access to Your Logins, Credit Cards and Identities.
bundle_short_version = 7.5
bundle_version = 70500002
copyright = Copyright © 2018 AgileBits Inc. All rights reserved.
extension_parent_app = DuckDuckGo Privacy Essentials.app
bundle_identifier = com.duckduckgo.macos.PrivacyEssentials.SafariAppExtension
display_name = Privacy Dashboard
description = DuckDuckGo Privacy Dashboard - track who we caught trying to track you.
bundle_short_version = 1.4.1
bundle_version = 12
copyright = Copyright © 2019 Duck Duck Go, Inc. All rights reserved. Additional research should be done to investigate whether additional paths should be considered (eg. |
Slight modification to the above query: WITH extensions_flat AS (SELECT * FROM plist WHERE path LIKE '/Applications/%.app/Contents/PlugIns/%.appex/Contents/Info.plist')
SELECT
SPLIT(path, '/', 1) AS extension_parent_app,
MAX(CASE WHEN key = 'CFBundleIdentifier' THEN value END) AS bundle_identifier,
MAX(CASE WHEN key = 'CFBundleDisplayName' THEN value END) AS display_name,
MAX(CASE WHEN key = 'NSHumanReadableDescription' THEN value END) AS description,
MAX(CASE WHEN key = 'CFBundleShortVersionString' THEN value END) AS bundle_short_version,
MAX(CASE WHEN key = 'CFBundleVersion' THEN value END) AS bundle_version,
MAX(CASE WHEN key = 'NSHumanReadableCopyright' THEN value END) AS copyright
FROM extensions_flat
GROUP BY path; |
Ah that is better! Thanks @theopolis! |
Teddy's above command worked great but it feels like a workaround to use in the short term. Longer term, should the virtual table code detect its environment and present the extensions correctly by parsing the plists in their new locations? |
Yes and no, I don’t think this current solution is accurate. It’s possible to have matches to this query, which are not recognized by Safari as extensions. And I am not sure if the inverse is true. |
Amended query which I think is closer to the end goal that we will want. This plist just popped up for me today when I was looking at this issue again, I think it is a recent addition: Of particular noteworthiness is the inclusion of the One issue with the query below is I am flattening using MAX for the keys The full query with results:WITH
app_extensions_flat AS (
SELECT * FROM plist
WHERE path LIKE '/Applications/%.app/Contents/PlugIns/%.appex/Contents/Info.plist'),
app_extension_pivot AS (
SELECT
SPLIT(path, '/', 1) AS extension_parent_app,
MAX(CASE WHEN key = 'CFBundleIdentifier' THEN value END) AS bundle_identifier,
MAX(CASE WHEN key = 'CFBundleDisplayName' THEN value END) AS display_name,
MAX(CASE WHEN key = 'NSHumanReadableDescription' THEN value END) AS description,
MAX(CASE WHEN key = 'CFBundleShortVersionString' THEN value END) AS bundle_short_version,
MAX(CASE WHEN key = 'CFBundleVersion' THEN value END) AS bundle_version,
MAX(CASE WHEN key = 'NSHumanReadableCopyright' THEN value END) AS copyright
FROM app_extensions_flat
GROUP BY path),
human_accounts AS (
SELECT username, uid, directory FROM users WHERE SUBSTR(uuid,0,8) != 'FFFFEEE'),
safari_raw AS (
SELECT
username, uid,
MAX(CASE WHEN subkey = 'Enabled' THEN value END) AS enabled,
MAX(CASE WHEN subkey LIKE '%Level' THEN value END) AS level,
MAX(CASE WHEN subkey LIKE '%Has Injected Content' THEN value END) AS has_injected_content,
REGEX_SPLIT(key,' \(', 0) AS bundle_identifier,
REGEX_MATCH(key,'\((.*?)\)', 1) AS extension_id
FROM plist JOIN human_accounts ha ON directory = '/Users/' || SPLIT(path,'/',1)
WHERE path LIKE '/Users/%/Library/Containers/com.apple.Safari/Data/Library/Safari/AppExtensions/Extensions.plist'
GROUP BY key, path),
-- Remove nulls
safari_extensions_plist AS (
SELECT * FROM safari_raw WHERE enabled NOT NULL)
SELECT * FROM safari_extensions_plist LEFT JOIN app_extension_pivot USING(bundle_identifier);
username = fritz-imac
uid = 502
enabled = 1
level = All
has_injected_content = 1
bundle_identifier = archive.org.waybackmachine.mac.extension
extension_id = ZSFX78H3ZT
extension_parent_app = Wayback Machine.app
display_name = Wayback Machine
description = Archive and explore web pages over time!
bundle_short_version = 1.4
bundle_version = 19
copyright =
username = fritz-imac
uid = 502
enabled = 1
level = All
has_injected_content = 1
bundle_identifier = com.agilebits.onepassword7.1PasswordSafariAppExtension
extension_id = 2BUA8C4S2C
extension_parent_app = 1Password 7.app
display_name = 1Password
description = Easy Access to Your Logins, Credit Cards and Identities.
bundle_short_version = 7.7
bundle_version = 70700016
copyright = Copyright © 2020 AgileBits Inc. All rights reserved.
username = fritz-imac
uid = 502
enabled = 1
level = All
has_injected_content = 1
bundle_identifier = com.duckduckgo.macos.PrivacyEssentials.SafariAppExtension
extension_id = HKE973VLUW
extension_parent_app = DuckDuckGo Privacy Essentials.app
display_name = Privacy Dashboard
description = DuckDuckGo Privacy Dashboard - track who we caught trying to track you.
bundle_short_version = 1.4.3
bundle_version = 14
copyright = Copyright © 2019 Duck Duck Go, Inc. All rights reserved. |
Confirmed today that:
|
Going through this now, its working for me in macOS Monterey 12.5.1, but I'm also discovering that not all extensions are listed in that file. there is another file |
Ok maybe i didnt give myself enough credit. This grabs the basics from both files. WITH
app_extensions_flat AS (
SELECT * FROM plist
WHERE path LIKE '/Applications/%.app/Contents/PlugIns/%.appex/Contents/Info.plist'),
app_extension_pivot AS (
SELECT
SPLIT(path, '/', 1) AS extension_parent_app,
MAX(CASE WHEN key = 'CFBundleIdentifier' THEN value END) AS bundle_identifier,
MAX(CASE WHEN key = 'CFBundleDisplayName' THEN value END) AS display_name,
MAX(CASE WHEN key = 'NSHumanReadableDescription' THEN value END) AS description,
MAX(CASE WHEN key = 'CFBundleShortVersionString' THEN value END) AS bundle_short_version,
MAX(CASE WHEN key = 'CFBundleVersion' THEN value END) AS bundle_version,
MAX(CASE WHEN key = 'NSHumanReadableCopyright' THEN value END) AS copyright
FROM app_extensions_flat
GROUP BY path),
human_accounts AS (
SELECT username, uid, directory FROM users WHERE SUBSTR(uuid,0,8) != 'FFFFEEE'),
safari_raw_app AS (
SELECT
username, uid,
MAX(CASE WHEN subkey = 'Enabled' THEN value END) AS enabled,
MAX(CASE WHEN subkey LIKE '%Level' THEN value END) AS level,
MAX(CASE WHEN subkey LIKE '%Has Injected Content' THEN value END) AS has_injected_content,
REGEX_SPLIT(key,' \(', 0) AS bundle_identifier,
REGEX_MATCH(key,'\((.*?)\)', 1) AS extension_id
FROM plist JOIN human_accounts ha ON directory = '/Users/' || SPLIT(path,'/',1)
WHERE path LIKE '/Users/%/Library/Containers/com.apple.Safari/Data/Library/Safari/AppExtensions/Extensions.plist'
GROUP BY key, path),
safari_raw_web AS (
SELECT
username, uid,
MAX(CASE WHEN subkey = 'Enabled' THEN value END) AS enabled,
REGEX_SPLIT(key,' \(', 0) AS bundle_identifier,
REGEX_MATCH(key,'\((.*?)\)', 1) AS extension_id
FROM plist JOIN human_accounts ha ON directory = '/Users/' || SPLIT(path,'/',1)
WHERE path LIKE '/Users/%/Library/Containers/com.apple.Safari/Data/Library/Safari/WebExtensions/Extensions.plist'
GROUP BY key, path),
safari_extensions_plist AS (
SELECT username, enabled, bundle_identifier, extension_id FROM safari_raw_app UNION SELECT username, enabled, bundle_identifier, extension_id FROM safari_raw_web
)
SELECT * FROM safari_extensions_plist LEFT JOIN app_extension_pivot USING(bundle_identifier);
|
safari_extensions
returns nothing since macOS 10.15
Bug report
What operating system and version are you using?
What version of osquery are you using?
What steps did you take to reproduce the issue?
osqueryd -S
) and run:SELECT e.name, e.identifier, e.version, e.description, e.path, "safari" as browser FROM users u JOIN safari_extensions e ON e.uid = u.uid;
What did you expect to see?
LastPass extension listed.
What did you see instead?
Nothing is printed.
The text was updated successfully, but these errors were encountered: