2014-12-18 18:50:47 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
2015-05-12 06:31:13 +00:00
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
2014-12-18 18:50:47 +00:00
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*
|
|
|
|
*/
|
2014-10-29 05:08:10 +00:00
|
|
|
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <grp.h>
|
|
|
|
#include <sys/stat.h>
|
2014-11-12 05:34:59 +00:00
|
|
|
|
2014-10-29 05:08:10 +00:00
|
|
|
#include <boost/filesystem.hpp>
|
2014-11-12 05:34:59 +00:00
|
|
|
|
2014-12-10 04:13:39 +00:00
|
|
|
#include <osquery/filesystem.h>
|
2014-12-03 23:14:02 +00:00
|
|
|
#include <osquery/logger.h>
|
|
|
|
#include <osquery/tables.h>
|
2014-10-29 05:08:10 +00:00
|
|
|
|
2014-12-10 00:38:14 +00:00
|
|
|
namespace fs = boost::filesystem;
|
|
|
|
|
2014-10-29 05:08:10 +00:00
|
|
|
namespace osquery {
|
|
|
|
namespace tables {
|
|
|
|
|
2014-12-10 00:38:14 +00:00
|
|
|
std::vector<std::string> kBinarySearchPaths = {
|
|
|
|
"/bin",
|
|
|
|
"/sbin",
|
|
|
|
"/usr/bin",
|
|
|
|
"/usr/sbin",
|
|
|
|
"/usr/local/bin",
|
|
|
|
"/usr/local/sbin",
|
2014-12-10 04:13:39 +00:00
|
|
|
"/tmp",
|
2014-12-10 00:38:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Status genBin(const fs::path& path, int perms, QueryData& results) {
|
2014-11-12 05:34:59 +00:00
|
|
|
struct stat info;
|
|
|
|
// store user and group
|
|
|
|
if (stat(path.c_str(), &info) != 0) {
|
|
|
|
return Status(1, "stat failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
// store path
|
2014-10-29 05:08:10 +00:00
|
|
|
Row r;
|
2014-11-12 05:34:59 +00:00
|
|
|
r["path"] = path.string();
|
|
|
|
struct passwd *pw = getpwuid(info.st_uid);
|
|
|
|
struct group *gr = getgrgid(info.st_gid);
|
|
|
|
|
|
|
|
// get user name + group
|
|
|
|
std::string user;
|
|
|
|
if (pw != nullptr) {
|
|
|
|
user = std::string(pw->pw_name);
|
|
|
|
} else {
|
|
|
|
user = boost::lexical_cast<std::string>(info.st_uid);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string group;
|
|
|
|
if (gr != nullptr) {
|
|
|
|
group = std::string(gr->gr_name);
|
|
|
|
} else {
|
|
|
|
group = boost::lexical_cast<std::string>(info.st_gid);
|
|
|
|
}
|
|
|
|
|
|
|
|
r["username"] = user;
|
|
|
|
r["groupname"] = group;
|
|
|
|
|
|
|
|
r["permissions"] = "";
|
|
|
|
if ((perms & 04000) == 04000) {
|
|
|
|
r["permissions"] += "S";
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((perms & 02000) == 02000) {
|
|
|
|
r["permissions"] += "G";
|
|
|
|
}
|
|
|
|
|
|
|
|
results.push_back(r);
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
2014-12-10 00:38:14 +00:00
|
|
|
bool isSuidBin(const fs::path& path, int perms) {
|
|
|
|
if (!fs::is_regular_file(path)) {
|
|
|
|
return false;
|
2014-11-12 05:34:59 +00:00
|
|
|
}
|
2014-11-06 22:00:58 +00:00
|
|
|
|
2014-12-10 00:38:14 +00:00
|
|
|
if ((perms & 04000) == 04000 || (perms & 02000) == 02000) {
|
|
|
|
return true;
|
2014-11-06 22:00:58 +00:00
|
|
|
}
|
2014-12-10 00:38:14 +00:00
|
|
|
return false;
|
|
|
|
}
|
2014-10-29 05:08:10 +00:00
|
|
|
|
2014-12-10 04:13:39 +00:00
|
|
|
void genSuidBinsFromPath(const std::string& path, QueryData& results) {
|
|
|
|
if (!pathExists(path).ok()) {
|
|
|
|
// Creating an iterator on a missing path will except.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-10 00:38:14 +00:00
|
|
|
auto it = fs::recursive_directory_iterator(fs::path(path));
|
2014-12-10 04:13:39 +00:00
|
|
|
fs::recursive_directory_iterator end;
|
|
|
|
while (it != end) {
|
|
|
|
fs::path path = *it;
|
2014-10-29 05:08:10 +00:00
|
|
|
try {
|
2014-12-10 04:13:39 +00:00
|
|
|
// Do not traverse symlinked directories.
|
|
|
|
if (fs::is_directory(path) && fs::is_symlink(path)) {
|
|
|
|
it.no_push();
|
|
|
|
}
|
|
|
|
|
|
|
|
int perms = it.status().permissions();
|
2014-12-10 00:38:14 +00:00
|
|
|
if (isSuidBin(path, perms)) {
|
2014-12-10 04:13:39 +00:00
|
|
|
// Only emit suid bins.
|
|
|
|
genBin(path, perms, results);
|
2014-10-29 05:08:10 +00:00
|
|
|
}
|
2014-12-10 04:13:39 +00:00
|
|
|
|
|
|
|
++it;
|
2014-12-10 00:38:14 +00:00
|
|
|
} catch (fs::filesystem_error& e) {
|
|
|
|
VLOG(1) << "Cannot read binary from " << path;
|
|
|
|
it.no_push();
|
2014-12-10 04:13:39 +00:00
|
|
|
// Try to recover, otherwise break.
|
|
|
|
try { ++it; } catch(fs::filesystem_error& e) { break; }
|
2014-10-29 05:08:10 +00:00
|
|
|
}
|
|
|
|
}
|
2014-12-10 00:38:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QueryData genSuidBin(QueryContext& context) {
|
|
|
|
QueryData results;
|
|
|
|
|
2014-12-10 04:13:39 +00:00
|
|
|
// Todo: add hidden column to select on that triggers non-std path searches.
|
2014-12-10 00:38:14 +00:00
|
|
|
for (const auto& path : kBinarySearchPaths) {
|
|
|
|
genSuidBinsFromPath(path, results);
|
|
|
|
}
|
|
|
|
|
2014-10-29 05:08:10 +00:00
|
|
|
return results;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|