- 11 Nov 2024
- 20 Minutes to read
- Print
- PDF
YAML-based Plugins
- Updated on 11 Nov 2024
- 20 Minutes to read
- Print
- PDF
Traceable provides you the option to use YAML-based custom plugins for API security testing within the Traceable platform. You can define test cases, operators for mutating (manipulating) API requests, and asserting responses in these plugins. You can define these custom plugins in the Traceable platform.
A custom plugin written in YAML supports adding multiple test-cases for detecting the vulnerabilities you specify. The YAML format should contain the following sections:
Test Case — In this section, you must define the security concern (vulnerability type) that the specific test aims to detect. It also includes additional parameters, such as attack vector, attribute, and title that define the context for the test. For more information on test and custom vulnerability types, see Vulnerability Types.
Mutations — In this section of the test case, you must define how Traceable should modify the request parameters during testing. Traceable supports mutating all the request attributes, for example, URL, body, cookies, headers, tokens, etc. alongside mutation operators such as add, delete, modify, set, etc.
Assertions — In this section of the test case, you must define how Traceable should compare the API response with the target value or patterns to confirm the presence of a vulnerability. This section plays an important role to check whether the attack with the mutated request reveals a vulnerability. Through the assertion parameters, Traceable determines if the API is secure or insecure for a vulnerability type.
The following is a sample code snippet for writing a custom YAML plugin:
Note
The values in the code snippet are for reference purposes only.
YAML plugin support requires a minimum CLI version of 1.10.16 or above.
tests:
- title: "Test#1 - Example File Inclusion Test"
vector: "web_application" # Attack vector string: "web application" in this example
attribute: "original.http.request.body" # The API attribute being tested
timeoutInSeconds: 10 # Test timeout in seconds
errorExpected: false # No error expected if the attack succeeds
vulnerabilityType: # Vulnerability type mapping
name: "custom_file_inclusion_vuln"
shouldReportVulnerability: true
mutations: # API Request mutations for the attack
- action: MUTATION_SET # Type of mutation
description: "Test file inclusion by modifying file path"
key: "original.http.request.body.file_path" # Attribute being mutated
field:
kind: STRING # Data Type of attribute
value: "/etc/passwd" # Mutation value
assertions: # Response assertions to determine vulnerability
- lhs: "${mutated.http.response.code}" # Actual value
rhs: "200" # Expected value for successfully marking test as Passed
operator: MATCH_OPERATOR_EQUALS # Asseertion operator
key: "mutated.http.response.code" # API Attribute key being asserted on
description: "Check for successful file inclusion"
assertionType: IMMEDIATE
The following sections specify the description of various fields present in the above code, the mutations and assertions of a test, along with the operators that you can use in them.
Attributes convention
Attributes in a custom plugin are the configurable parameters that determine how the plugin should operate and process API requests and responses.
While the attributes starting with original.
correspond to the requests Traceable is receiving from you or that are being generated from other sources, the attributes starting with mutated.
represent the modified traffic from Traceable.
All attributes are stored in the form of their fully qualified name. For example, the authorization header is represented as original.http.request.header.authorization
in the original request and mutated.http.request.header.authorization
in the mutated request.
Mutation Function
The mutation function adds, modifies, and deletes specific parameters within API requests. The function contains the following parameters:
operator (String) — The type of operation to be performed.
key (String) — The key or attribute to be mutated.
value (Any) — The new value to replace the existing value. This parameter can contain any value, for example, none or an empty string (““).
Mutation operators
The following are the supported operators that you can use along with the mutation function while writing a custom plugin:
Operator | Description | Example |
---|---|---|
MUTATION_ADD | This operator adds a new key attribute with the specified value. If the key attribute already exists, it duplicates it. | Example:
The above example suffixes the URL with two query params ?id=100& id=50 to check parameter pollution. |
MUTATION_DELETE | This operator deletes an existing key attribute. | Example:
The above example removes the query param id from the API request. |
MUTATION_MODIFY | This operator modifies a key attribute if it exists; otherwise, it does nothing. | Example:
The above example updates the query param id with the value 100 if it exists; otherwise it ignores the instruction. |
MUTATION_SET | This operator sets the value of an existing key attribute or adds it if it does not exist. | Example:
The above example sets the query param id to 100 if it exists; otherwise it creates a query param id with the same value. |
MUTATION_REGEX_DELETE | This operator deletes all attributes that match the key/regular expression with value. | Example:
The above example deletes all query params ending with the string “amount”. |
MUTATION_REGEX_MODIFY | This operator modifies all attributes that match the key/regular expression with value. | Example:
The above example modifies the query params ending with the string “amount” with the value 100, if it exists; otherwise, it ignores the instruction. |
MUTATION_REGEX_SET | This operator sets all attributes that match the key/regular expression with value. | Example:
The above example sets the query params ending with the string “amount” with the value 100, if it exists; otherwise, it ignores the instruction. |
Assertion Function
The Assertion Function in YAML-based plugins is used to evaluate API responses for vulnerabilities by comparing specific values in the response to expected outcomes, with various operators available to define the conditions for a successful match. The following sections explain the various sub-functions and operators.
Logical Assertion Function
The logical assertion function is used to apply conditional operators (AND/OR) to a list of operations. The function contains the following parameters:
operator (String) — The logical operator used to combine multiple assertions. The default operator is OR; however, it can be set to AND.
assertions (List[Assertion]) — A list of assertion objects to be combined using the logical operator.
Vulnerable Logical Assertion Operators
The following are the supported operators that you can use along with the logical assertion function while writing a custom plugin:
Operator | Description |
---|---|
LOGICAL_OPERATOR_AND | All assertion items in the assertion list need to be VULN(True) for the return value to be VULN(True). |
LOGICAL_OPERATOR_OR | Any assertion item in the assertion list needs to be VULN(True) for the return value to be VULN(True). |
Assertion Create Function
Assertions are used to evaluate the scans’ responses for vulnerabilities. The function contains the following parameters:
key (String) — Used for display purposes as part of visualization on the UI. It is not used for any processing.
operator (String) — The match operator used for comparison.
lhs (String) — The mutated value for comparison.
rhs (String) — The original value for comparison.
Assertion operators
The following are the supported operators that you can use along with the assertion create function while writing a custom plugin:
Operator | Description |
---|---|
MATCH_OPERATOR_EQUALS | This operator checks whether the mutated value matches the original value. If it does, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the response code received from the mutated request matches the response code received from the original request. |
MATCH_OPERATOR_NOT_EQUALS | This operator checks whether the mutated value does not match the original value. If it does not, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if param1 received in the body of the response received for the mutated request does not match param1 in the body of the response received from the original request. |
MATCH_OPERATOR_MATCHES_REGEX | This operator checks whether the mutated value matches the regex. If it does, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the response code received for the mutated request matches the specified regular expression. |
MATCH_OPERATOR_NOT_MATCHES_REGEX | This operator checks whether the mutated value does not match the regex. If it does not, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the response code received for the mutated request does not match the specified regular expression. |
MATCH_OPERATOR_GREATER_THAN | This operator checks whether the mutated value is greater than the original value. If it is, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the time taken to receive a response to the mutated request takes longer than 100 ms. |
MATCH_OPERATOR_GREATER_THAN_EQUALS | This operator checks whether the mutated value is greater than or equal to the original value. If it is, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if param1 in the body of the response received for the mutated request has a value greater than or equal to 100. |
MATCH_OPERATOR_LESS_THAN | This operator checks whether the mutated value is less than the original value. If it is, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if param1 in the body of the response received for the mutated request has a value less than 100. |
MATCH_OPERATOR_LESS_THAN_EQUALS | This operator checks whether the mutated value is less than or equal to the original value. If it is, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if param1 in the body of the response received for the mutated request has a value less than or equal to 100. |
MATCH_OPERATOR_CONTAINS | This operator checks whether the mutated value contains the original value. If it does, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. It also supports various python data structures, such as list, set, and string. Example:
The above example evaluates to True if param1 in the body of the response received for the mutated request contains the key word “Unauthorized”. |
MATCH_OPERATOR_NOT_CONTAINS | This operator checks whether the mutated value does not contain the original value. If it does not, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. It also supports various python data structures, such as list, set, and string. Example:
The above example evaluates to True if the body of the response received for the mutated request does not contain the key word “Bad request”. |
MATCH_OPERATOR_IN | This operator checks whether the mutated value is present in the original value. If it is, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the message in the body of the response received for the mutated request includes either “Failed” or “Errored”. |
MATCH_OPERATOR_NOT_IN | This operator checks whether the mutated value is not present in the original value. If it is not, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the message in the body of the response received for the mutated request does not include either “Failed” or “Errored”. |
MATCH_OPERATOR_KEYS_EQUALS | This operator checks whether the mutated value is not present in the original value. If it is not, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the keys in the body of the response received for the mutated request has the same set of keys in the body of the response received for the original request - up to a depth of 5 for the JSON encoded tree |
MATCH_OPERATOR_KEYS_NOT_EQUALS | This operator checks whether the mutated value is not present in the original value. If it is not, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the keys in the body of the response received for the mutated request does not have the same set of keys in the body of the response received for the original request - up to a depth of 5 for the JSON encoded tree |
MATCH_OPERATOR_FUZZY_EQUALS | This operator checks whether the mutated and original values match up to the specified threshold. If they do, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the body of the response received for the mutated request matches (at least up to the threshold value of 80%) with the response received for the original request - up to a depth of 5 for the JSON encoded tree. |
MATCH_OPERATOR_FUZZY_NOT_EQUALS | This operator checks whether the mutated and original values do not match up to the specified threshold. If they do not, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the body of the response received for the mutated request does not match (at least up to the threshold value of 80%) with the response received for the original request - up to a depth of 5 for the JSON encoded tree. |
MATCH_OPERATOR_FUZZY_KEYS_EQUALS | This operator checks whether the mutated and original values are JSON/URL-encoded parseable and the keys match up to the specified threshold. If they do, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the keys in the body of the response received for the mutated request matches (at least up to the threshold value of 80%) with the keys in the body of the response received for the original request - up to a depth of 5 for the JSON encoded tree. |
MATCH_OPERATOR_FUZZY_KEYS_NOT_EQUALS | This operator checks whether the mutated and original values are JSON/URL-encoded parseable and the keys match up to the specified threshold. If they do, the assertion evaluates to False/Not Vulnerable; otherwise, it evaluates to True/Vulnerable. Example:
The above example evaluates to True if the keys in the body of the response received for the mutated request does not match (at least up to the threshold value of 80%) with the keys in the body of the response received for the original request - up to a depth of 5 for the JSON encoded tree. |
MATCH_OPERATOR_VALUES_DIFFERENCE | This operator checks if the absolute difference between the mutated and original value is a certain amount. Example:
The above example evaluates to True if the query param id of the mutated request differs from the response parameter id by a value of 100. |
MATCH_OPERATOR_VALUES_SEARCH | This operator searches for the original value in the mutated value. The mutated value can be a dictionary or a URL-encoded payload. The level specified in this operator signifies the max depth till which Traceable should look at in the tree structure like JSON. If the original value is found in the mutated one, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the body of the response received for the mutated request contains the value 15 - up to the depth 5 for the JSON encoded tree. |
MATCH_OPERATOR_VALUES_NOT_SEARCH | This operator searches for the original value in the mutated value. The mutated value can be a dictionary or a URL-encoded payload. The level specified in this operator signifies the max depth till which Traceable should look at in the tree structure like JSON. If the original value is not found in the mutated one, the assertion evaluates to True/Vulnerable; otherwise, it evaluates to False/Not Vulnerable. Example:
The above example evaluates to True if the body of the response received for the mutated request does not contain the query param id of the original request - up to a depth of 5 for the JSON encoded tree. |
MATCH_OPERATOR_REGEXLOOKUP_EQUALS | This operator works in two steps:
Example:
The above example evaluates to True if all parameters that match the specified regex in response to the mutated request contains the value 15. |
MATCH_OPERATOR_REGEXLOOKUP_NOT_EQUALS | This operator works in two steps:
Example:
The above example evaluates to True if all parameters that match the specified regex in response to the mutated request does not contain the value 15. |
MATCH_OPERATOR_REGEXLOOKUP_MATCHES_REGEX | This operator works in two steps:
Example:
The above example evaluates to True if all parameters that match the specified regex in response to the mutated request contains a value of that matches the regex ("141[a-z0-9]{1,10}411"). |
MATCH_OPERATOR_REGEXLOOKUP_NOT_MATCHES_REGEX | This operator works in two steps:
Example:
The above example evaluates to True if all parameters that match the specified regex in response to the mutated request does not contain a value of that matches the regex ("141[a-z0-9]{1,10}411"). |
MATCH_OPERATOR_ALWAYS_TRUE | This operator always returns True/Vulnerable. It is mostly useful when you are writing plugins and want to test dummy assertions. Example:
|
MATCH_OPERATOR_ALWAYS_FALSE | This operator always returns False/Not Vulnerable. It is mostly useful when you are writing plugins and want to test dummy assertions. Example:
|
MATCH_OPERATOR_COLLABORATOR_LOOKUP_CONTAINS | This operator is used for SSRF-based scans, where if the application reaches out to Traceable collaborator, it looks out for the presence of test id in the payload received by the collaborator. Example:
The above example evaluates to True if the payload (from the application) received by the collaborator contains the test id. |
MATCH_OPERATOR_RAW | This operator executes raw lambda code supplying it with mutated and original values. If lambda returns True, it is marked as Vulnerable, else Not Vulnerable. Example:
|