-
Notifications
You must be signed in to change notification settings - Fork 73
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 an "exists" check for "not" condition in sigma rules #852
Changes from all commits
872b14f
2ac748b
d0831f2
27333ec
1ba0117
20086b2
9a01b04
034097b
0769096
5ddaab6
444472d
fa2b9ae
ec8d4c5
5efdc79
e774d02
c71312a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,8 +4,6 @@ | |
*/ | ||
package org.opensearch.securityanalytics.rules.backend; | ||
|
||
import org.opensearch.commons.alerting.aggregation.bucketselectorext.BucketSelectorExtAggregationBuilder; | ||
import org.opensearch.search.aggregations.AggregationBuilder; | ||
import org.opensearch.securityanalytics.rules.aggregation.AggregationItem; | ||
import org.opensearch.securityanalytics.rules.backend.OSQueryBackend.AggregationQueries; | ||
import org.opensearch.securityanalytics.rules.condition.ConditionAND; | ||
|
@@ -47,7 +45,6 @@ | |
import java.util.Set; | ||
|
||
public abstract class QueryBackend { | ||
|
||
private boolean convertOrAsIn; | ||
private boolean convertAndAsIn; | ||
private boolean collectErrors; | ||
|
@@ -85,15 +82,15 @@ | |
|
||
Object query; | ||
if (conditionItem instanceof ConditionAND) { | ||
query = this.convertCondition(new ConditionType(Either.left(AnyOneOf.leftVal((ConditionAND) conditionItem)))); | ||
query = this.convertCondition(new ConditionType(Either.left(AnyOneOf.leftVal((ConditionAND) conditionItem))), false, false); | ||
} else if (conditionItem instanceof ConditionOR) { | ||
query = this.convertCondition(new ConditionType(Either.left(AnyOneOf.middleVal((ConditionOR) conditionItem)))); | ||
query = this.convertCondition(new ConditionType(Either.left(AnyOneOf.middleVal((ConditionOR) conditionItem))), false, false); | ||
} else if (conditionItem instanceof ConditionNOT) { | ||
query = this.convertCondition(new ConditionType(Either.left(AnyOneOf.rightVal((ConditionNOT) conditionItem)))); | ||
query = this.convertCondition(new ConditionType(Either.left(AnyOneOf.rightVal((ConditionNOT) conditionItem))), true, false); | ||
} else if (conditionItem instanceof ConditionFieldEqualsValueExpression) { | ||
query = this.convertCondition(new ConditionType(Either.right(Either.left((ConditionFieldEqualsValueExpression) conditionItem)))); | ||
query = this.convertCondition(new ConditionType(Either.right(Either.left((ConditionFieldEqualsValueExpression) conditionItem))), false, false); | ||
} else { | ||
query = this.convertCondition(new ConditionType(Either.right(Either.right((ConditionValueExpression) conditionItem)))); | ||
query = this.convertCondition(new ConditionType(Either.right(Either.right((ConditionValueExpression) conditionItem))), false, false); | ||
} | ||
queries.add(query); | ||
if (aggItem != null) { | ||
|
@@ -113,30 +110,41 @@ | |
return queries; | ||
} | ||
|
||
public Object convertCondition(ConditionType conditionType) throws SigmaValueError { | ||
public Object convertCondition(ConditionType conditionType, boolean isConditionNot, boolean applyDeMorgans) throws SigmaValueError { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are both these newly added bool params even necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see above |
||
if (conditionType.isConditionOR()) { | ||
if (this.decideConvertConditionAsInExpression(Either.right(conditionType.getConditionOR()))) { | ||
return this.convertConditionAsInExpression(Either.right(conditionType.getConditionOR())); | ||
return this.convertConditionAsInExpression(Either.right(conditionType.getConditionOR()), isConditionNot, applyDeMorgans ); | ||
} else { | ||
return this.convertConditionOr(conditionType.getConditionOR()); | ||
return this.convertConditionOr(conditionType.getConditionOR(), isConditionNot, applyDeMorgans); | ||
} | ||
} else if (conditionType.isConditionAND()) { | ||
if (this.decideConvertConditionAsInExpression(Either.left(conditionType.getConditionAND()))) { | ||
return this.convertConditionAsInExpression(Either.left(conditionType.getConditionAND())); | ||
return this.convertConditionAsInExpression(Either.left(conditionType.getConditionAND()), isConditionNot, applyDeMorgans); | ||
} else { | ||
return this.convertConditionAnd(conditionType.getConditionAND()); | ||
return this.convertConditionAnd(conditionType.getConditionAND(), isConditionNot, applyDeMorgans); | ||
} | ||
} else if (conditionType.isConditionNOT()) { | ||
return this.convertConditionNot(conditionType.getConditionNOT()); | ||
return this.convertConditionNot(conditionType.getConditionNOT(), isConditionNot, applyDeMorgans); | ||
} else if (conditionType.isEqualsValueExpression()) { | ||
return this.convertConditionFieldEqVal(conditionType.getEqualsValueExpression()); | ||
// check to see if conditionNot is an ancestor of the parse tree, otherwise return as normal | ||
if (isConditionNot) { | ||
return this.convertConditionFieldEqValNot(conditionType, isConditionNot, applyDeMorgans); | ||
} else { | ||
return this.convertConditionFieldEqVal(conditionType.getEqualsValueExpression(), isConditionNot, applyDeMorgans); | ||
} | ||
} else if (conditionType.isValueExpression()) { | ||
return this.convertConditionVal(conditionType.getValueExpression()); | ||
return this.convertConditionVal(conditionType.getValueExpression(), applyDeMorgans); | ||
} else { | ||
throw new IllegalArgumentException("Unexpected data type in condition parse tree"); | ||
} | ||
} | ||
|
||
public String convertConditionFieldEqValNot(ConditionType conditionType, boolean isConditionNot, boolean applyDeMorgans) throws SigmaValueError { | ||
String baseString = this.convertConditionFieldEqVal(conditionType.getEqualsValueExpression(), isConditionNot, applyDeMorgans).toString(); | ||
String addExists = this.convertExistsField(conditionType.getEqualsValueExpression()).toString(); | ||
return String.format(Locale.getDefault(), ("%s" + "%s"), baseString, addExists); | ||
} | ||
|
||
public boolean decideConvertConditionAsInExpression(Either<ConditionAND, ConditionOR> condition) { | ||
if ((!this.convertOrAsIn && condition.isRight()) || (!this.convertAndAsIn && condition.isLeft())) { | ||
return false; | ||
|
@@ -181,74 +189,76 @@ | |
} | ||
} | ||
|
||
public abstract Object convertConditionAsInExpression(Either<ConditionAND, ConditionOR> condition); | ||
public abstract Object convertConditionAsInExpression(Either<ConditionAND, ConditionOR> condition, boolean isConditionNot, boolean applyDeMorgans); | ||
|
||
public abstract Object convertConditionAnd(ConditionAND condition); | ||
public abstract Object convertConditionAnd(ConditionAND condition, boolean isConditionNot, boolean applyDeMorgans); | ||
|
||
public abstract Object convertConditionOr(ConditionOR condition); | ||
public abstract Object convertConditionOr(ConditionOR condition, boolean isConditionNot, boolean applyDeMorgans); | ||
|
||
public abstract Object convertConditionNot(ConditionNOT condition); | ||
public abstract Object convertConditionNot(ConditionNOT condition, boolean isConditionNot, boolean applyDeMorgans); | ||
|
||
public Object convertConditionFieldEqVal(ConditionFieldEqualsValueExpression condition) throws SigmaValueError { | ||
public Object convertConditionFieldEqVal(ConditionFieldEqualsValueExpression condition, boolean isConditionNot, boolean applyDeMorgans) throws SigmaValueError { | ||
if (condition.getValue() instanceof SigmaString) { | ||
return this.convertConditionFieldEqValStr(condition); | ||
return this.convertConditionFieldEqValStr(condition, applyDeMorgans); | ||
} else if (condition.getValue() instanceof SigmaNumber) { | ||
return this.convertConditionFieldEqValNum(condition); | ||
return this.convertConditionFieldEqValNum(condition, applyDeMorgans); | ||
} else if (condition.getValue() instanceof SigmaBool) { | ||
return this.convertConditionFieldEqValBool(condition); | ||
return this.convertConditionFieldEqValBool(condition, applyDeMorgans); | ||
} else if (condition.getValue() instanceof SigmaRegularExpression) { | ||
return this.convertConditionFieldEqValRe(condition); | ||
return this.convertConditionFieldEqValRe(condition, applyDeMorgans); | ||
} else if (condition.getValue() instanceof SigmaCIDRExpression) { | ||
return this.convertConditionFieldEqValCidr(condition); | ||
return this.convertConditionFieldEqValCidr(condition, applyDeMorgans); | ||
} else if (condition.getValue() instanceof SigmaCompareExpression) { | ||
return this.convertConditionFieldEqValOpVal(condition); | ||
return this.convertConditionFieldEqValOpVal(condition, applyDeMorgans); | ||
} else if (condition.getValue() instanceof SigmaNull) { | ||
return this.convertConditionFieldEqValNull(condition); | ||
return this.convertConditionFieldEqValNull(condition, applyDeMorgans); | ||
}/* TODO: below methods will be supported when Sigma Expand Modifier is supported. | ||
else if (condition.getValue() instanceof SigmaQueryExpression) { | ||
return this.convertConditionFieldEqValQueryExpr(condition); | ||
}*/ else if (condition.getValue() instanceof SigmaExpansion) { | ||
return this.convertConditionFieldEqValQueryExpansion(condition); | ||
return this.convertConditionFieldEqValQueryExpansion(condition, isConditionNot, applyDeMorgans); | ||
} else { | ||
throw new IllegalArgumentException("Unexpected value type class in condition parse tree: " + condition.getValue().getClass().getName()); | ||
} | ||
} | ||
|
||
public abstract Object convertConditionFieldEqValStr(ConditionFieldEqualsValueExpression condition) throws SigmaValueError; | ||
public abstract Object convertConditionFieldEqValStr(ConditionFieldEqualsValueExpression condition, boolean applyDeMorgans) throws SigmaValueError; | ||
|
||
public abstract Object convertConditionFieldEqValNum(ConditionFieldEqualsValueExpression condition, boolean applyDeMorgans); | ||
|
||
public abstract Object convertConditionFieldEqValNum(ConditionFieldEqualsValueExpression condition); | ||
public abstract Object convertConditionFieldEqValBool(ConditionFieldEqualsValueExpression condition, boolean applyDeMorgans); | ||
|
||
public abstract Object convertConditionFieldEqValBool(ConditionFieldEqualsValueExpression condition); | ||
public abstract Object convertConditionFieldEqValRe(ConditionFieldEqualsValueExpression condition, boolean applyDeMorgans); | ||
|
||
public abstract Object convertConditionFieldEqValRe(ConditionFieldEqualsValueExpression condition); | ||
public abstract Object convertConditionFieldEqValCidr(ConditionFieldEqualsValueExpression condition, boolean applyDeMorgans); | ||
|
||
public abstract Object convertConditionFieldEqValCidr(ConditionFieldEqualsValueExpression condition); | ||
public abstract Object convertConditionFieldEqValOpVal(ConditionFieldEqualsValueExpression condition, boolean applyDeMorgans); | ||
|
||
public abstract Object convertConditionFieldEqValOpVal(ConditionFieldEqualsValueExpression condition); | ||
public abstract Object convertConditionFieldEqValNull(ConditionFieldEqualsValueExpression condition, boolean applyDeMorgans); | ||
|
||
public abstract Object convertConditionFieldEqValNull(ConditionFieldEqualsValueExpression condition); | ||
public abstract Object convertExistsField(ConditionFieldEqualsValueExpression condition); | ||
|
||
/* public abstract Object convertConditionFieldEqValQueryExpr(ConditionFieldEqualsValueExpression condition);*/ | ||
/* public abstract Object convertConditionFieldEqValQueryExpr(ConditionFieldEqualsValueExpression condition);*/ | ||
|
||
public Object convertConditionFieldEqValQueryExpansion(ConditionFieldEqualsValueExpression condition) { | ||
public Object convertConditionFieldEqValQueryExpansion(ConditionFieldEqualsValueExpression condition, boolean isConditionNot, boolean applyDeMorgans) { | ||
List<Either<AnyOneOf<ConditionItem, ConditionFieldEqualsValueExpression, ConditionValueExpression>, String>> args = new ArrayList<>(); | ||
for (SigmaType sigmaType: ((SigmaExpansion) condition.getValue()).getValues()) { | ||
args.add(Either.left(AnyOneOf.middleVal(new ConditionFieldEqualsValueExpression(condition.getField(), sigmaType)))); | ||
} | ||
|
||
ConditionOR conditionOR = new ConditionOR(false, args); | ||
return this.convertConditionOr(conditionOR); | ||
return this.convertConditionOr(conditionOR, isConditionNot, applyDeMorgans); | ||
} | ||
|
||
public Object convertConditionVal(ConditionValueExpression condition) throws SigmaValueError { | ||
public Object convertConditionVal(ConditionValueExpression condition, boolean applyDeMorgans) throws SigmaValueError { | ||
if (condition.getValue() instanceof SigmaString) { | ||
return this.convertConditionValStr(condition); | ||
return this.convertConditionValStr(condition, applyDeMorgans); | ||
} else if (condition.getValue() instanceof SigmaNumber) { | ||
return this.convertConditionValNum(condition); | ||
return this.convertConditionValNum(condition, applyDeMorgans); | ||
} else if (condition.getValue() instanceof SigmaBool) { | ||
throw new SigmaValueError("Boolean values can't appear as standalone value without a field name."); | ||
} else if (condition.getValue() instanceof SigmaRegularExpression) { | ||
return this.convertConditionValRe(condition); | ||
return this.convertConditionValRe(condition, applyDeMorgans); | ||
}/* else if (condition.getValue() instanceof SigmaCIDRExpression) { | ||
throw new SigmaValueError("CIDR values can't appear as standalone value without a field name."); | ||
} else if (condition.getValue() instanceof SigmaQueryExpression) { | ||
|
@@ -258,11 +268,11 @@ | |
} | ||
} | ||
|
||
public abstract Object convertConditionValStr(ConditionValueExpression condition) throws SigmaValueError; | ||
public abstract Object convertConditionValStr(ConditionValueExpression condition, boolean applyDeMorgans) throws SigmaValueError; | ||
|
||
public abstract Object convertConditionValNum(ConditionValueExpression condition); | ||
public abstract Object convertConditionValNum(ConditionValueExpression condition, boolean applyDeMorgans); | ||
|
||
public abstract Object convertConditionValRe(ConditionValueExpression condition); | ||
public abstract Object convertConditionValRe(ConditionValueExpression condition, boolean applyDeMorgans); | ||
|
||
/* public abstract Object convertConditionValQueryExpr(ConditionValueExpression condition);*/ | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is the
applyDeMorgans
always false? do we even need it??There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
applyDeMorgans
starts off as false but we need it since we are recursively traversing the tree. It gets set to true (ie. we need to apply deMorgans) only if there is anAND
orOR
condition when it is an ancestor of aNOT
.Ex.
Ex.
Incorrect: NOT(A OR B) -> NOT(A AND exists:A OR B AND exists:B) -> NOT A OR exists:A AND NOT B OR exists:B
Correct: NOT(A OR B) -> NOT A AND NOT B -> NOT A AND exists:A AND NOT B AND exists:B