Extending chrome browser extension table to Windows (#2619)

This commit is contained in:
Nick Anderson 2016-10-14 10:23:37 -07:00 committed by GitHub
parent 2048d17931
commit 208d2324d5
18 changed files with 217 additions and 118 deletions

View File

@ -24,8 +24,8 @@
namespace osquery {
std::string getUserId() {
return std::to_string(::getuid());
int platformGetUid() {
return ::getuid();
}
bool isLauncherProcessDead(PlatformProcess& launcher) {
@ -82,4 +82,8 @@ void setToBackgroundPriority() {
bool isUserAdmin() {
return getuid() == 0;
}
int platformGetPid() {
return (int)getpid();
}
}

View File

@ -208,8 +208,8 @@ class SecurityDescriptor {
};
#endif
/// Returns the current user's ID (UID on POSIX systems and SID for Windows)
std::string getUserId();
/// Returns the current user's ID (UID on POSIX systems and RID for Windows)
int platformGetUid();
/// Causes the current thread to sleep for a specified time in milliseconds.
void sleepFor(size_t msec);
@ -255,8 +255,11 @@ std::string platformModuleGetError();
*/
bool platformModuleClose(ModuleHandle module);
/// Checks to see if the launcher process is dead (only works for worker
/// processes).
/**
* @brief Checks to see if the launcher process is dead
*
* Note, this only works on worker processes.
*/
bool isLauncherProcessDead(PlatformProcess& launcher);
/// Waits for defunct processes to terminate.
@ -264,4 +267,12 @@ void cleanupDefunctProcesses();
/// Sets the current process to run with background scheduling priority.
void setToBackgroundPriority();
/**
* @brief Returns the current processes pid
*
* On Windows, returns the value of GetCurrentProcessId
* and on posix platforms returns getpid()
*/
int platformGetPid();
}

View File

@ -8,28 +8,36 @@
*
*/
#define _WIN32_DCOM
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
// clang-format off
#include <LM.h>
// clang-format on
#include <string>
#include <vector>
#include <boost/optional.hpp>
#include "osquery/core/process.h"
#include "osquery/core/windows/wmi.h"
#include "osquery/system.h"
namespace osquery {
std::string getUserId() {
int platformGetUid() {
DWORD nbytes = 0;
HANDLE token = INVALID_HANDLE_VALUE;
if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token)) {
return "";
return -1;
}
::GetTokenInformation(token, TokenUser, nullptr, 0, &nbytes);
if (nbytes == 0) {
::CloseHandle(token);
return "";
return -1;
}
std::vector<char> tu_buffer;
@ -43,19 +51,46 @@ std::string getUserId() {
&nbytes);
::CloseHandle(token);
if (status == 0) {
return "";
return -1;
}
LPSTR sid = nullptr;
tu = (PTOKEN_USER)tu_buffer.data();
if (!::ConvertSidToStringSidA(tu->User.Sid, &sid)) {
return "";
SID_NAME_USE eUse = SidTypeUnknown;
DWORD unameSize = 0;
DWORD domNameSize = 1;
// LookupAccountSid first gets the size of the username buff required.
LookupAccountSid(
nullptr, tu->User.Sid, nullptr, &unameSize, nullptr, &domNameSize, &eUse);
std::vector<char> uname(unameSize);
std::vector<char> domName(domNameSize);
auto ret = LookupAccountSid(nullptr,
tu->User.Sid,
uname.data(),
&unameSize,
domName.data(),
&domNameSize,
&eUse);
if (ret == 0) {
return -1;
}
std::string uid(sid);
::LocalFree(sid);
// USER_INFO_3 struct contains the RID (uid) of our user
DWORD userInfoLevel = 3;
LPUSER_INFO_3 userBuff = nullptr;
std::wstring wideUserName = stringToWstring(std::string(uname.data()));
ret = NetUserGetInfo(
nullptr, wideUserName.c_str(), userInfoLevel, (LPBYTE*)&userBuff);
return uid;
if (ret != NERR_Success) {
return -1;
}
::LocalFree(sid);
return userBuff->usri3_user_id;
}
bool isLauncherProcessDead(PlatformProcess& launcher) {
@ -147,4 +182,8 @@ bool isUserAdmin() {
}
return Elevation.TokenIsElevated ? true : false;
}
int platformGetPid() {
return (int)GetCurrentProcessId();
}
}

View File

@ -19,8 +19,8 @@
#include <osquery/filesystem.h>
#include <osquery/tables.h>
#include "osquery/tests/test_util.h"
#include "osquery/events/linux/inotify.h"
#include "osquery/tests/test_util.h"
namespace fs = boost::filesystem;
@ -233,7 +233,9 @@ TEST_F(INotifyTests, test_inotify_match_subscription) {
class TestINotifyEventSubscriber
: public EventSubscriber<INotifyEventPublisher> {
public:
TestINotifyEventSubscriber() { setName("TestINotifyEventSubscriber"); }
TestINotifyEventSubscriber() {
setName("TestINotifyEventSubscriber");
}
Status init() override {
callback_count_ = 0;
@ -283,7 +285,9 @@ class TestINotifyEventSubscriber
return actions_;
}
int count() { return callback_count_; }
int count() {
return callback_count_;
}
public:
std::atomic<int> callback_count_{0};
@ -450,7 +454,7 @@ TEST_F(INotifyTests, test_inotify_recursion) {
pub->configure();
// Expect only the directories to be monitored.
EXPECT_EQ(pub->path_descriptors_.size(), 6U);
EXPECT_EQ(pub->path_descriptors_.size(), 11U);
RemoveAll(pub);
// Use a directory structure that includes a loop.
@ -463,7 +467,7 @@ TEST_F(INotifyTests, test_inotify_recursion) {
pub->configure();
// Also expect canonicalized resolution (to prevent loops).
EXPECT_EQ(pub->path_descriptors_.size(), 6U);
EXPECT_EQ(pub->path_descriptors_.size(), 11U);
RemoveAll(pub);
// Remove mock directory structure.

View File

@ -239,7 +239,8 @@ TEST_F(FileOpsTests, test_glob) {
kFakeDirectory + "/door.txt",
kFakeDirectory + "/root.txt",
kFakeDirectory + "/root2.txt",
kFakeDirectory + "/roto.txt"};
kFakeDirectory + "/roto.txt",
kFakeDirectory + "/toplevel/"};
auto result = platformGlob(kFakeDirectory + "/*");
EXPECT_TRUE(globResultsMatch(result, expected));
}
@ -249,15 +250,21 @@ TEST_F(FileOpsTests, test_glob) {
kFakeDirectory + "/deep1/level1.txt",
kFakeDirectory + "/deep11/deep2/",
kFakeDirectory + "/deep11/level1.txt",
kFakeDirectory + "/deep11/not_bash"};
kFakeDirectory + "/deep11/not_bash",
kFakeDirectory + "/toplevel/secondlevel1/",
kFakeDirectory + "/toplevel/secondlevel2/",
kFakeDirectory + "/toplevel/secondlevel3/"};
auto result = platformGlob(kFakeDirectory + "/*/*");
EXPECT_TRUE(globResultsMatch(result, expected));
}
{
std::vector<fs::path> expected{kFakeDirectory + "/deep1/deep2/level2.txt",
kFakeDirectory + "/deep11/deep2/deep3/",
kFakeDirectory + "/deep11/deep2/level2.txt"};
std::vector<fs::path> expected{
kFakeDirectory + "/deep1/deep2/level2.txt",
kFakeDirectory + "/deep11/deep2/deep3/",
kFakeDirectory + "/deep11/deep2/level2.txt",
kFakeDirectory + "/toplevel/secondlevel3/thirdlevel1/",
};
auto result = platformGlob(kFakeDirectory + "/*/*/*");
EXPECT_TRUE(globResultsMatch(result, expected));
}
@ -285,16 +292,21 @@ TEST_F(FileOpsTests, test_glob) {
}
{
std::vector<fs::path> expected{kFakeDirectory + "/deep1/deep2/",
#ifdef WIN32
kFakeDirectory + "/deep1/level1.txt",
kFakeDirectory + "/deep11/deep2/",
#else
kFakeDirectory + "/deep11/deep2/",
kFakeDirectory + "/deep1/level1.txt",
#endif
kFakeDirectory + "/deep11/level1.txt",
kFakeDirectory + "/deep11/not_bash"};
std::vector<fs::path> expected;
if (isPlatform(PlatformType::TYPE_WINDOWS)) {
expected = {kFakeDirectory + "/deep1/deep2/",
kFakeDirectory + "/deep1/level1.txt",
kFakeDirectory + "/deep11/deep2/",
kFakeDirectory + "/deep11/level1.txt",
kFakeDirectory + "/deep11/not_bash"};
} else {
expected = {kFakeDirectory + "/deep1/deep2/",
kFakeDirectory + "/deep11/deep2/",
kFakeDirectory + "/deep1/level1.txt",
kFakeDirectory + "/deep11/level1.txt",
kFakeDirectory + "/deep11/not_bash"};
}
auto result =
platformGlob(kFakeDirectory + "/*/{deep2,level1,not_bash}{,.txt}");
EXPECT_TRUE(globResultsMatch(result, expected));

View File

@ -54,7 +54,6 @@ std::string kDoorTxtPath;
std::string kDeep11Path;
class FilesystemTests : public testing::Test {
protected:
void SetUp() {
createMockFileStructure();
@ -65,10 +64,12 @@ class FilesystemTests : public testing::Test {
fs::path(kFakeDirectory + "/deep11").make_preferred().string();
}
void TearDown() { tearDownMockFileStructure(); }
void TearDown() {
tearDownMockFileStructure();
}
/// Helper method to check if a path was included in results.
bool contains(const std::vector<std::string> &all, const std::string &n) {
bool contains(const std::vector<std::string>& all, const std::string& n) {
return !(std::find(all.begin(), all.end(), n) == all.end());
}
};
@ -98,8 +99,7 @@ TEST_F(FilesystemTests, test_read_limit) {
EXPECT_FALSE(status.ok());
FLAGS_read_max = max;
#ifndef WIN32
if (getuid() != 0) {
if (platformGetUid() != 0) {
content.erase();
FLAGS_read_user_max = 2;
status = readFile(kFakeDirectory + "/root.txt", content);
@ -115,7 +115,6 @@ TEST_F(FilesystemTests, test_read_limit) {
status = readFile(kFakeDirectory + "/root2.txt", content);
EXPECT_TRUE(status.ok());
}
#endif
}
TEST_F(FilesystemTests, test_list_files_missing_directory) {
@ -142,6 +141,14 @@ TEST_F(FilesystemTests, test_list_files_valid_directory) {
EXPECT_TRUE(contains(results, kEtcHostsPath));
}
TEST_F(FilesystemTests, test_intermediate_globbing_directories) {
fs::path thirdLevelDir =
fs::path(kFakeDirectory) / "toplevel" / "%" / "thirdlevel1";
std::vector<std::string> results;
resolveFilePattern(thirdLevelDir, results);
EXPECT_EQ(results.size(), 1U);
}
TEST_F(FilesystemTests, test_canonicalization) {
std::string complex =
(fs::path(kFakeDirectory) / "deep1" / ".." / "deep1" / "..")
@ -179,7 +186,7 @@ TEST_F(FilesystemTests, test_simple_globs) {
// Test the shell '*', we will support SQL's '%' too.
auto status = resolveFilePattern(kFakeDirectory + "/*", results);
EXPECT_TRUE(status.ok());
EXPECT_EQ(results.size(), 6U);
EXPECT_EQ(results.size(), 7U);
// Test the csh-style bracket syntax: {}.
results.clear();
@ -199,7 +206,7 @@ TEST_F(FilesystemTests, test_wildcard_single_all) {
std::vector<std::string> results;
auto status = resolveFilePattern(kFakeDirectory + "/%", results, GLOB_ALL);
EXPECT_TRUE(status.ok());
EXPECT_EQ(results.size(), 6U);
EXPECT_EQ(results.size(), 7U);
EXPECT_TRUE(contains(
results,
fs::path(kFakeDirectory + "/roto.txt").make_preferred().string()));
@ -221,7 +228,7 @@ TEST_F(FilesystemTests, test_wildcard_single_files) {
TEST_F(FilesystemTests, test_wildcard_single_folders) {
std::vector<std::string> results;
resolveFilePattern(kFakeDirectory + "/%", results, GLOB_FOLDERS);
EXPECT_EQ(results.size(), 2U);
EXPECT_EQ(results.size(), 3U);
EXPECT_TRUE(contains(
results,
fs::path(kFakeDirectory + "/deep11/").make_preferred().string()));
@ -232,9 +239,10 @@ TEST_F(FilesystemTests, test_wildcard_dual) {
std::vector<std::string> results;
auto status = resolveFilePattern(kFakeDirectory + "/%/%", results);
EXPECT_TRUE(status.ok());
EXPECT_TRUE(contains(results, fs::path(kFakeDirectory + "/deep1/level1.txt")
.make_preferred()
.string()));
EXPECT_TRUE(contains(results,
fs::path(kFakeDirectory + "/deep1/level1.txt")
.make_preferred()
.string()));
}
TEST_F(FilesystemTests, test_wildcard_double) {
@ -242,21 +250,21 @@ TEST_F(FilesystemTests, test_wildcard_double) {
std::vector<std::string> results;
auto status = resolveFilePattern(kFakeDirectory + "/%%", results);
EXPECT_TRUE(status.ok());
EXPECT_EQ(results.size(), 15U);
EXPECT_TRUE(
contains(results, fs::path(kFakeDirectory + "/deep1/deep2/level2.txt")
.make_preferred()
.string()));
EXPECT_EQ(results.size(), 20U);
EXPECT_TRUE(contains(results,
fs::path(kFakeDirectory + "/deep1/deep2/level2.txt")
.make_preferred()
.string()));
}
TEST_F(FilesystemTests, test_wildcard_double_folders) {
std::vector<std::string> results;
resolveFilePattern(kFakeDirectory + "/%%", results, GLOB_FOLDERS);
EXPECT_EQ(results.size(), 5U);
EXPECT_TRUE(
contains(results, fs::path(kFakeDirectory + "/deep11/deep2/deep3/")
.make_preferred()
.string()));
EXPECT_EQ(results.size(), 10U);
EXPECT_TRUE(contains(results,
fs::path(kFakeDirectory + "/deep11/deep2/deep3/")
.make_preferred()
.string()));
}
TEST_F(FilesystemTests, test_wildcard_end_last_component) {
@ -275,12 +283,14 @@ TEST_F(FilesystemTests, test_wildcard_middle_component) {
EXPECT_TRUE(status.ok());
EXPECT_EQ(results.size(), 5U);
EXPECT_TRUE(contains(results, fs::path(kFakeDirectory + "/deep1/level1.txt")
.make_preferred()
.string()));
EXPECT_TRUE(contains(results, fs::path(kFakeDirectory + "/deep11/level1.txt")
.make_preferred()
.string()));
EXPECT_TRUE(contains(results,
fs::path(kFakeDirectory + "/deep1/level1.txt")
.make_preferred()
.string()));
EXPECT_TRUE(contains(results,
fs::path(kFakeDirectory + "/deep11/level1.txt")
.make_preferred()
.string()));
}
TEST_F(FilesystemTests, test_wildcard_all_types) {
@ -288,8 +298,9 @@ TEST_F(FilesystemTests, test_wildcard_all_types) {
auto status = resolveFilePattern(kFakeDirectory + "/%p11/%/%%", results);
EXPECT_TRUE(status.ok());
EXPECT_TRUE(contains(
results, fs::path(kFakeDirectory + "/deep11/deep2/deep3/level3.txt")
EXPECT_TRUE(
contains(results,
fs::path(kFakeDirectory + "/deep11/deep2/deep3/level3.txt")
.make_preferred()
.string()));
}
@ -393,4 +404,3 @@ TEST_F(FilesystemTests, test_read_urandom) {
}
#endif
}

View File

@ -1024,7 +1024,9 @@ std::vector<std::string> platformGlob(const std::string& find_path) {
boost::system::error_code ec;
if (fs::exists(valid_path / component, ec) &&
ec.value() == errc::success) {
tmp_valid_paths.push_back(valid_path / component);
fs::path tmp_vpath =
component.string() != "." ? valid_path / component : valid_path;
tmp_valid_paths.push_back(tmp_vpath);
}
}
}
@ -1054,7 +1056,11 @@ std::vector<std::string> platformGlob(const std::string& find_path) {
}
}
} else {
WindowsFindFiles wf(valid_path / full_path.filename());
fs::path glob_path = full_path.filename() == "."
? valid_path
: valid_path / full_path.filename();
WindowsFindFiles wf(glob_path);
for (auto& result : wf.get()) {
auto result_path = result.make_preferred().string();

View File

@ -106,10 +106,10 @@ if(NOT WINDOWS)
endif()
# No cross-platform application tables yet.
# file(GLOB OSQUERY_CROSS_APPLICATIONS_TABLES "applications/*.cpp")
# ADD_OSQUERY_LIBRARY_ADDITIONAL(osquery_tables_applications
# ${OSQUERY_CROSS_APPLICATIONS_TABLES}
#)
file(GLOB OSQUERY_CROSS_APPLICATIONS_TABLES "applications/*.cpp")
ADD_OSQUERY_LIBRARY_ADDITIONAL(osquery_tables_applications
${OSQUERY_CROSS_APPLICATIONS_TABLES}
)
file(GLOB OSQUERY_CROSS_NETWORKING_TABLES "networking/*.cpp")
ADD_OSQUERY_LIBRARY_ADDITIONAL(osquery_tables_networking

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2014-present, 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/tables/applications/browser_utils.h"
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;
namespace osquery {
namespace tables {
#pragma warning(disable : 4503)
QueryData genChromeExtensions(QueryContext& context) {
fs::path chromePath;
/// Each home directory will include custom extensions.
if (isPlatform(PlatformType::TYPE_WINDOWS)) {
chromePath = "\\AppData\\Local\\Google\\Chrome\\User Data\\%\\Extensions\\";
} else if (isPlatform(PlatformType::TYPE_OSX)) {
chromePath = "/Library/Application Support/Google/Chrome/%/Extensions/";
} else {
chromePath = "/.config/google-chrome/%/Extensions/";
}
return genChromeBasedExtensions(context, chromePath);
}
}
}

View File

@ -10,7 +10,7 @@
#include <osquery/logger.h>
#include "osquery/tables/applications/posix/browser_utils.h"
#include "osquery/tables/applications/browser_utils.h"
#include "osquery/tables/system/system_utils.h"
namespace osquery {
@ -42,7 +42,7 @@ void genExtension(const std::string& uid,
std::stringstream json_stream;
json_stream << json_data;
pt::read_json(json_stream, tree);
} catch (const pt::json_parser::json_parser_error& e) {
} catch (const pt::json_parser::json_parser_error& /* e */) {
VLOG(1) << "Could not parse JSON from: " << path + kManifestFile;
return;
}

View File

@ -10,7 +10,14 @@
#pragma once
#ifdef WIN32
#pragma warning(push, 3)
#pragma warning(disable : 4715)
#endif
#include <boost/property_tree/json_parser.hpp>
#ifdef WIN32
#pragma warning(pop)
#endif
#include <osquery/filesystem.h>
#include <osquery/tables.h>

View File

@ -16,7 +16,7 @@
#include <archive.h>
#include <archive_entry.h>
#include "osquery/tables/applications/posix/browser_utils.h"
#include "osquery/tables/applications/browser_utils.h"
#include "osquery/tables/system/system_utils.h"
namespace fs = boost::filesystem;

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2014-present, 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/tables/applications/posix/browser_utils.h"
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;
namespace osquery {
namespace tables {
/// Each home directory will include custom extensions.
#ifdef __APPLE__
#define kChromePath "/Library/Application Support/Google/Chrome/%/"
#else
#define kChromePath "/.config/google-chrome/%/"
#endif
#define kChromeExtensionsPath "Extensions/"
QueryData genChromeExtensions(QueryContext& context) {
return genChromeBasedExtensions(context, (kChromePath kChromeExtensionsPath));
}
}
}

View File

@ -14,7 +14,7 @@
#include <osquery/logger.h>
#include <osquery/tables.h>
#include "osquery/tables/applications/posix/browser_utils.h"
#include "osquery/tables/applications/browser_utils.h"
#include "osquery/tables/system/system_utils.h"
namespace fs = boost::filesystem;

View File

@ -8,7 +8,7 @@
*
*/
#include "osquery/tables/applications/posix/browser_utils.h"
#include "osquery/tables/applications/browser_utils.h"
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;

View File

@ -17,15 +17,13 @@ QueryData usersFromContext(const QueryContext& context, bool all) {
QueryData users;
if (context.hasConstraint("uid", EQUALS)) {
context.forEachConstraint(
"uid",
EQUALS,
([&users](const std::string& expr) {
"uid", EQUALS, ([&users](const std::string& expr) {
auto user = SQL::selectAllFrom("users", "uid", EQUALS, expr);
users.insert(users.end(), user.begin(), user.end());
}));
} else if (!all) {
users =
SQL::selectAllFrom("users", "uid", EQUALS, std::to_string(getuid()));
users = SQL::selectAllFrom(
"users", "uid", EQUALS, std::to_string(platformGetUid()));
} else {
users = SQL::selectAllFrom("users");
}
@ -36,15 +34,13 @@ QueryData pidsFromContext(const QueryContext& context, bool all) {
QueryData procs;
if (context.hasConstraint("pid", EQUALS)) {
context.forEachConstraint(
"pid",
EQUALS,
([&procs](const std::string& expr) {
"pid", EQUALS, ([&procs](const std::string& expr) {
auto proc = SQL::selectAllFrom("processes", "pid", EQUALS, expr);
procs.insert(procs.end(), procs.begin(), procs.end());
}));
} else if (!all) {
procs = SQL::selectAllFrom(
"processes", "pid", EQUALS, std::to_string(getpid()));
"processes", "pid", EQUALS, std::to_string(platformGetPid()));
} else {
procs = SQL::selectAllFrom("processes");
}

View File

@ -82,7 +82,7 @@ void initTesting() {
// Set safe default values for path-based flags.
// Specific unittests may edit flags temporarily.
kTestWorkingDirectory += getUserId() + "/";
kTestWorkingDirectory += std::to_string(platformGetUid()) + "/";
kFakeDirectory = kTestWorkingDirectory + kFakeDirectoryName;
fs::remove_all(kTestWorkingDirectory);
@ -393,6 +393,11 @@ QueryData getEtcProtocolsExpectedResults() {
}
void createMockFileStructure() {
fs::create_directories(kFakeDirectory + "/toplevel/");
fs::create_directories(kFakeDirectory + "/toplevel/secondlevel1");
fs::create_directories(kFakeDirectory + "/toplevel/secondlevel2");
fs::create_directories(kFakeDirectory + "/toplevel/secondlevel3");
fs::create_directories(kFakeDirectory + "/toplevel/secondlevel3/thirdlevel1");
fs::create_directories(kFakeDirectory + "/deep11/deep2/deep3/");
fs::create_directories(kFakeDirectory + "/deep1/deep2/");
writeTextFile(kFakeDirectory + "/root.txt", "root");