Skip to content

Commit a9ef474

Browse files
jowg-amazongithub-actions[bot]
authored andcommitted
Fix get mappings view API incorrectly returning ecs path (#867)
* add logic and integ tests to not add duplicate to log-types-config index Signed-off-by: Joanne Wang <[email protected]> * change naming for existingFieldMapping and change contains to equals Signed-off-by: Joanne Wang <[email protected]> --------- Signed-off-by: Joanne Wang <[email protected]> (cherry picked from commit 25f6c50)
1 parent 71d9c91 commit a9ef474

File tree

3 files changed

+92
-6
lines changed

3 files changed

+92
-6
lines changed

src/main/java/org/opensearch/securityanalytics/logtype/LogTypeService.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -349,15 +349,26 @@ private List<FieldMappingDoc> mergeFieldMappings(List<FieldMappingDoc> existingF
349349
List<FieldMappingDoc> newFieldMappings = new ArrayList<>();
350350
fieldMappingDocs.forEach( newFieldMapping -> {
351351
Optional<FieldMappingDoc> foundFieldMappingDoc = Optional.empty();
352-
for (FieldMappingDoc e: existingFieldMappings) {
353-
if (e.getRawField().equals(newFieldMapping.getRawField())) {
352+
for (FieldMappingDoc existingFieldMapping: existingFieldMappings) {
353+
if (existingFieldMapping.getRawField().equals(newFieldMapping.getRawField())) {
354354
if ((
355-
e.get(defaultSchemaField) != null && newFieldMapping.get(defaultSchemaField) != null &&
356-
e.get(defaultSchemaField).equals(newFieldMapping.get(defaultSchemaField))
355+
existingFieldMapping.get(defaultSchemaField) != null && newFieldMapping.get(defaultSchemaField) != null &&
356+
existingFieldMapping.get(defaultSchemaField).equals(newFieldMapping.get(defaultSchemaField))
357357
) || (
358-
e.get(defaultSchemaField) == null && newFieldMapping.get(defaultSchemaField) == null
358+
existingFieldMapping.get(defaultSchemaField) == null && newFieldMapping.get(defaultSchemaField) == null
359359
)) {
360-
foundFieldMappingDoc = Optional.of(e);
360+
foundFieldMappingDoc = Optional.of(existingFieldMapping);
361+
}
362+
// Grabs the right side of the ID with "|" as the delimiter if present representing the ecs field from predefined mappings
363+
// Additional check to see if raw field path + log type combination is already in existingFieldMappings so a new one is not indexed
364+
} else {
365+
String id = existingFieldMapping.getId();
366+
int indexOfPipe = id.indexOf("|");
367+
if (indexOfPipe != -1) {
368+
String ecsIdField = id.substring(indexOfPipe + 1);
369+
if (ecsIdField.equals(newFieldMapping.getRawField()) && existingFieldMapping.getLogTypes().containsAll(newFieldMapping.getLogTypes())) {
370+
foundFieldMappingDoc = Optional.of(existingFieldMapping);
371+
}
361372
}
362373
}
363374
}

src/test/java/org/opensearch/securityanalytics/TestHelpers.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,35 @@ public static String randomRule() {
259259
"level: high";
260260
}
261261

262+
public static String randomRuleWithRawField() {
263+
return "title: Remote Encrypting File System Abuse\n" +
264+
"id: 5f92fff9-82e2-48eb-8fc1-8b133556a551\n" +
265+
"description: Detects remote RPC calls to possibly abuse remote encryption service via MS-EFSR\n" +
266+
"references:\n" +
267+
" - https://attack.mitre.org/tactics/TA0008/\n" +
268+
" - https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-36942\n" +
269+
" - https://github.com/jsecurity101/MSRPC-to-ATTACK/blob/main/documents/MS-EFSR.md\n" +
270+
" - https://github.com/zeronetworks/rpcfirewall\n" +
271+
" - https://zeronetworks.com/blog/stopping_lateral_movement_via_the_rpc_firewall/\n" +
272+
"tags:\n" +
273+
" - attack.defense_evasion\n" +
274+
"status: experimental\n" +
275+
"author: Sagie Dulce, Dekel Paz\n" +
276+
"date: 2022/01/01\n" +
277+
"modified: 2022/01/01\n" +
278+
"logsource:\n" +
279+
" product: rpc_firewall\n" +
280+
" category: application\n" +
281+
" definition: 'Requirements: install and apply the RPC Firewall to all processes with \"audit:true action:block uuid:df1941c5-fe89-4e79-bf10-463657acf44d or c681d488-d850-11d0-8c52-00c04fd90f7e'\n" +
282+
"detection:\n" +
283+
" selection:\n" +
284+
" eventName: testinghere\n" +
285+
" condition: selection\n" +
286+
"falsepositives:\n" +
287+
" - Legitimate usage of remote file encryption\n" +
288+
"level: high";
289+
}
290+
262291
public static String randomRuleWithNotCondition() {
263292
return "title: Remote Encrypting File System Abuse\n" +
264293
"id: 5f92fff9-82e2-48eb-8fc1-8b133556a551\n" +

src/test/java/org/opensearch/securityanalytics/resthandler/OCSFDetectorRestApiIT.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,52 @@ public void testOCSFCloudtrailGetMappingsViewApi() throws IOException {
439439
assertEquals(24, unmappedFieldAliases.size());
440440
}
441441

442+
@SuppressWarnings("unchecked")
443+
public void testOCSFCloudtrailGetMappingsViewApiWithCustomRule() throws IOException {
444+
String index = createTestIndex("cloudtrail", ocsfCloudtrailMappings());
445+
446+
Request request = new Request("GET", SecurityAnalyticsPlugin.MAPPINGS_VIEW_BASE_URI);
447+
// both req params and req body are supported
448+
request.addParameter("index_name", index);
449+
request.addParameter("rule_topic", "cloudtrail");
450+
Response response = client().performRequest(request);
451+
assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
452+
Map<String, Object> respMap = responseAsMap(response);
453+
// Verify alias mappings
454+
Map<String, Object> props = (Map<String, Object>) respMap.get("properties");
455+
Assert.assertEquals(18, props.size());
456+
// Verify unmapped index fields
457+
List<String> unmappedIndexFields = (List<String>) respMap.get("unmapped_index_fields");
458+
assertEquals(20, unmappedIndexFields.size());
459+
// Verify unmapped field aliases
460+
List<String> unmappedFieldAliases = (List<String>) respMap.get("unmapped_field_aliases");
461+
assertEquals(25, unmappedFieldAliases.size());
462+
463+
// create a cloudtrail rule with a raw field
464+
String rule = randomRuleWithRawField();
465+
Response createResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.RULE_BASE_URI, Collections.singletonMap("category", "cloudtrail"),
466+
new StringEntity(rule), new BasicHeader("Content-Type", "application/json"));
467+
Assert.assertEquals("Create rule failed", RestStatus.CREATED, restStatus(createResponse));
468+
469+
// check the mapping view API again to ensure it's the same after rule is created
470+
Response response2 = client().performRequest(request);
471+
assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
472+
Map<String, Object> respMap2 = responseAsMap(response2);
473+
// Verify alias mappings
474+
Map<String, Object> props2 = (Map<String, Object>) respMap2.get("properties");
475+
Assert.assertEquals(18, props2.size());
476+
// Verify unmapped index fields
477+
List<String> unmappedIndexFields2 = (List<String>) respMap2.get("unmapped_index_fields");
478+
assertEquals(20, unmappedIndexFields2.size());
479+
// Verify unmapped field aliases
480+
List<String> unmappedFieldAliases2 = (List<String>) respMap2.get("unmapped_field_aliases");
481+
assertEquals(25, unmappedFieldAliases2.size());
482+
// Verify that first response and second response are the same after rule was indexed
483+
assertEquals(props, props2);
484+
assertEquals(unmappedIndexFields, unmappedIndexFields2);
485+
assertEquals(unmappedFieldAliases, unmappedFieldAliases2);
486+
}
487+
442488
@SuppressWarnings("unchecked")
443489
public void testOCSFVpcflowGetMappingsViewApi() throws IOException {
444490
String index = createTestIndex("vpcflow", ocsfVpcflowMappings());

0 commit comments

Comments
 (0)