[#787] Add chrome, firefox, and safari related tables

This commit is contained in:
Teddy Reed 2015-03-08 22:21:58 -07:00
parent 4916392aa8
commit e281e6a214
8 changed files with 416 additions and 0 deletions

View File

@ -10,6 +10,9 @@ if(APPLE)
)
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/file_changes.cpp
events/darwin/hardware_events.cpp

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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")

View 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")

View 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")

View 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")