Support for Office MRU (most recently used) entries (#6587)

This commit is contained in:
puffyCid 2020-09-13 10:51:51 -04:00 committed by GitHub
parent 5c71654dcf
commit bd545631ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 201 additions and 0 deletions

View File

@ -39,6 +39,7 @@ function(generateOsqueryTablesApplications)
elseif(DEFINED PLATFORM_WINDOWS)
list(APPEND source_files
windows/carbon_black.cpp
windows/office_mru.cpp
)
elseif(DEFINED PLATFORM_LINUX)
list(APPEND source_files

View File

@ -0,0 +1,148 @@
/**
* Copyright (c) 2014-present, The osquery authors
*
* This source code is licensed as defined by the LICENSE file found in the
* root directory of this source tree.
*
* SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only)
*/
#include <osquery/core/core.h>
#include <osquery/core/tables.h>
#include <osquery/filesystem/fileops.h>
#include <osquery/logger/logger.h>
#include <osquery/tables/system/windows/registry.h>
#include <osquery/utils/conversions/tryto.h>
#include <osquery/utils/conversions/windows/windows_time.h>
#include <string>
namespace osquery {
namespace tables {
// Get all Office applications and get all installed versions
constexpr auto kOfficePath = "\\Software\\Microsoft\\Office\\%\\%\\File MRU\\%";
constexpr auto kOffice365Path =
"\\Software\\Microsoft\\Office\\%\\%\\User MRU\\%";
// Parse all the office MRU entries.
void parseOfficeData(QueryData& results,
const Row& entry,
const std::string& sid,
const std::string& office_version) {
auto item = entry.find("name");
// All file entries start with "Item", skip entries that are not named
// "Item"
if (item->second.find("Item") == std::string::npos) {
return;
}
// MRU entries should also be over 20 characters long
auto data = entry.find("data");
auto& file_path = data->second;
if (file_path.length() < 20) {
LOG(WARNING) << "MRU entry malformed: " << file_path;
return;
}
Row r;
// File path starts with *
r["path"] = file_path.substr(file_path.find("*") + 1);
// Extract the office application version from the registry path
auto version = office_version;
r["version"] = version.substr(office_version.find("Office\\"), 11).substr(7);
// Extract the office application name from the registry path
auto application = office_version;
auto office_app = application.substr(office_version.find(r["version"]));
r["application"] = office_app.substr(office_app.find("\\") + 1,
office_app.find(" MRU") - 10);
// Last opened time stored in Big endian Windows FILETIME Hex format, also
// starts with T
auto time_data = file_path.substr(file_path.find("T") + 1, 16);
// Try to convert last open time string to ull
unsigned long long last_open =
tryTo<unsigned long long>(time_data, 16).takeOr(0ull);
FILETIME file_time;
ULARGE_INTEGER large_time;
large_time.QuadPart = last_open;
file_time.dwHighDateTime = large_time.HighPart;
file_time.dwLowDateTime = large_time.LowPart;
auto open_time = filetimeToUnixtime(file_time);
r["last_opened_time"] = INTEGER(open_time);
r["sid"] = sid;
results.push_back(r);
}
// Get non-office 365 documents in File MRU key
void officeData(QueryData& results,
const std::string& office_data,
const std::string& sid) {
QueryData office_entries;
queryKey(office_data, office_entries);
for (const auto& entry : office_entries) {
parseOfficeData(results, entry, sid, office_data);
}
}
// Get Office 365 documents in User MRU and File MRU keys
void office365Data(QueryData& results,
const std::string& office_365_data,
const std::string& sid) {
std::string key = office_365_data;
std::set<std::string> office_365_results_files;
// Iterate through all User MRU entries
expandRegistryGlobs(key.append("\\%"), office_365_results_files);
for (const auto& fKey : office_365_results_files) {
// User accounts should have "_" in them, skip all keys that do not have
// "_"
if (fKey.find("_") == std::string::npos) {
continue;
}
QueryData office_entries;
std::string final_key = fKey;
queryKey(final_key.append("\\File MRU"), office_entries);
for (const auto& entry : office_entries) {
parseOfficeData(results, entry, sid, office_365_data);
}
}
}
QueryData genOfficeMru(QueryContext& context) {
QueryData results;
QueryData users;
queryKey("HKEY_USERS", users);
for (const auto& uKey : users) {
auto keyType = uKey.find("type");
auto keyPath = uKey.find("path");
if (keyType == uKey.end() || keyPath == uKey.end()) {
continue;
}
std::string office_path = keyPath->second + kOfficePath;
std::string office_365_path = keyPath->second + kOffice365Path;
std::string sid = uKey.at("name");
std::set<std::string> office_results;
expandRegistryGlobs(office_path, office_results);
for (const auto& office_data : office_results) {
officeData(results, office_data, sid);
}
std::set<std::string> office_365_results;
expandRegistryGlobs(office_365_path, office_365_results);
for (const auto& office_365_data : office_365_results) {
office365Data(results, office_365_data, sid);
}
}
return results;
}
} // namespace tables
} // namespace osquery

View File

@ -79,6 +79,7 @@ function(generateNativeTables)
set(platform_dependent_spec_files
"arp_cache.table:linux,macos,windows"
"atom_packages.table:linux,macos"
"office_mru.table:windows"
"darwin/account_policy_data.table:macos"
"darwin/ad_config.table:macos"
"darwin/alf.table:macos"

13
specs/office_mru.table Normal file
View File

@ -0,0 +1,13 @@
table_name("office_mru")
description("View recently opened Office documents.")
schema([
Column("application", TEXT, "Associated Office application"),
Column("version", TEXT, "Office application version number"),
Column("path", TEXT, "File path"),
Column("last_opened_time", INTEGER, "Most recent opened time file was opened"),
Column("sid", TEXT, "User SID"),
])
implementation("office_mru@genOfficeMru")
examples([
"select * from office_mru;",
])

View File

@ -281,6 +281,7 @@ function(generateTestsIntegrationTablesTestsTest)
kernel_info.cpp
kva_speculative_info.cpp
logical_drives.cpp
office_mru.cpp
ntdomains.cpp
ntfs_acl_permissions.cpp
patches.cpp

View File

@ -0,0 +1,37 @@
/**
* Copyright (c) 2014-present, The osquery authors
*
* This source code is licensed as defined by the LICENSE file found in the
* root directory of this source tree.
*
* SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only)
*/
#include <osquery/tests/integration/tables/helper.h>
namespace osquery {
namespace table_tests {
class OfficeMruTest : public testing::Test {
protected:
void SetUp() override {
setUpEnvironment();
}
};
TEST_F(OfficeMruTest, test_sanity) {
QueryData const rows = execute_query("select * from office_mru");
ValidationMap row_map = {{"application", NonEmptyString},
{"version", NonEmptyString},
{"path", NonEmptyString},
{"last_opened_time", NormalType},
{"sid", NonEmptyString}};
if (!rows.empty()) {
validate_rows(rows, row_map);
ASSERT_GT(rows.size(), 0ul);
}
}
} // namespace table_tests
} // namespace osquery