mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-06 09:35:20 +00:00
295 lines
9.7 KiB
C++
295 lines
9.7 KiB
C++
/**
|
|
* 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 <cstring>
|
|
#include <functional>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include <osquery/hashing/hashing.h>
|
|
#include <osquery/logger/logger.h>
|
|
|
|
#include <boost/asio/ip/address.hpp>
|
|
#include <boost/endian/buffers.hpp>
|
|
#include <sqlite3.h>
|
|
|
|
#ifdef OSQUERY_POSIX
|
|
#include <fuzzy.h>
|
|
#endif
|
|
|
|
namespace errc = boost::system::errc;
|
|
namespace ip = boost::asio::ip;
|
|
|
|
namespace osquery {
|
|
|
|
static void hashSqliteValue(sqlite3_context* ctx,
|
|
int argc,
|
|
sqlite3_value** argv,
|
|
HashType ht) {
|
|
if (argc == 0) {
|
|
return;
|
|
}
|
|
|
|
if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
|
|
sqlite3_result_null(ctx);
|
|
return;
|
|
}
|
|
|
|
// Parse and verify the split input parameters.
|
|
const char* input =
|
|
reinterpret_cast<const char*>(sqlite3_value_text(argv[0]));
|
|
if (input == nullptr) {
|
|
sqlite3_result_null(ctx);
|
|
return;
|
|
}
|
|
|
|
auto result = hashFromBuffer(ht, input, strlen(input));
|
|
sqlite3_result_text(
|
|
ctx, result.c_str(), static_cast<int>(result.size()), SQLITE_TRANSIENT);
|
|
}
|
|
|
|
static void sqliteMD5Func(sqlite3_context* context,
|
|
int argc,
|
|
sqlite3_value** argv) {
|
|
hashSqliteValue(context, argc, argv, HASH_TYPE_MD5);
|
|
}
|
|
|
|
static void sqliteSHA1Func(sqlite3_context* context,
|
|
int argc,
|
|
sqlite3_value** argv) {
|
|
hashSqliteValue(context, argc, argv, HASH_TYPE_SHA1);
|
|
}
|
|
|
|
static void sqliteSHA256Func(sqlite3_context* context,
|
|
int argc,
|
|
sqlite3_value** argv) {
|
|
hashSqliteValue(context, argc, argv, HASH_TYPE_SHA256);
|
|
}
|
|
|
|
#ifdef OSQUERY_POSIX
|
|
static void sqliteSsdeepCompareFunc(sqlite3_context* context,
|
|
int argc,
|
|
sqlite3_value** argv) {
|
|
if (sqlite3_value_type(argv[0]) != SQLITE_TEXT ||
|
|
sqlite3_value_type(argv[1]) != SQLITE_TEXT) {
|
|
sqlite3_result_error(
|
|
context, "Invalid inputs to ssdeep_compare, TEXT was expected", -1);
|
|
return;
|
|
}
|
|
const char* sig1 = reinterpret_cast<const char*>(sqlite3_value_text(argv[0]));
|
|
const char* sig2 = reinterpret_cast<const char*>(sqlite3_value_text(argv[1]));
|
|
sqlite3_result_int(context, fuzzy_compare(sig1, sig2));
|
|
}
|
|
#endif
|
|
|
|
static void sqliteCommunityIDv1(sqlite3_context* context,
|
|
int argc,
|
|
sqlite3_value** argv,
|
|
void (*errFunc)(sqlite3_context*,
|
|
const char*)) {
|
|
// Implemented as defined in https://github.com/corelight/community-id-spec
|
|
|
|
const size_t saddr_idx = 0, daddr_idx = 1, sport_idx = 2, dport_idx = 3,
|
|
proto_idx = 4, seed_idx = 5;
|
|
|
|
boost::endian::big_int16_buf_t seed(0);
|
|
if (argc == 6) {
|
|
if (sqlite3_value_type(argv[seed_idx]) != SQLITE_INTEGER) {
|
|
errFunc(context, "Community ID seed must be an integer");
|
|
return;
|
|
}
|
|
const int64_t seed64 =
|
|
static_cast<int64_t>(sqlite3_value_int64(argv[seed_idx]));
|
|
if (seed64 < INT16_MIN || seed64 > INT16_MAX) {
|
|
errFunc(context, "Community ID seed must fit in 2 bytes");
|
|
return;
|
|
}
|
|
seed = seed64;
|
|
}
|
|
|
|
if (sqlite3_value_type(argv[saddr_idx]) != SQLITE_TEXT ||
|
|
sqlite3_value_type(argv[daddr_idx]) != SQLITE_TEXT) {
|
|
errFunc(context, "Community ID IPs must be strings");
|
|
return;
|
|
}
|
|
const char* saddr_str =
|
|
reinterpret_cast<const char*>(sqlite3_value_text(argv[saddr_idx]));
|
|
const char* daddr_str =
|
|
reinterpret_cast<const char*>(sqlite3_value_text(argv[daddr_idx]));
|
|
|
|
boost::system::error_code ec;
|
|
ip::address saddr = ip::make_address(saddr_str, ec);
|
|
if (ec.value() != errc::success) {
|
|
errFunc(context, "Community ID saddr cannot be parsed as IP");
|
|
return;
|
|
}
|
|
ip::address daddr = ip::make_address(daddr_str, ec);
|
|
if (ec.value() != errc::success) {
|
|
errFunc(context, "Community ID daddr cannot be parsed as IP");
|
|
return;
|
|
}
|
|
|
|
if (sqlite3_value_type(argv[sport_idx]) != SQLITE_INTEGER ||
|
|
sqlite3_value_type(argv[dport_idx]) != SQLITE_INTEGER) {
|
|
errFunc(context, "Community ID ports must be integers");
|
|
return;
|
|
}
|
|
const int64_t sport64 =
|
|
static_cast<int64_t>(sqlite3_value_int64(argv[sport_idx]));
|
|
const int64_t dport64 =
|
|
static_cast<int64_t>(sqlite3_value_int64(argv[dport_idx]));
|
|
if (sport64 < 0 || sport64 > UINT16_MAX || dport64 < 0 ||
|
|
dport64 > UINT16_MAX) {
|
|
errFunc(context, "Community ID ports must fit in 2 bytes");
|
|
return;
|
|
}
|
|
boost::endian::big_uint16_buf_t sport(sport64);
|
|
boost::endian::big_uint16_buf_t dport(dport64);
|
|
|
|
if (sqlite3_value_type(argv[proto_idx]) != SQLITE_INTEGER) {
|
|
errFunc(context, "Community ID protocol must be an integer");
|
|
return;
|
|
}
|
|
const int64_t proto64 =
|
|
static_cast<int64_t>(sqlite3_value_int64(argv[proto_idx]));
|
|
if (proto64 < 0 || proto64 > UINT8_MAX) {
|
|
errFunc(context, "Community ID protocol must fit in 1 byte");
|
|
return;
|
|
}
|
|
uint8_t proto = proto64;
|
|
|
|
// Ensure ordering
|
|
if (!(saddr < daddr || (saddr == daddr && sport64 < dport64))) {
|
|
std::swap(saddr, daddr);
|
|
std::swap(sport, dport);
|
|
}
|
|
|
|
// seed . saddr . daddr . proto . 0 . sport . dport
|
|
std::stringstream bytes;
|
|
bytes.write(seed.data(), 2);
|
|
if (saddr.is_v4()) {
|
|
bytes.write(reinterpret_cast<const char*>(saddr.to_v4().to_bytes().data()),
|
|
4);
|
|
} else {
|
|
bytes.write(reinterpret_cast<const char*>(saddr.to_v6().to_bytes().data()),
|
|
16);
|
|
}
|
|
if (daddr.is_v4()) {
|
|
bytes.write(reinterpret_cast<const char*>(daddr.to_v4().to_bytes().data()),
|
|
4);
|
|
} else {
|
|
bytes.write(reinterpret_cast<const char*>(daddr.to_v6().to_bytes().data()),
|
|
16);
|
|
}
|
|
bytes.write(reinterpret_cast<const char*>(&proto), 1);
|
|
bytes.put(0);
|
|
bytes.write(sport.data(), 2);
|
|
bytes.write(dport.data(), 2);
|
|
|
|
std::string res = bytes.str();
|
|
|
|
Hash hash(HASH_TYPE_SHA1, HASH_ENCODING_TYPE_BASE64);
|
|
hash.update(res.c_str(), res.size());
|
|
auto result = "1:" + hash.digest();
|
|
|
|
sqlite3_result_text(context,
|
|
result.c_str(),
|
|
static_cast<int>(result.size()),
|
|
SQLITE_TRANSIENT);
|
|
}
|
|
|
|
static void sqliteCommunityIDv1Error(sqlite3_context* context,
|
|
int argc,
|
|
sqlite3_value** argv) {
|
|
auto handleError = [](sqlite3_context* context, const char* errMsg) {
|
|
sqlite3_result_error(context, errMsg, -1);
|
|
};
|
|
sqliteCommunityIDv1(context, argc, argv, handleError);
|
|
}
|
|
|
|
static void sqliteCommunityIDv1Null(sqlite3_context* context,
|
|
int argc,
|
|
sqlite3_value** argv) {
|
|
auto handleError = [](sqlite3_context* context, const char* errMsg) {
|
|
sqlite3_result_null(context);
|
|
LOG(WARNING) << errMsg;
|
|
};
|
|
sqliteCommunityIDv1(context, argc, argv, handleError);
|
|
}
|
|
|
|
void registerHashingExtensions(sqlite3* db) {
|
|
sqlite3_create_function(db,
|
|
"md5",
|
|
1,
|
|
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
|
nullptr,
|
|
sqliteMD5Func,
|
|
nullptr,
|
|
nullptr);
|
|
sqlite3_create_function(db,
|
|
"sha1",
|
|
1,
|
|
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
|
nullptr,
|
|
sqliteSHA1Func,
|
|
nullptr,
|
|
nullptr);
|
|
sqlite3_create_function(db,
|
|
"sha256",
|
|
1,
|
|
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
|
nullptr,
|
|
sqliteSHA256Func,
|
|
nullptr,
|
|
nullptr);
|
|
#ifdef OSQUERY_POSIX
|
|
sqlite3_create_function(db,
|
|
"ssdeep_compare",
|
|
2,
|
|
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
|
nullptr,
|
|
sqliteSsdeepCompareFunc,
|
|
nullptr,
|
|
nullptr);
|
|
#endif
|
|
sqlite3_create_function(db,
|
|
"community_id_v1",
|
|
5,
|
|
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
|
nullptr,
|
|
sqliteCommunityIDv1Null,
|
|
nullptr,
|
|
nullptr);
|
|
sqlite3_create_function(db,
|
|
"community_id_v1",
|
|
6, // with seed
|
|
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
|
nullptr,
|
|
sqliteCommunityIDv1Null,
|
|
nullptr,
|
|
nullptr);
|
|
sqlite3_create_function(db,
|
|
"community_id_v1_strict",
|
|
5,
|
|
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
|
nullptr,
|
|
sqliteCommunityIDv1Error,
|
|
nullptr,
|
|
nullptr);
|
|
sqlite3_create_function(db,
|
|
"community_id_v1_strict",
|
|
6, // with seed
|
|
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
|
nullptr,
|
|
sqliteCommunityIDv1Error,
|
|
nullptr,
|
|
nullptr);
|
|
}
|
|
} // namespace osquery
|