Example #1
0
Status YARAEventSubscriber::Callback(const FileEventContextRef& ec,
                                     const void* user_data) {
  if (user_data == nullptr) {
    return Status(1, "No YARA category string provided");
  }

  if (ec->action != "UPDATED" && ec->action != "CREATED") {
    return Status(1, "Invalid action");
  }

  Row r;
  r["action"] = ec->action;
  r["target_path"] = ec->path;
  r["category"] = *(std::string*)user_data;

  // Only FSEvents transactions updates (inotify is a no-op).
  r["transaction_id"] = INTEGER(ec->transaction_id);

  // These are default values, to be updated in YARACallback.
  r["count"] = INTEGER(0);
  r["matches"] = std::string("");
  r["strings"] = std::string("");
  r["tags"] = std::string("");

  ConfigDataInstance config;
  const auto& parser = config.getParser("yara");
  if (parser == nullptr)
    return Status(1, "ConfigParser unknown.");
  const auto& yaraParser = std::static_pointer_cast<YARAConfigParserPlugin>(parser);
  auto rules = yaraParser->rules();

  // Use the category as a lookup into the yara file_paths. The value will be
  // a list of signature groups to scan with.
  auto category = r.at("category");
  const auto& yara_config = config.getParsedData("yara");
  const auto& yara_paths = yara_config.get_child("file_paths");
  const auto& sig_groups = yara_paths.find(category);
  for (const auto& rule : sig_groups->second) {
    const std::string group = rule.second.data();
    int result = yr_rules_scan_file(rules[group],
                                    ec->path.c_str(),
                                    SCAN_FLAGS_FAST_MODE,
                                    YARACallback,
                                    (void*)&r,
                                    0);

    if (result != ERROR_SUCCESS) {
      return Status(1, "YARA error: " + std::to_string(result));
    }
  }

  if (ec->action != "" && r.at("matches").size() > 0) {
    add(r, ec->time);
  }

  return Status(0, "OK");
}
Example #2
0
QueryData genYara(QueryContext& context) {
  QueryData results;
  Status status;

  auto paths = context.constraints["path"].getAll(EQUALS);
  auto patterns = context.constraints["pattern"].getAll(EQUALS);
  auto groups = context.constraints["sig_group"].getAll(EQUALS);
  auto sigfiles = context.constraints["sigfile"].getAll(EQUALS);

  // Must specify a path constraint and at least one of sig_group or sigfile.
  if (groups.size() == 0 && sigfiles.size() == 0) {
    return results;
  }

  // XXX: Abstract this into a common "get rules for group" function.
  ConfigDataInstance config;
  const auto& parser = config.getParser("yara");
  if (parser == nullptr) {
    return results;
  }
  const auto& yaraParser = std::static_pointer_cast<YARAConfigParserPlugin>(parser);
  if (yaraParser == nullptr) {
    return results;
  }
  auto rules = yaraParser->rules();

  // Store resolved paths in a vector of pairs.
  // Each pair has the first element as the path to scan and the second
  // element as the pattern which generated it.
  std::vector<std::pair<std::string, std::string> > path_pairs;

  // Expand patterns and push onto path_pairs.
  for (const auto& pattern : patterns) {
    std::vector<std::string> expanded_patterns;
    auto status = resolveFilePattern(pattern, expanded_patterns);
    if (!status.ok()) {
      VLOG(1) << "Could not expand pattern properly: " << status.toString();
      return results;
    }

    for (const auto& resolved : expanded_patterns) {
      if (!isReadable(resolved)) {
        continue;
      }
      path_pairs.push_back(make_pair(resolved, pattern));
    }
  }

  // Collect all paths specified too.
  for (const auto& path_string : paths) {
    if (!isReadable(path_string)) {
      continue;
    }
    path_pairs.push_back(make_pair(path_string, ""));
  }

  // Compile all sigfiles into a map.
  std::map<std::string, YR_RULES*> compiled_rules;
  for (const auto& file : sigfiles) {
    YR_RULES *rules = nullptr;

    std::string full_path;
    if (file[0] != '/') {
      full_path = std::string("/etc/osquery/yara/") + file;
    } else {
      full_path = file;
    }

    status = compileSingleFile(full_path, &rules);
    if (!status.ok()) {
      VLOG(1) << "YARA error: " << status.toString();
    } else {
      compiled_rules[file] = rules;
    }
  }

  // Scan every path pair.
  for (const auto& path_pair : path_pairs) {
    // Scan using siggroups.
    for (const auto& group : groups) {
      if (rules.count(group) == 0) {
        continue;
      }

      VLOG(1) << "Scanning with group: " << group;
      status = doYARAScan(rules[group],
                          path_pair.first.c_str(),
                          path_pair.second,
                          results,
                          group,
                          "");
      if (!status.ok()) {
        VLOG(1) << "YARA error: " << status.toString();
      }
    }

    // Scan using files.
    for (const auto& element : compiled_rules) {
      VLOG(1) << "Scanning with file: " << element.first;
      status = doYARAScan(element.second,
                          path_pair.first.c_str(),
                          path_pair.second,
                          results,
                          "",
                          element.first);
      if (!status.ok()) {
        VLOG(1) << "YARA error: " << status.toString();
      }
    }
  }

  // Cleanup compiled rules
  for (const auto& element : compiled_rules) {
    yr_rules_destroy(element.second);
  }

  return results;
}