Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sigrules to pass YARA signature with query #6568

Merged
merged 10 commits into from
Aug 29, 2020

Conversation

kumarak
Copy link
Contributor

@kumarak kumarak commented Jul 27, 2020

The PR adds a new column sigrules that can be used to pass a small set of YARA signature with the query.

osquery> select * from yara where path = '/etc/passwd' and sigrules = 'rule always_true { condition: true }';
+-------------+-------------+-------+-----------+---------+--------------------------------------+---------+------+
| path        | matches     | count | sig_group | sigfile | sigrules                             | strings | tags |
+-------------+-------------+-------+-----------+---------+--------------------------------------+---------+------+
| /etc/passwd | always_true | 1     |           |         | rule always_true { condition: true } |         |      |
+-------------+-------------+-------+-----------+---------+--------------------------------------+---------+------+

Copy link
Member

@directionless directionless left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nits)

tests/integration/tables/yara.cpp Outdated Show resolved Hide resolved
specs/yara/yara.table Outdated Show resolved Hide resolved
tests/integration/tables/yara.cpp Outdated Show resolved Hide resolved
osquery/tables/yara/yara.cpp Outdated Show resolved Hide resolved
osquery/tables/yara/yara.cpp Outdated Show resolved Hide resolved
osquery/tables/yara/yara.cpp Outdated Show resolved Hide resolved
osquery/tables/yara/yara_utils.cpp Outdated Show resolved Hide resolved
osquery/tables/yara/yara_utils.cpp Outdated Show resolved Hide resolved
tests/integration/tables/yara.cpp Outdated Show resolved Hide resolved
tests/integration/tables/yara.cpp Outdated Show resolved Hide resolved
continue;
}

rules[rule_string] = tmp_rules;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this caching could be dangerous, strings can be extremely large and people might run arbitrary queries via the distributed APIs. I suggest that we hash the rule string before adding it to the map here, add a known prefix, and that we clear these and free the memory after the scanning occurs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @theopolis for the review. I updated it to hash the rule string before adding to the cache and remove it after the scan to reduce/avoid the possibility of collision in case of multiple queries raised by distributed APIs. This is similar to not adding the sigrule string to the cache. Please let me know your thoughts.

@theopolis
Copy link
Member

theopolis commented Jul 31, 2020

I thought more about this and I'm worried the feature could be abused to read arbitrary content from files. The yara table can do this now but it requires someone to write the signature file to disk first. My recommendation to accommodate for this we should default-disable this feature with a configuration option.

Edit: Ignore the next section, it seems too clunky

Additionally, I am curious if the rule compilation and usage can be accomplished with a function instead of a column. For example could one write a query like:

select * from yara where path = apply_signature('/etc/passwd', 'rule always_true { condition: true }');

Then it's easier to disable/enable the apply_signature function via a flag.

@directionless
Copy link
Member

I thought more about this and I'm worried the feature could be abused to read arbitrary content from files.

Hrm. I was under the impression yara rules returned a boolean? Is there a way we can constrain the results to minimize the data leakage?

@theopolis
Copy link
Member

From my understanding the strings column will include matched strings.

@kumarak kumarak force-pushed the kumarak/yara_table_extension branch from 8dbcba4 to 27ced24 Compare August 10, 2020 19:28
@kumarak
Copy link
Contributor Author

kumarak commented Aug 11, 2020

@theopolis, I added an osquery flag enable_yara_table_extension to enable passing the signature rules with the query. Could you let me know your feedback? Also, if you think of other approaches to enable/disable the feature (maybe through configuration file) please let me know.

I have not explored the possibility of using the function to enable this feature yet. I will check how to use functions with the query and if it will be a convenient approach.

@directionless
Copy link
Member

We talked a bit about this in office hours. A suggestion I made, which submitted for consideration and seemed to be supported, is to create 2 flag. One to enable the this feature. And another to include whether or not to populate the strings column at all.

I think there's clear value in this, and in #6558, but I also think the data exfiltration is real. So thinking about how to allow the functionality, while not allowing easy extraction.

FLAG(uint32,
yara_delay,
50,
"Time in ms to sleep after scan of each file (default 50) to reduce "
"memory spikes");

FLAG(bool,
enable_yara_table_extension,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In osquery parlance, this is not an extension. Maybe enable_yara_sigrule?

Though probably should also gain enable_yara_string_return

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the configuration flag to enable_yara_sigrule and the rule strings are set to private by default. The private strings does not show-up in the yara table. disable_yara_string_private flag can be used to disable making strings to private.

osquery/tables/yara/yara.cpp Outdated Show resolved Hide resolved
osquery/tables/yara/yara.cpp Outdated Show resolved Hide resolved
Comment on lines 128 to 129
// Check if this "ad-hoc" signature file has not been used/compiled.
if (rules.count(hashStr(file, YC_FILE)) == 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cached based on filename, right? Short of restarting osquery, is there a way to clear that cache? I don't think there needs to be, but the limitation might need documenting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rule cache based on filename does not get cleanup. It avoids recompilation of file if they are already compiled.

Comment on lines 187 to 190
auto groups = context.constraints["sig_group"].getAll(EQUALS);
auto sigfiles = context.constraints["sigfile"].getAll(EQUALS);
auto sigrules = context.constraints["sigrule"].getAll(EQUALS);
if (groups.empty() && sigfiles.empty() && sigrules.empty()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels odd. These are checked here, but also then checked in the genYaraRuleFrom... routines. Do you think it's cleaner to call the genYaraRuleFrom... routines, and then check if scanContext is gt 0?

(This is not a leading question, I don't know what feels cleaner)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the checks and it will get the rules compiled and add them to the scanContext. It checks if the scanContext is empty and return empty result.

@kumarak kumarak force-pushed the kumarak/yara_table_extension branch from 46da858 to 3c2ed27 Compare August 21, 2020 08:02
@kumarak
Copy link
Contributor Author

kumarak commented Aug 21, 2020

Thanks, @directionless for comments. I added two flags: enable_yara_sigrule and disable_yara_string_private.

If a query is generated with sigrule, the rule strings are set as private by default. The private strings does not show-up in the yara table. To disable the feature and show the string column disable_yara_string_private flags can be used.

osquery/tables/yara/yara_utils.cpp Outdated Show resolved Hide resolved
osquery/tables/yara/yara_utils.cpp Outdated Show resolved Hide resolved
static std::shared_ptr<YARAConfigParserPlugin> getYaraParser(void) {
auto parser = Config::getParser("yara");
if (isNull(parser)) {
LOG(ERROR) << "YARA config parser plugin has no pointer";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"YARA config parser plugin not found"

osquery/tables/yara/yara.cpp Outdated Show resolved Hide resolved

Status genYaraRuleFromFile(QueryContext& queryContext,
YaraScanContext& scanContext) {
auto yaraParser = getYaraParser();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method getYaraParser may print an error then this function will "bubble up" a similar error but with a loss of precision. We should check that we do not unintentionally emit the same (or similar) error twice. For example, this status is passed up to genYara, do we end up printing a status message there too?

I suggest we avoid writing status messages in getYaraParser and allow the top-most calling method to choose to print.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the status log printing from the top-most calling function and let getYaraParser print the error logs. These logs are more useful to debug the specific issues. The top-most function returns if the parser is null.

osquery/tables/yara/yara_utils.cpp Outdated Show resolved Hide resolved
osquery/tables/yara/yara_utils.cpp Outdated Show resolved Hide resolved
osquery/tables/yara/yara_utils.cpp Outdated Show resolved Hide resolved
osquery/tables/yara/yara.cpp Show resolved Hide resolved
osquery/tables/yara/yara.cpp Outdated Show resolved Hide resolved
@theopolis
Copy link
Member

Thanks for the update! I'll take a final look at this tomorrow :)

/**
* Compile yara rules from string and load it into rule pointer.
*/
Status compileFromString(const std::string& rule_defs, YR_RULES** rules) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function compileFromString is similar to compileSingleFile and there are common code creating the yara compiler and error handling. I kept it as separate function to have different path for compiling the signature files and signature strings. Please let me know your thoughts.

@kumarak kumarak requested a review from theopolis August 26, 2020 19:23
@theopolis theopolis merged commit d86e90c into osquery:master Aug 29, 2020
nabilschear pushed a commit to nabilschear/osquery that referenced this pull request Aug 31, 2020
@kumarak kumarak deleted the kumarak/yara_table_extension branch September 30, 2020 01:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants