mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 09:58:54 +00:00
[#787] Add chrome, firefox, and safari related tables
This commit is contained in:
parent
4916392aa8
commit
e281e6a214
@ -10,6 +10,9 @@ if(APPLE)
|
|||||||
)
|
)
|
||||||
|
|
||||||
ADD_OSQUERY_LIBRARY(FALSE osquery_tables_darwin
|
ADD_OSQUERY_LIBRARY(FALSE osquery_tables_darwin
|
||||||
|
applications/darwin/browser_chrome.cpp
|
||||||
|
applications/darwin/browser_firefox.cpp
|
||||||
|
applications/darwin/browser_safari.cpp
|
||||||
events/darwin/passwd_changes.cpp
|
events/darwin/passwd_changes.cpp
|
||||||
events/darwin/file_changes.cpp
|
events/darwin/file_changes.cpp
|
||||||
events/darwin/hardware_events.cpp
|
events/darwin/hardware_events.cpp
|
||||||
|
112
osquery/tables/applications/darwin/browser_chrome.cpp
Normal file
112
osquery/tables/applications/darwin/browser_chrome.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
|
|
||||||
|
#include <osquery/filesystem.h>
|
||||||
|
#include <osquery/logger.h>
|
||||||
|
#include <osquery/tables.h>
|
||||||
|
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
namespace pt = boost::property_tree;
|
||||||
|
|
||||||
|
namespace osquery {
|
||||||
|
namespace tables {
|
||||||
|
|
||||||
|
/// Each home directory will include custom extensions.
|
||||||
|
#define kChromePath "/Library/Application Support/Google/Chrome/Default/"
|
||||||
|
#define kChromeExtensionsPath "Extensions/"
|
||||||
|
#define kChromeManifestFile "/manifest.json"
|
||||||
|
|
||||||
|
const std::map<std::string, std::string> kChromeExtensionKeys = {
|
||||||
|
{"version", "version"},
|
||||||
|
{"name", "name"},
|
||||||
|
{"description", "description"},
|
||||||
|
{"default_locale", "locale"},
|
||||||
|
{"update_url", "update_url"},
|
||||||
|
{"author", "author"},
|
||||||
|
{"background.persistent", "persistent"},
|
||||||
|
};
|
||||||
|
|
||||||
|
void genChromeExtension(const std::string& path, QueryData& results) {
|
||||||
|
std::string json_data;
|
||||||
|
if (!readFile(path + kChromeManifestFile, json_data).ok()) {
|
||||||
|
VLOG(1) << "Could not read file: " << path + kChromeManifestFile;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the extensions data into a JSON blob, then property tree.
|
||||||
|
pt::ptree tree;
|
||||||
|
std::stringstream json_stream;
|
||||||
|
json_stream << json_data;
|
||||||
|
try {
|
||||||
|
pt::read_json(json_stream, tree);
|
||||||
|
} catch (const pt::json_parser::json_parser_error& e) {
|
||||||
|
VLOG(1) << "Could not parse JSON from: " << path + kChromeManifestFile;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Row r;
|
||||||
|
// Most of the keys are in the top-level JSON dictionary.
|
||||||
|
for (const auto& it : kChromeExtensionKeys) {
|
||||||
|
try {
|
||||||
|
r[it.second] = tree.get<std::string>(it.first);
|
||||||
|
} catch (const pt::ptree_error& e) {
|
||||||
|
r[it.second] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert JSON bool-types to an integer.
|
||||||
|
if (r[it.second] == "true") {
|
||||||
|
r[it.second] = INTEGER(1);
|
||||||
|
} else if (r[it.second] == "false") {
|
||||||
|
r[it.second] = INTEGER(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the default persistence setting to false
|
||||||
|
if (r.at("persistent") == "") {
|
||||||
|
r["persistent"] = INTEGER(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
r["identifier"] = fs::path(path).parent_path().leaf().string();
|
||||||
|
r["path"] = path;
|
||||||
|
results.push_back(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryData genChromeExtensions(QueryContext& context) {
|
||||||
|
QueryData results;
|
||||||
|
|
||||||
|
auto homes = osquery::getHomeDirectories();
|
||||||
|
for (const auto& home : homes) {
|
||||||
|
// For each user, enumerate all of their Chrome profiles.
|
||||||
|
std::vector<std::string> extensions;
|
||||||
|
fs::path extension_path = home / (kChromePath kChromeExtensionsPath);
|
||||||
|
if (!listDirectoriesInDirectory(extension_path, extensions).ok()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate an addons list from their extensions JSON.
|
||||||
|
for (const auto& extension : extensions) {
|
||||||
|
std::vector<std::string> versions;
|
||||||
|
if (!listDirectoriesInDirectory(extension, versions).ok()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extensions use /<ID>/<VERSION>/manifest.json.
|
||||||
|
for (const auto& version : versions) {
|
||||||
|
genChromeExtension(version, results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
118
osquery/tables/applications/darwin/browser_firefox.cpp
Normal file
118
osquery/tables/applications/darwin/browser_firefox.cpp
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
|
|
||||||
|
#include <osquery/filesystem.h>
|
||||||
|
#include <osquery/logger.h>
|
||||||
|
#include <osquery/tables.h>
|
||||||
|
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
namespace pt = boost::property_tree;
|
||||||
|
|
||||||
|
namespace osquery {
|
||||||
|
namespace tables {
|
||||||
|
|
||||||
|
/// Each home directory will include custom extensions.
|
||||||
|
#define kFirefoxPath "/Library/Application Support/Firefox/Profiles/"
|
||||||
|
#define kFirefoxExtensionsFile "/extensions.json"
|
||||||
|
|
||||||
|
/// Not parsed, but may be helpful later.
|
||||||
|
#define kFirefoxAddonsFile "/addons.json"
|
||||||
|
#define kFirefoxWebappsFile "/webapps/webapps.json"
|
||||||
|
|
||||||
|
const std::map<std::string, std::string> kFirefoxAddonKeys = {
|
||||||
|
{"defaultLocale.name", "name"},
|
||||||
|
{"id", "identifier"},
|
||||||
|
{"type", "type"},
|
||||||
|
{"version", "version"},
|
||||||
|
{"defaultLocale.creator", "creator"},
|
||||||
|
{"defaultLocale.description", "description"},
|
||||||
|
{"sourceURI", "source_url"},
|
||||||
|
{"visible", "visible"},
|
||||||
|
{"active", "active"},
|
||||||
|
{"applyBackgroundUpdates", "autoupdate"},
|
||||||
|
{"hasBinaryComponents", "native"},
|
||||||
|
{"location", "location"},
|
||||||
|
{"descriptor", "path"},
|
||||||
|
};
|
||||||
|
|
||||||
|
void genFirefoxAddonsFromExtensions(const std::string& path,
|
||||||
|
QueryData& results) {
|
||||||
|
std::string json_data;
|
||||||
|
if (!readFile(path + kFirefoxExtensionsFile, json_data).ok()) {
|
||||||
|
VLOG(1) << "Could not read file: " << path + kFirefoxExtensionsFile;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the extensions data into a JSON blob, then property tree.
|
||||||
|
pt::ptree tree;
|
||||||
|
std::stringstream json_stream;
|
||||||
|
json_stream << json_data;
|
||||||
|
try {
|
||||||
|
pt::read_json(json_stream, tree);
|
||||||
|
} catch (const pt::json_parser::json_parser_error& e) {
|
||||||
|
VLOG(1) << "Could not parse JSON from: " << path + kFirefoxExtensionsFile;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& addon : tree.get_child("addons")) {
|
||||||
|
Row r;
|
||||||
|
// Most of the keys are in the top-level JSON dictionary.
|
||||||
|
for (const auto& it : kFirefoxAddonKeys) {
|
||||||
|
try {
|
||||||
|
r[it.second] = addon.second.get<std::string>(it.first);
|
||||||
|
} catch (const pt::ptree_error& e) {
|
||||||
|
r[it.second] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert bool-types to an integer.
|
||||||
|
if (r[it.second] == "true" || r[it.second] == "YES" ||
|
||||||
|
r[it.first] == "Yes") {
|
||||||
|
r[it.second] = INTEGER(1);
|
||||||
|
} else if (r[it.second] == "false" || r[it.second] == "NO" ||
|
||||||
|
r[it.second] == "No") {
|
||||||
|
r[it.second] = INTEGER(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are several ways to disabled the addon, check each.
|
||||||
|
if (addon.second.get<std::string>("softDisable", "false") == "true" ||
|
||||||
|
addon.second.get<std::string>("appDisabled", "false") == "true" ||
|
||||||
|
addon.second.get<std::string>("userDisabled", "false") == "true") {
|
||||||
|
r["disabled"] = INTEGER(1);
|
||||||
|
} else {
|
||||||
|
r["disabled"] = INTEGER(0);
|
||||||
|
}
|
||||||
|
results.push_back(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryData genFirefoxAddons(QueryContext& context) {
|
||||||
|
QueryData results;
|
||||||
|
|
||||||
|
auto homes = osquery::getHomeDirectories();
|
||||||
|
for (const auto& home : homes) {
|
||||||
|
// For each user, enumerate all of their Firefox profiles.
|
||||||
|
std::vector<std::string> profiles;
|
||||||
|
if (!listDirectoriesInDirectory(home / kFirefoxPath, profiles).ok()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate an addons list from their extensions JSON.
|
||||||
|
for (const auto& profile : profiles) {
|
||||||
|
genFirefoxAddonsFromExtensions(profile, results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
125
osquery/tables/applications/darwin/browser_safari.cpp
Normal file
125
osquery/tables/applications/darwin/browser_safari.cpp
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <osquery/filesystem.h>
|
||||||
|
#include <osquery/tables.h>
|
||||||
|
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
namespace pt = boost::property_tree;
|
||||||
|
|
||||||
|
namespace osquery {
|
||||||
|
namespace tables {
|
||||||
|
|
||||||
|
/// Each home directory will include custom extensions.
|
||||||
|
#define kSafariExtensionsPath "/Library/Safari/Extensions/"
|
||||||
|
|
||||||
|
#define kSafariPluginsPath "/Library/Internet Plug-Ins/"
|
||||||
|
|
||||||
|
/// Safari extensions will not load unless they have the expected pattern.
|
||||||
|
#define kSafariExtensionsPattern "%.safariextz"
|
||||||
|
|
||||||
|
const std::map<std::string, std::string> kSafariPluginKeys = {
|
||||||
|
{"WebPluginName", "name"},
|
||||||
|
{"CFBundleIdentifier", "identifier"},
|
||||||
|
{"CFBundleShortVersionString", "version"},
|
||||||
|
{"DTPlatformBuild", "sdk"},
|
||||||
|
{"WebPluginDescription", "description"},
|
||||||
|
{"CFBundleDevelopmentRegion", "development_region"},
|
||||||
|
{"LSRequiresNativeExecution", "native"},
|
||||||
|
};
|
||||||
|
|
||||||
|
void genSafariPlugin(const std::string& path, QueryData& results) {
|
||||||
|
Row r;
|
||||||
|
pt::ptree tree;
|
||||||
|
if (osquery::parsePlist(path + "/Contents/Info.plist", tree).ok()) {
|
||||||
|
// Plugin did not include an Info.plist, or it was invalid
|
||||||
|
for (const auto& it : kSafariPluginKeys) {
|
||||||
|
try {
|
||||||
|
r[it.second] = tree.get<std::string>(it.first);
|
||||||
|
} catch (const pt::ptree_error& e) {
|
||||||
|
r[it.second] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert Plist bool-types to an integer.
|
||||||
|
if (r[it.second] == "true" || r[it.second] == "YES" ||
|
||||||
|
r[it.first] == "Yes") {
|
||||||
|
r[it.second] = INTEGER(1);
|
||||||
|
} else if (r[it.second] == "false" || r[it.second] == "NO" ||
|
||||||
|
r[it.second] == "No") {
|
||||||
|
r[it.second] = INTEGER(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r.at("is_native").size() == 0) {
|
||||||
|
// The default case for native execution is false.
|
||||||
|
r["is_native"] = "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
r["path"] = path;
|
||||||
|
results.push_back(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryData genSafariPlugins(QueryContext& context) {
|
||||||
|
QueryData results;
|
||||||
|
|
||||||
|
std::vector<std::string> bundles;
|
||||||
|
if (listDirectoriesInDirectory(kSafariPluginsPath, bundles).ok()) {
|
||||||
|
for (const auto& dir : bundles) {
|
||||||
|
genSafariPlugin(dir, results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto homes = osquery::getHomeDirectories();
|
||||||
|
for (const auto& home : homes) {
|
||||||
|
bundles.clear();
|
||||||
|
if (listDirectoriesInDirectory(home / kSafariPluginsPath, bundles).ok()) {
|
||||||
|
for (const auto& dir : bundles) {
|
||||||
|
genSafariPlugin(dir, results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
void genSafariExtension(const std::string& path, QueryData& results) {
|
||||||
|
Row r;
|
||||||
|
r["name"] = fs::path(path).stem().string();
|
||||||
|
r["path"] = path;
|
||||||
|
results.push_back(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryData genSafariExtensions(QueryContext& context) {
|
||||||
|
QueryData results;
|
||||||
|
|
||||||
|
auto homes = osquery::getHomeDirectories();
|
||||||
|
for (const auto& home : homes) {
|
||||||
|
auto dir = home / kSafariExtensionsPath;
|
||||||
|
// Check that an extensions directory exists.
|
||||||
|
if (!pathExists(dir).ok()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glob the extension files.
|
||||||
|
std::vector<std::string> paths;
|
||||||
|
if (!resolveFilePattern(dir / kSafariExtensionsPattern, paths).ok()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& extension_path : paths) {
|
||||||
|
genSafariExtension(extension_path, results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
osquery/tables/specs/darwin/chrome_extensions.table
Normal file
15
osquery/tables/specs/darwin/chrome_extensions.table
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
table_name("chrome_extensions")
|
||||||
|
description("Chrome browser extensions.")
|
||||||
|
schema([
|
||||||
|
Column("name", TEXT, "Extension display name"),
|
||||||
|
Column("identifier", TEXT, "Extension identifier"),
|
||||||
|
Column("version", TEXT, "Extension-supplied version"),
|
||||||
|
Column("description", TEXT, "Extension-optional description"),
|
||||||
|
Column("locale", TEXT, "Default locale supported by extension"),
|
||||||
|
Column("update_url", TEXT, "Extension-supplied update URI"),
|
||||||
|
Column("author", TEXT, "Optional extension author"),
|
||||||
|
Column("persistent", INTEGER,
|
||||||
|
"1 if extension is persistent across all tabs else 0"),
|
||||||
|
Column("path", TEXT, "Path to extension folder"),
|
||||||
|
])
|
||||||
|
implementation("applications/browser_chrome@genChromeExtensions")
|
23
osquery/tables/specs/darwin/firefox_addons.table
Normal file
23
osquery/tables/specs/darwin/firefox_addons.table
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
table_name("firefox_addons")
|
||||||
|
description("Firefox browser extensions, webapps, and addons.")
|
||||||
|
schema([
|
||||||
|
Column("name", TEXT, "Addon display name"),
|
||||||
|
Column("identifier", TEXT, "Addon identifier"),
|
||||||
|
Column("creator", TEXT< "Addon-supported creator string"),
|
||||||
|
Column("type", TEXT, "Extension, addon, webapp"),
|
||||||
|
Column("version", TEXT, "Addon-supplied version string"),
|
||||||
|
Column("description", TEXT, "Addon-supplied description string"),
|
||||||
|
Column("source_url", TEXT, "URL that installed the addon"),
|
||||||
|
Column("visible", INTEGER, "1 if the addon is shown in browser else 0"),
|
||||||
|
Column("active", INTEGER, "1 if the addon is active else 0"),
|
||||||
|
Column("disabled", INTEGER,
|
||||||
|
"1 if the addon is application-disabled else 0"),
|
||||||
|
Column("autoupdate", INTEGER,
|
||||||
|
"1 if the addon applies background updates else 0"),
|
||||||
|
Column("native", INTEGER,
|
||||||
|
"1 if the addon includes binary components else 0"),
|
||||||
|
Column("location", TEXT, "Global, profile location"),
|
||||||
|
Column("path", TEXT, "Path to plugin bundle"),
|
||||||
|
|
||||||
|
])
|
||||||
|
implementation("applications/browser_firefox@genFirefoxAddons")
|
7
osquery/tables/specs/darwin/safari_extensions.table
Normal file
7
osquery/tables/specs/darwin/safari_extensions.table
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
table_name("safari_extensions")
|
||||||
|
description("Safari browser extension details for all users.")
|
||||||
|
schema([
|
||||||
|
Column("name", TEXT, "Default name of the node"),
|
||||||
|
Column("path", TEXT, "Path to extension xar"),
|
||||||
|
])
|
||||||
|
implementation("applications/browser_safari@genSafariExtensions")
|
13
osquery/tables/specs/darwin/safari_plugins.table
Normal file
13
osquery/tables/specs/darwin/safari_plugins.table
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
table_name("safari_plugins")
|
||||||
|
description("Safari browser plugin details for all users.")
|
||||||
|
schema([
|
||||||
|
Column("name", TEXT, "Plugin display name"),
|
||||||
|
Column("identifier", TEXT, "Plugin identifier"),
|
||||||
|
Column("version", TEXT, "Plugin short version"),
|
||||||
|
Column("sdk", TEXT, "Build SDK used to compile plugin"),
|
||||||
|
Column("description", TEXT, "Plugin description text"),
|
||||||
|
Column("development_region", TEXT, "Plugin language-localization"),
|
||||||
|
Column("native", INTEGER, "Plugin requires native execution"),
|
||||||
|
Column("path", TEXT, "Path to plugin bundle"),
|
||||||
|
])
|
||||||
|
implementation("applications/browser_safari@genSafariPlugins")
|
Loading…
Reference in New Issue
Block a user