IMPORTANT: This document assumes you already have an Organization within the Contrast UI with Serverless enabled: Contrast Serverless Application Security.
Objective
To provide steps to configure the Webhook integration for Contrast Serverless Application Security.
Process
1. Getting Organization Authentication Details
Log in with Admin account for your serverless organization and get Organization UUID,
API key
and Authorization Header
from the User Settings page.
Organization UUID: {orgUuid}
Organization API Key: {API-Key}
Admin User Authorization Header: {Authorization}
Your Keys
2. Creating Serverless Generic Webhook
At the moment of writing this document, the UI work to create Serverless Generic Webhook was not ready. The only way to create a Serverless Generic Webhook is via API.
-
serverless_account_ids
andserverless_rule_severities
attributes in the Request body can be empty which means that this webhook will match any new vulnerability serverless event received. -
Use the
Authorization
andAPI-Key header
values obtained in the previous section.
Request
// POST http://<YourContrastURL>/Contrast/api/ng/{orgUuid}/webhooks
curl --request POST 'http://<YourContrastURL>/Contrast/api/ng/{orgUuid}/webhooks' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: {Authorization}' \
--header 'API-Key: {API-Key}' \
--data-raw '{
"name":"Serverless Generic Webhook",
"url":"https://ent3azpoyfw7b.x.pipedream.net",
"payload": "{\n \"severity\": $Severity,\n \"status\": $Status,\n \"scanId\": $ScanId,\n \"resourceId\": $ResourceId,\n \"resultFirstTimeFound\": $ResultFirstTimeFound,\n \"resultLastTimeSeen\": $ResultLastTimeSeen,\n \"resultId\": $ResultId,\n \"resultTitle\": $ResultTitle,\n \"resultCategory\": $ResultCategory,\n \"resultEvidence\": $ResultEvidence,\n \"resultImpact\": $ResultImpact,\n \"resultRemediation\": $ResultRemediation,\n \"resultDescription\": $ResultDescription,\n \"accountId\": $AccountId,\n \"accountName\": $AccountName,\n \"region\": $Region,\n \"provider\": $Provider\n}",
"use_html":true,
"send_failure_notification":true,
"all_applications":true,
"applications":[],
"product":"SERVERLESS",
"serverless_account_ids":["account-1"],
"serverless_rule_severities":["CRITICAL"],
"type":"GENERIC"
}'
Response
{
"success": true,
"messages": [
"Webhook configuration connected successfully"
]
}
3. Getting Serverless User Authentication Details
-
Use the
Organization UUID, Authorization
andAPI-Key
values obtained in the Getting Organization Details section
Request
// GET http://<YourContrastURL>/Contrast/api/ng/organizations/{orgUuid}/serverless/keys
curl --request GET 'http://<YourContrastURL>/Contrast/api/ng/organizations/{orgUuid}/serverless/keys' \
--header 'Content-Type: application/json' \
--header 'Authorization: {Authorization}' \
--header 'API-Key: {API-Key}'
Response
{
"success": true,
"messages": [
"Serverless service key loaded successfully"
],
"service_key": "HQNGP773Q5QA20I3",
"user_uid": "serverless_8d734fa9-289b-48fa-89df-035724dee5a4@ServerlessGenericWebhookNotifications"
}
4. Sending Serverless Vulnerability Events Requests
-
Use the
Organization UUID
value obtained in the Getting Organization Details section -
Authorization
header will bebase64(user_uid:service_key)
from Getting Organization Details section-
base64(serverless_8d734fa9-289b-48fa-89df-035724dee5a4@ServerlessGenericWebhookNotifications:HQNGP773Q5QA20I3)
-
Request
// POST http://<YourContrastURL>/Contrast/integrations/v1.0/organizations/{orgUuid}/notifications/vulnerabilities
curl --request POST 'http://<YourContrastURL>/Contrast/integrations/v1.0/organizations/{orgUuid}/notifications/vulnerabilities' \
--header 'Content-Type: application/json' \
--header 'Authorization: {Authorization}' \
--header 'API-Key: {API-Key}' \
--data-raw '{
"eventType": "NEW_RESULT",
"sarifRun": {
"tool": {
"driver": {
"name": "CloudEssence",
"rules": [
{
"id": "LFI",
"name": "LFI",
"guid": "bf1c73ba-3d5a-4894-b880-1becaab566ad",
"messageStrings": {
"title": {
"text": "Local File Inclusion (LFI)"
}
}
}
],
"taxa": [
{
"id": "Exploit",
"name": "Exploit",
"guid": "e0da8b7d-5b3f-4eac-ba57-bbb791ece6f0"
}
]
}
},
"results": [
{
"ruleId": "LFI",
"ruleIndex": 0,
"rule": {
"guid": "bf1c73ba-3d5a-4894-b880-1becaab566ad"
},
"message": {
"id": "title"
},
"locations": [
{
"id": 0,
"message": {
"text": "The File Inclusion vulnerability allows an attacker to include a file, usually exploiting a '\''dynamic file inclusion'\'' mechanisms implemented in the target application. The vulnerability occurs due to the use of user-supplied input without proper validation. A successful attack can lead into reading the Function'\''s source code as well as other sensitive files in the environment."
}
}
],
"relatedLocations": [
{
"id": 1,
"message": {
"text": "JSON"
},
"physicalLocation": {
"artifactLocation": {
"uri": "unknown"
},
"region": {
"message": {
"text": "correctly permissive policy in json"
},
"snippet": {
"rendered": {
"text": "{\"correctly permissive\" : \"policy\"}"
}
}
}
}
},
{
"id": 2,
"message": {
"text": "YAML"
},
"physicalLocation": {
"artifactLocation": {
"uri": "unknown"
},
"region": {
"message": {
"text": "correctly permissive policy in yaml"
},
"snippet": {
"rendered": {
"text": "{\"correctly permissive\" : \"policy\"}"
}
}
}
}
},
{
"id": 3,
"message": {
"text": "TERRAFORM"
},
"physicalLocation": {
"artifactLocation": {
"uri": "unknown"
},
"region": {
"message": {
"text": "correctly permissive policy in terraform"
},
"snippet": {
"rendered": {
"text": "{\"correctly permissive\" : \"policy\"}"
}
}
}
}
}
],
"codeFlows": [
{
"message": {
"text": "cloudessence has identified evidence in the function logs (CWL) that indicates of was successfull exploit"
},
"threadFlows": [
{
"locations": [
{
"location": {
"physicalLocation": {
"artifactLocation": {
"uri": "unknown"
},
"region": {
"snippet": {
"rendered": {
"text": "payload: ../../../etc/passwd\nrequestId: 3fa6d034-242f-4aa6-b125-19a2d9bc9132\nlogGroup: /aws/lambda/DVSA-ADMIN-SHELL\nlogStream: 2021/07/16/[$LATEST]0ab88791946445889df3d95465a1f173"
}
}
}
}
}
}
]
}
]
}
],
"guid": "a59e4ada-8899-45f1-bb68-a1595558a7fc",
"provenance": {
"firstDetectionTimeUtc": "2021-07-16T16:13:51.419002Z",
"lastDetectionTimeUtc": "2021-07-16T16:14:53.420642Z"
},
"properties": {
"security-severity": 9.0,
"contrastSeverity": "MEDIUM",
"category": "EXPLOITS",
"status": "REPORTED",
"additionalExplanation": {
"recommendation": {
"text": "The most effective solution to eliminate file inclusion vulnerabilities is to avoid passing user-submitted input to any filesystem. If this is not possible the application can maintain an allow list of files, that may be included by the page, and then use an identifier (for example the index number) to access to the selected file. Any request containing an invalid identifier has to be rejected, in this way there is no attack surface for malicious users to manipulate the path.",
"properties": {
"title": "Remediation"
}
},
"impact": {
"text": "execute-api,ses,logs,cloudformation,cloudwatch,ec2,kms,iam,lambda,states,tag,xray",
"properties": {
"title": "Impact"
}
}
},
"additionalIdentificationInformation": {
"function": {
"text": "arn:aws:lambda:us-east-1:402181209224:function:DVSA-ADMIN-SHELL"
},
"accountId": {
"text": "402181209224"
},
"accountName": {
"text": "accountNameDemo"
},
"region": {
"text": "us-east-1"
},
"provider": {
"text": "aws"
},
"scanId": {
"text": "402181209224#0abb6825-060c-4627-ac77-742258cc335e"
}
},
"matching": {
"accountId": "account-1",
"severity": "CRITICAL"
}
}
}
]
}
}'
Response
[
{
"requestUuid": "8bd35b15-b1ae-4231-9402-71524dc4b1cc",
"resultGuid": "a59e4ada-8899-45f1-bb68-a1595558a7fc",
"requestStatus": "IN_PROGRESS"
}
]
5. Checking Serverless Vulnerability Events Request status
To check the status of the request, you can use the field requestUuid
(8bd35b15-b1ae-4231-9402-71524dc4b1cc
) from the Sending Serverless Vulnerability Events Requests section
Check request status
// GET 'http://<YourContrastURL>/Contrast/integrations/v1.0/organizations/{orgUuid}/notifications/requests/{requestUuid}'
curl --request GET 'http://<YourContrastURL>/Contrast/integrations/v1.0/organizations/{orgUuid}/notifications/requests/{requestUuid}' \
--header 'Content-Type: application/json' \
--header 'Authorization: {Authorization}' \
--header 'API-Key: {API-Key}'
Response
{
"requestUuid": "8bd35b15-b1ae-4231-9402-71524dc4b1cc",
"resultGuid": "a59e4ada-8899-45f1-bb68-a1595558a7fc",
"requestStatus": "COMPLETED",
"integrationStatuses": [
{
"integrationId": 7,
"integrationType": "GENERIC",
"status": "SUCCESS",
"responseCode": 200,
"resultGuid": "a59e4ada-8899-45f1-bb68-a1595558a7fc",
"matchingCriteria": {
"product": "SERVERLESS",
"matchingConditions": {
"severity": [
"CRITICAL"
],
"accountId": [
"account-1"
]
}
}
}
]
}