QueryData genChromeBasedExtensions(QueryContext& context, const fs::path& sub_dir) { QueryData results; auto users = usersFromContext(context); for (const auto& row : users) { if (row.count("uid") > 0 && row.count("directory") > 0) { // For each user, enumerate all of their chrome profiles. std::vector<std::string> profiles; fs::path extension_path = row.at("directory") / sub_dir; if (!resolveFilePattern(extension_path, profiles, GLOB_FOLDERS).ok()) { continue; } // For each profile list each extension in the Extensions directory. std::vector<std::string> extensions; for (const auto& profile : profiles) { listDirectoriesInDirectory(profile, extensions); } // Generate an addons list from their extensions JSON. std::vector<std::string> versions; for (const auto& extension : extensions) { listDirectoriesInDirectory(extension, versions); } // Extensions use /<EXTENSION>/<VERSION>/manifest.json. for (const auto& version : versions) { genExtension(row.at("uid"), version, results); } } } return results; }
QueryData genBrowserPlugins(QueryContext& context) { QueryData results; std::vector<std::string> bundles; // The caller is not requesting a JOIN against users. // This is "special" logic for user data-based tables since there is a concept // of system-available browser extensions. if (context.constraints["uid"].notExistsOrMatches("0")) { std::vector<std::string> bundles; if (listDirectoriesInDirectory(kBrowserPluginsPath, bundles).ok()) { for (const auto& dir : bundles) { genBrowserPlugin("0", dir, results); } } } // Iterate over each user auto users = usersFromContext(context); for (const auto& row : users) { if (row.count("uid") > 0 && row.count("directory") > 0) { std::vector<std::string> bundles; auto dir = fs::path(row.at("directory")) / kBrowserPluginsPath; if (listDirectoriesInDirectory(dir, bundles).ok()) { for (const auto& dir : bundles) { genBrowserPlugin(row.at("uid"), dir, results); } } } } return results; }
QueryData genChromeBasedExtensions(QueryContext& context, const fs::path sub_dir) { QueryData results; auto homes = osquery::getHomeDirectories(); for (const auto& home : homes) { // For each user, enumerate all of their chrome profiles. std::vector<std::string> profiles; fs::path extension_path = home / sub_dir; if (!resolveFilePattern(extension_path, profiles, REC_LIST_FOLDERS).ok()) { continue; } // For each profile list each extension in the Extensions directory. std::vector<std::string> extensions; for (const auto& profile : profiles) { listDirectoriesInDirectory(profile, extensions); } // Generate an addons list from their extensions JSON. std::vector<std::string> versions; for (const auto& extension : extensions) { listDirectoriesInDirectory(extension, versions); } // Extensions use /<EXTENSION>/<VERSION>/manifest.json. for (const auto& version : versions) { genExtension(version, results); } } return results; }
bool INotifyEventPublisher::addMonitor(const std::string& path, bool recursive) { if (!isPathMonitored(path)) { int watch = ::inotify_add_watch(getHandle(), path.c_str(), IN_ALL_EVENTS); if (watch == -1) { LOG(ERROR) << "Could not add inotfy watch on: " << path; return false; } // Keep a list of the watch descriptors descriptors_.push_back(watch); // Keep a map of the path -> watch descriptor path_descriptors_[path] = watch; // Keep a map of the opposite (descriptor -> path) descriptor_paths_[watch] = path; } if (recursive && isDirectory(path).ok()) { std::vector<std::string> children; // Get a list of children of this directory (requesed recursive watches). listDirectoriesInDirectory(path, children); for (const auto& child : children) { addMonitor(child, recursive); } } return true; }
bool INotifyEventPublisher::addMonitor(const std::string& path, uint32_t mask, bool recursive, bool add_watch) { if (!isPathMonitored(path)) { int watch = ::inotify_add_watch( getHandle(), path.c_str(), ((mask == 0) ? kFileDefaultMasks : mask)); if (add_watch && watch == -1) { LOG(WARNING) << "Could not add inotify watch on: " << path; return false; } // Keep a list of the watch descriptors descriptors_.push_back(watch); // Keep a map of the path -> watch descriptor path_descriptors_[path] = watch; // Keep a map of the opposite (descriptor -> path) descriptor_paths_[watch] = path; } if (recursive && isDirectory(path).ok()) { std::vector<std::string> children; // Get a list of children of this directory (requested recursive watches). listDirectoriesInDirectory(path, children, true); boost::system::error_code ec; for (const auto& child : children) { auto canonicalized = fs::canonical(child, ec).string() + '/'; addMonitor(canonicalized, mask, false); } } return true; }
QueryData genMemoryMap(QueryContext& context) { QueryData results; // Linux memory map is exposed in /sys. std::vector<std::string> regions; auto status = listDirectoriesInDirectory(kMemoryMapLocation, regions); if (!status.ok()) { return {}; } for (const auto& index : regions) { fs::path index_path(index); Row r; r["region"] = index_path.filename().string(); // The type is a textual description std::string content; readFile(index_path / "type", content); boost::trim(content); r["type"] = content; // Keep these in 0xFFFF (hex) form. readFile(index_path / "start", content); boost::trim(content); r["start"] = content; readFile(index_path / "end", content); boost::trim(content); r["end"] = content; results.push_back(r); } return results; }
QueryData genScheduledTasks(QueryContext& context) { QueryData results; // First process all tasks in the root folder enumerateTasksForFolder("\\", results); // We attempt to derive the location of the tasks folder auto sysRoot = getEnvVar("SystemRoot"); if (!sysRoot.is_initialized()) { return results; } auto sysTaskPath = *sysRoot + "\\System32\\Tasks"; // Then process all tasks in subsequent folders std::vector<std::string> taskPaths; listDirectoriesInDirectory(sysTaskPath, taskPaths, true); for (const auto& path : taskPaths) { if (sysTaskPath.size() >= path.size()) { VLOG(1) << "Invalid task path " << path; continue; } auto taskPath = "\\" + join(split(path.substr(sysTaskPath.size(), (path.size() - sysTaskPath.size())), "\\"), "\\"); enumerateTasksForFolder(taskPath, results); } return results; }
void genSiteDirectories(const std::string& site, QueryData& results) { std::vector<std::string> directories; if (!listDirectoriesInDirectory(site, directories, true).ok()) { return; } for (const auto& directory : directories) { if (!isDirectory(directory).ok()) { continue; } Row r; if (directory.find(".dist-info") != std::string::npos) { auto path = directory + "/METADATA"; genPackage(path, r); } else if (directory.find(".egg-info") != std::string::npos) { auto path = directory + "/PKG-INFO"; genPackage(path, r); } else { continue; } r["directory"] = site; r["path"] = directory; results.push_back(r); } }
QueryData genBrowserPlugins(QueryContext& context) { QueryData results; std::vector<std::string> bundles; // Lambda to walk through each browser plugin and process the plist file. auto enum_browser_plugins = [&results](const fs::path& path, const std::string& uid) { std::vector<std::string> bundles; if (listDirectoriesInDirectory(path, bundles).ok()) { for (const auto& dir : bundles) { genBrowserPlugin(uid, dir, results, false); } } // Check if the plugin is the 'Disabled' folder. std::vector<std::string> disabled_bundles; auto dis_path = path / "Disabled Plug-Ins"; if (listDirectoriesInDirectory(dis_path, disabled_bundles).ok()) { for (const auto& disabled_dir : disabled_bundles) { genBrowserPlugin(uid, disabled_dir, results, true); } } }; // The caller is not requesting a JOIN against users. This is "special" logic // for user data-based tables since there is a concept of system-available // browser extensions. if (context.constraints["uid"].notExistsOrMatches("0")) { enum_browser_plugins(kBrowserPluginsPath, "0"); } // Iterate over each user auto users = usersFromContext(context); for (const auto& row : users) { if (row.count("uid") > 0 && row.count("directory") > 0) { auto dir = fs::path(row.at("directory")) / kBrowserPluginsPath; enum_browser_plugins(dir, row.at("uid")); } } return results; }
QueryData genBrowserPlugins(QueryContext& context) { QueryData results; std::vector<std::string> bundles; if (listDirectoriesInDirectory(kBrowserPluginsPath, bundles).ok()) { for (const auto& dir : bundles) { genBrowserPlugin(dir, results); } } auto homes = osquery::getHomeDirectories(); for (const auto& home : homes) { bundles.clear(); if (listDirectoriesInDirectory(home / kBrowserPluginsPath, bundles).ok()) { for (const auto& dir : bundles) { genBrowserPlugin(dir, results); } } } return results; }
void genAllControls(QueryData& results, const std::map<std::string, std::string>& config, const std::string& subsystem) { // Linux sysctl subsystems are directories in /proc std::vector<std::string> subsystems; if (!listDirectoriesInDirectory("/proc/sys", subsystems).ok()) { return; } for (const auto& sub : subsystems) { if (subsystem.size() != 0 && fs::path(sub).filename().string() != subsystem) { // Request is limiting subsystem. continue; } genControlInfo(sub, results, config); } }
QueryData genPythonPackages(QueryContext& context) { QueryData results; std::set<std::string> paths; if (context.constraints.count("directory") > 0 && context.constraints.at("directory").exists(EQUALS)) { paths = context.constraints["directory"].getAll(EQUALS); } else { paths = kPythonPath; } for (const auto& key : paths) { genSiteDirectories(key, results); } if (isPlatform(PlatformType::TYPE_OSX)) { for (const auto& dir : kDarwinPythonPath) { std::vector<std::string> versions; if (!listDirectoriesInDirectory(dir, versions, false).ok()) { continue; } for (const auto& version : versions) { // macOS will link older versions to 2.6. auto version_path = fs::path(version).parent_path(); if (fs::is_symlink(symlink_status(version_path))) { continue; } auto complete = version + "lib/python" + version_path.filename().string() + "/site-packages/"; genSiteDirectories(complete, results); } } } else if (isPlatform(PlatformType::TYPE_WINDOWS)) { // Enumerate any system installed python packages auto installPathKey = "HKEY_LOCAL_MACHINE\\" + kWinPythonInstallKey; genWinPythonPackages(installPathKey, results); // Enumerate any user installed python packages installPathKey = "HKEY_USERS\\%\\" + kWinPythonInstallKey; genWinPythonPackages(installPathKey, results); } return results; }
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; }
void genControlInfo(const std::string& mib_path, QueryData& results, const std::map<std::string, std::string>& config) { if (isDirectory(mib_path).ok()) { // Iterate through the subitems and items. std::vector<std::string> items; if (listDirectoriesInDirectory(mib_path, items).ok()) { for (const auto& item : items) { genControlInfo(item, results, config); } } if (listFilesInDirectory(mib_path, items).ok()) { for (const auto& item : items) { genControlInfo(item, results, config); } } return; } // This is a file (leaf-control). Row r; r["name"] = mib_path.substr(kSystemControlPath.size()); std::replace(r["name"].begin(), r["name"].end(), '/', '.'); // No known way to convert name MIB to int array. r["subsystem"] = osquery::split(r.at("name"), ".")[0]; if (isReadable(mib_path).ok()) { std::string content; readFile(mib_path, content); boost::trim(content); r["current_value"] = content; } if (config.count(r.at("name")) > 0) { r["config_value"] = config.at(r.at("name")); } r["type"] = "string"; results.push_back(r); }
QueryData genFirefoxAddons(QueryContext& context) { QueryData results; // Iterate over each user QueryData users = usersFromContext(context); for (const auto& row : users) { if (row.count("uid") > 0 && row.count("directory") > 0) { // For each user, enumerate all of their Firefox profiles. std::vector<std::string> profiles; auto directory = fs::path(row.at("directory")) / kFirefoxPath; if (!listDirectoriesInDirectory(directory, profiles).ok()) { continue; } // Generate an addons list from their extensions JSON. for (const auto& profile : profiles) { genFirefoxAddonsFromExtensions(row.at("uid"), profile, results); } } } return results; }