VT Development

VT Development for OpenVAS Scanner

This page collects hints and guides for developing vulnerability tests for the OpenVAS Scanner.
It essentially means to write scripts in NASL language.

Questions

If you have any questions to VT Development please start a new thread for each question and link back to this topic if the question is related to this thread.

How to start

The best start is to learn from existing NASL scripts. The content of the Greenbone Community Feed contains the scripts in source code form, see in your local setup under /var/lib/openvas/plugins (the actual path depends on how you set up your GVM Source Edition). There is also a
template.nasl (7.3 KB)maintained containing some source code documentation. (note- updated template added December 06, 2021)

You will find other developers for questions and discussions in the Vulnerability Tests Category.

License requirements: Please be aware that most of the GCF content is licensed under GNU GPLv2+. If you distribute your works under another license, this might create legal conflicts.

Golden Rules

This is a collection assembled over time from lessons learned.

  • Avoid writing your own product detection inside a vulnerability check.

    Rationale: We separate product detection from actual vulnerability check where ever possible. You will find various detection scripts in the OpenVAS Scanner repository and should check whether there is already one you can use. Usually these scripts have a "detect* in their filename and you can search for other VTs on how to use it.

    In case there is no detection yet, consider writing a new detection script so it can be re-used in the future. In doubt how to do that or whether it makes sense in some special cases, just get in contact with the developers at Vulnerability Tests Category.

  • Use product detection result in proper way (example: gb_openssl_dos_vuln_lin_jun09.nasl).

    You can do so by doing the following:

    • You will need these includes:

      include("version_func.inc");
      include("host_details.inc");
      
    • Add the dependency to the detection:

      script_dependencies("gb_openssl_detect_lin.nasl");
      
    • Add a key requirement to ensure the scripts doesn’t run in unnecessary situations like:

      script_mandatory_keys("OpenSSL/Linux/Ver");
      
    • Use get_app_version() to work with the version number:

      NOTE: The usage of getting product information from a Detection-VT is currently subject to change, this part will be updated once the rework is finished.

      ver = get_app_version(cpe:"cpe:/a:openssl:openssl");
      

    Rationale: This enables product detection references inside vulnerability report.

  • Don’t add any port scanner as dependency.

    Rationale: Since the user should decide on his/her own which scanner to use, this could lead to situations where more then one port scanner is concurrently executed.

  • Don’t use toolcheck.nasl as dependency if your VT does not directly(!) use one of the tools listed in toolcheck.nasl.

    Rationale: It’s simply useless. Though it has no effect it creates a wrong impression when reading the code.

  • If you use script_mandatory_keys("login/SSH/success"); then you also need to apply script_dependencies("ssh_authorization.nasl");.

    Rationale: The key will only be set when ssh_authorization.nasl is executed.

  • Use script_mandatory_keys() (also instead of script_require_keys()) if the script does not do anything sensible if a key is not available.

    For example: Use script_mandatory_keys("MyApp/Linux/Version"); if your script starts like this with a very early exit():

    include("version_func.inc");
    
    myappVer = get_kb_item("MyApp/Linux/Version");
    if(!myappVer){
      exit(0);
    }
    ...
    

    Rationale: Using script_mandatory_keys will prevent that the VT is executed at all; even if optimize_tests setting is disabled. This improves the scan performance.

  • Don’t use UTF-8 encoding for your VT. For the time being (as long as old scanner protocol OTP is supported), the encoding to be used for VTs is ISO-8859-1.

    Rationale: OTP is not encoding-safe.

  • Place a newly developed VT into the subdirectory named as the current year (e.g. 2018/). Important exceptions are:

    • VTs that are used as dependencies for others. This covers for example all detection VTs.
    • Any include files.

Which OID to apply

If you develop your own VTs, please use the OID range 1.3.6.1.4.1.25623.1.0.30NNNN which is reserved for personal use. This way, you won’t get in conflict with any OID from the Greenbone feeds.

Note that the above pattern means to start with 300000 and not with 300.

How to write a product detection VT

It is very important for the VT Feed that we separate the work of the detection a certain product from actual vulnerability evaluation. The actual detection VTs should result a CPE code for the product. If none is available yet, it needs to be registered with NIST. Also it is very important to explain the method how the product was detected (description) and where it was detected (result).

A good example for a authenticated product detection is gb_openssl_dectect_lin.nasl. Watch out for these elements:

  • script_tag(name:"detection", value:"..."): Always set the type of detection. This could be “executable version check” or “remote banner” and we can agree on further if needed.

  • script_name("..."): Use a simple direct name like "“OpenSSL Version Detection (Linux)”.

  • script_description("..."): Explain how the product is detected. For example:

    "Detection of installed version of OpenSSL.

    The script logs in via ssh, searches for executable ‘openssl’ and queries the found executables via command line option ‘version’."

  • script_family("Product detection"): apply this family.

  • Necessary include’s:

    include("cpe.inc");
    include("host_details.inc");
    
  • Build a CPE and register the product:

    NOTE: The product registration method is currently subject to change, this part will be updated once the rework is finished.

    cpe = build_cpe(value:sslVer[1], exp:"^([0-9.]+[a-z0-9]*)", base:"cpe:/a:openssl:openssl:");
    if(!isnull(cpe))
      register_product(cpe:cpe, location:executableFile);
    
  • log_message(): Always send a log message with as detailed and helpful information as possible. Here is a good example for the OpenSSL local detection:

    log_message(data:
      build_detection_report(app:"OpenSSL",
      version: sslVer[1],
      install: executableFile,
      cpe: cpe,
      concluded:sslVer[max_index(sslVer)-1]),
      port:0);
    
  • Finally set a key to help scan scheduler like this example:

    set_kb_item(name:"openssl/detected", value:TRUE);
    

How to write a policy VT

A policy VT does not search for a documented general vulnerability. It rather tests a target system for properties that a user defines.

In order to allow the user to configure the severity level, a policy is split into 4 parts. For the following example you will find a reference implementation with NAME=file_checksums:

  • Policy/policy_NAME.nasl: The main routine that offers and manages the user preferences. Furthermore it will execute the policy checks and store the results in the internal knowledge base. This VT will not report anything except “error” in case it fails fundamentally.
  • Policy/policy_NAME_violation.nasl: Creates a log-result for all policy violations.
  • Policy/policy_NAME_ok.nasl: Creates a log-result for all policies that were met.
  • Policy/policy_NAME_error.nasl: Creates a log-result for all policies where an error occurred while trying to check. For example if a file could not be accessed due to permission problems.

The routines _violation, _ok and _error report log level. The user can define appropriate Overrides in the Manager and assign an own severity as felt appropriate. Those Overrides are typically configured to be applied generally for all tasks and/or IPs.

Developers should implement their policies as close to the reference example as possible, especially in terms of naming scheme and code structure.

How to assign a CVSS to a VT

Any new VT must be provided with a CVSS Score and a CVSS Base Vector.

Common Vulnerability Scoring System (CVSS) is an industry standard for assessing the severity of computer system security vulnerabilities. CVSS is composed of three metric groups:

  1. Base Metrics
  2. Temporal Metric Group
  3. Environmental Metric Group

For VT development purposes, we only use Base Metrics. Where linked to other security information (for example CVE), these are automatically updated over time. The information is captured in the following tags in VT:

script_tag(name:"cvss_base", value:"x.x");
script_tag(name:"cvss_base_vector", value:"AV:N/AC:M/Au:N/C:P/I:C/A:C");

Follow these steps for assigning a CVSS:

  1. If there is a CVE for which VT is being developed, take the CVSS score already computed from NVD (National Vulnerability Database), http://web.nvd.nist.gov/view/vuln/search.

    In case multiple CVEs are referenced, pick the one with the Maximum CVSS Base and take the corresponding CVSS Base Vector.

    It is not allowed to apply any other CVSS in case at least one CVE is referenced that offers a CVSS. In case author likes to apply another CVSS, a second VT should be added that has no CVE reference and a CVSS of its own. However, the better approach is to submit a rationale to NIST if you think the CVSS is wrong for the respective vulnerability.

  2. If there is a CVE for which VT is being developed and if CVSS is not yet available at NVD, manually compute the CVSS score based on the guideline described below.

  3. If there is non-CVE vulnerability reference for which VT is being developed, manually compute the CVSS score based on the guidelines described below.

Scoring Guidelines

Base score is a score in the range of 0.0-10.0 at steps of 0.1. The attributes for computing CVSS Base Score are:

  1. Access Vector

    The metric reflects how the vulnerability is exploited. Possible values are:

    • Local (L): local system, shell account
    • Adjacent Network (A): Attack is from an adjacent network
    • Network (N): Through network
  2. Access Complexity

    Measures the complexity of the attack required to exploit the vulnerability. Possible values are:

    • High (H): If it is too complex to perform an attack. For example, not a default configuration race condition
    • Medium (M): Some kind of privilege is required, non-default setting
    • Low (L): easy to exploit
  3. Authentication

    Measures the number of times an attacker must authenticate to a target in order to exploit. Possible values are:

    • Multiple (M): multiple authentication is required
    • Single (S): one instance of authentication is required
    • None (N): No authentication is required
  4. Confidentiality

    Measures the impact on confidentiality of a successfully exploited vulnerability. Possible values are:

    • None (N)
    • Partial (P)
    • Complete (C)
  5. Integrity

    Measures the impact to integrity of a successfully exploited vulnerability. Possible values are:

    • None (N)
    • Partial (P)
    • Complete (C)
  6. Availability

    Measures the impact to availability of a successfully exploited vulnerability. Possible values are:

    • None (N)
    • Partial (P)
    • Complete (C)

Base Metrics: AV:[L,A,N]/AC:[H,M,L]/Au:[M,S,N]/C:[N,P,C]/I:[N,P,C]/A:[N,P,C]

The following tips can be applied while scoring:

  • Consider the direct impact a vulnerability will have on the target

  • If there are multiple vulnerabilities VT is addressing, for scoring purposes for each of the above attributes, consider the vulnerability which will have high impact on the target (the one that yields high score)

  • If multiple options can be selected for each attribute, consider the one that will have high impact on the target.

  • In general, the following Confidentiality, Integrity and Availability values can be applied for different type of vulnerability.

    Denial of Service:

    1. Confidentiality is None (N)
    2. Integrity is None (N)
    3. Availability is either Partial (P) or Complete (C)

    Buffer overflow vulnerability:

    1. Confidentiality is Partial (P) or Complete (C)
    2. Integrity is Partial (P) or Complete (C)
    3. Availability is Partial (P) or Complete (C)

    Format string vulnerability:

    1. Confidentiality is Partial (P) or Complete (C)
    2. Integrity is Partial (P) or Complete (C)
    3. Availability is Partial (P) or Complete (C)

    Cross-site scripting vulnerability:

    1. Confidentiality is None (N)
    2. Integrity is Partial (P) or Complete (C)
    3. Availability is None (N)

    SQL Injection vulnerability:

    1. Confidentiality is Partial (P ) or Complete (C)
    2. Integrity is Partial (P) or Complete (C)
    3. Availability is Partial (P) or Complete (C)

    Directory traversal vulnerability:

    1. Confidentiality is Partial (P) or Complete (C)
    2. Integrity is None (N)
    3. Availability is None (N)

    File inclusion vulnerability:

    1. Confidentiality is Partial (P) or Complete (C)
    2. Integrity is Partial (P) or Complete (C)
    3. Availability is Partial (P) or Complete (C)

    Command execution vulnerability:

    1. Confidentiality is Partial (P) or Complete (C)
    2. Integrity is Partial (P) or Complete (C)
    3. Availability is Partial (P) or Complete (C)

    Information disclosure vulnerability:

    1. Confidentiality is Partial (P) or Complete (C)
    2. Integrity is None (N)
    3. Availability is None (N)

    Spoofing:

    1. Confidentiality is Partial (P) or Complete (C)
    2. Integrity is None (N)
    3. Availability is None (N)

    Session Hijacking:

    1. Confidentiality is Partial (P) or Complete (C)
    2. Integrity is None (N)
    3. Availability is None (N)

    Cross-site request forgery:

    1. Confidentiality is Partial (P) or Complete (C)
    2. Integrity is None (N)
    3. Availability is None (N)

    Code execution:

    1. Confidentiality is Partial (P) or Complete (C)
    2. Integrity is Partial (P) or Complete (C)
    3. Availability is Partial (P) or Complete (C)

    The decision on whether to choose Partial (P) or Complete (C) is based on how much impact it’ll have on the target.

How to score

Once the values are chosen for each of the CVSS attributes, apply those values to CVSS Calculator program available at:

Common Vulnerability Scoring System Version 2 Calculator

References

  1. CVSS Home page
  2. CVSS Guide
  3. CVSS v2 Calculator at NVD of NIST
  4. CVSS v2 Calculator at Greenbone SecInfo

How to deprecate a VT

In some (rare) situations it might be necessary to deprecate a VT so that it is not executed anymore even if selected in a Scan-Config.

Simply removing it from the Feed is a sub-optimal solution because older Scan-Result will reference it and users can not view details anymore, not at least that it has been deprecated meanwhile.

Therefore this procedure is recommended for a deprecation:

  1. Update the description to inform that is is being deprecated and explain the reason why it has been deprecated.

    In case the VT was replaced by another one, name this VT and its OID. For example: “This VT has been replaced by VT “THE-VT Development” (OID: THE-FULL-OID).”

  2. Add the deprecation tag: script_tag(name:"deprecated", value:TRUE);

  3. Add an early exit(66);. Of course this must be after the description block. The exit code 66 marks the VT as deprecated to the scanner.

How to handle references to CVEs that are marked REJECTED

It may happen that a CVE is marked REJECTED over time but already used as a reference in a VT.

In this case the following procedure should be applied:

  • In case other (not rejected) CVEs are present as references: Remove the CVE reference.

  • In case it is the only CVE reference: Remove the CVE reference. Then evaluate whether the VT creates a helpful log information for the user or collects helpful information for other VTs.

    If so, then make the VT a log-class VT. Else deprecate the VT.

How to handle VTs with “no solution” for the user

It happens that for a vulnerability there is no solution for the user yet. This usually is the case when the respective weakness was only recently discovered. Of course a special solution can be a workaround or even disabling a service, but no known patch or vendor update is available to actually close the attack vector.

In the case no solution is available at time of writing the respective tag should contain this sentence (dd is the day, mmmmmmmm the month as a word, yyyy is the year; ‘th’ is ‘st’, ‘nd’ or ‘rd’ where appropriate):

No known solution is available as of ddth mmmmmmmm, yyyy. Information regarding this issue will be updated once solution details are available.

Next, the solution_type must be set to NoneAvailable.

After some time, solutions get available. But for some vulnerabilities solutions are never worked out for a particular software release.

For updating the “no solution” information the following guide should be applied (if getting aware of a solution, this can and should be applied anytime, independent of the described schedule):

After one month after creation of the VT, the solution availability must be re-checked and if still no solution is available, the “No known solution …” should be updated with the current date.

After 6 month after creation of the VT, the same must be done like after one month.

If no solution becomes available for over 12 month after release of the VT, the phrase “No known solution …” in the tag “solution” must be replaced by:

No known solution was made available for at least one year since the disclosure of this vulnerability. Likely none will be provided anymore. General solution options are to upgrade to a newer release, disable respective features, remove the product or replace the product by another one.

Also, the solution_type tag should be set to WillNotFix.

And in case there is a work around:

No known solution was made available for at least one year since the disclosure of this vulnerability. Likely none will be provided anymore. General solution options are to upgrade to a newer release, disable respective features, remove the product or replace the product by another one.

A workaround is to …

There might be special cases where it is known from the beginning that no solution will be provided by the Vendor (e.g. the product is EOL, the vendor states that no fix will be provided, …). For such situations the following solution text should be used:

No solution was made available by the vendor. General solution options are to upgrade to a newer release, disable respective features, remove the product or replace the product by another one.

Also, the solution_type tag should be set to WillNotFix.

And in case additional information is provided by the vendor:

No solution was made available by the vendor. General solution options are to upgrade to a newer release, disable respective features, remove the product or replace the product by another one.

Note: The product has reached its end-of-life.

How to assign a QoD to a VT

The QoD is a value between 0% and 100% describing the reliability of the executed vulnerability detection or product detection.

One of the main reasons to introduce this concept was to handle the challenge of potential vulnerabilities properly. The goal was to keep such in the results database but only visible on demand.

While the QoD range allows to express the quality pretty refined, in fact most of the test routines use a standard methodology. Therefore the QoD Types were introduced of which each is associated with a QoD value. The current list of types might be extended over time.

Overview on QoD values and types

How to assign a solution type to a VT

This describes the type of solution available for the vulnerability in a formal way. Use one of the following keywords.

Workaround: Information is available about a configuration or specific deployment scenario that can be used to avoid exposure to the vulnerability. There may be none, one, or more workarounds available. This is typically the “first line of defense” against a new vulnerability before a mitigation or vendor fix has been issued or even discovered.

Mitigation: Information is available about a configuration or deployment scenario that helps to reduce the risk of the vulnerability but that does not resolve the vulnerability on the affected product. Mitigations may include using devices or access controls external to the affected product. Mitigations may or may not be issued by the original author of the affected product, and they may or may not be officially sanctioned by the document producer.

VendorFix: Information is available about an official fix that is issued by the original author of the affected product. Unless otherwise noted, it is assumed that this fix fully resolves the vulnerability.

NoneAvailable: Currently there is no fix available. Information should contain details about why there is no fix.

WillNotFix: There is no fix for the vulnerability and there never will be one. This is often the case when a product has been orphaned, end-of-lifed, or otherwise deprecated. Information should contain details about why there will be no fix issued.

9 Likes