microsoft / rest-api-fuzz-testing

REST API Fuzz Testing (RAFT): Source code for self-hosted service developed for Azure, including the API, orchestration engine, and default set of security tools (including MSR's RESTler), that enables developers to embed security tooling into their CI/CD workflows
MIT License
262 stars 41 forks source link

ZAP wrong endpoint URL #216

Open Sticcia opened 3 years ago

Sticcia commented 3 years ago

Running ZAP in a local deployment with the following configuration:

{
  "readOnlyFileShareMounts": [
    {
      "fileShareName": "specifications",
      "mountPath": "/specifications"
    }
  ],
  "testTasks": {
    "targetConfiguration": {
      "apiSpecifications": [
        "/specifications/openapi.json"
      ],
      "endpoint": "https://<endpoint-url>/managementserver/rest"
    },
    "tasks": [
      {
        "toolName": "ZAP",
        "outputFolder": "zap",
        "keyVaultSecrets": [
          "TOKEN"
        ],
        "authenticationMethod": {
          "Token": "Token"
        }
      }
    ]
  }
}

The openapi.json specification contains the following:

"servers": [
  {
    "url": "https://localhost/ManagementServer/rest",
    "description": "Management Server entry point"
  }
]

Execution runs tests against URL from specification instead of endpoint in configuration, causing many errors like:

14529 [ZAP-Import-OpenAPI-1] WARN  org.zaproxy.zap.extension.openapi.ExtensionOpenApi - Failed to access URL: https://localhost/ManagementServer/rest/cameras : java.net.ConnectException : Connection refused (Connection refused)
14529 [ZAP-Import-OpenAPI-1] WARN  org.zaproxy.zap.extension.openapi.ExtensionOpenApi - Failed to access URL: https://localhost/ManagementServer/rest/cameras/id?tasks=tasks : java.net.ConnectException : Connection refused (Connection refused)
14529 [ZAP-Import-OpenAPI-1] WARN  org.zaproxy.zap.extension.openapi.ExtensionOpenApi - Failed to access URL: https://localhost/ManagementServer/rest/cameras/id?task=task : java.net.ConnectException : Connection refused (Connection refused)

This happens only when using a mounted file path for the specification. Running a local python http.server on the host and changing the URL in the configuration to:

"apiSpecifications": [ "http://host.docker.internal:8000/openapi.json" ]

returns expected result. Lastly, all other tools work with:

"apiSpecifications": [ "/specifications/openapi.json" ]
stishkin commented 3 years ago

@Sticcia

Hi I cannot seem to be able to repro the issue

I am using petstore swagger specification https://petstore.swagger.io/v2/swagger.json and I added the following modification

image

I'm using the following RAFT job configuration file:

{
  "readonlyFileShareMounts": [
    {
      "FileShareName": "Zap-repro",
      "MountPath": "/specs"
    }
  ],
  "testTasks" : {
    "tasks": [
      {
        "toolName": "ZAP",
        "outputFolder": "zap-out",
        "targetConfiguration" : {
          "apiSpecifications": [
            "/specs/spec.json"
          ],
          "endpoint": "https://petstore.swagger.io"
        }
      }
    ]
  }
}
Sticcia commented 3 years ago

Hi @stishkin ,

The modification should replace your "host" and "basePath" as seen here: https://swagger.io/docs/specification/api-host-and-base-path/ Or, my guess is, you could try changing from "host": "petstore.swagger.io" to "host": "localhost".

From what I understand, ZAP is grabbing the endpoint url from the specification (either "host" or "servers") instead of the configuration. So, having the spec differ from the config should suffice to reproduce this. (this happens only when using local mounted file, works fine if hosting i.e. Python server)

Also, I tried removing the URL altogether from the specification and got the following:

22612 [ZAP-Import-OpenAPI-1] WARN  org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter - Failed to build/normalise the API URL using Server URL: /
java.lang.IllegalArgumentException: The scheme must not be null.
    at org.zaproxy.zap.extension.openapi.converter.swagger.UriBuilder.validateNotNull(UriBuilder.java:279) ~[openapi-beta-19.zap:?]
    at org.zaproxy.zap.extension.openapi.converter.swagger.UriBuilder.build(UriBuilder.java:252) ~[openapi-beta-19.zap:?]
    at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.createApiUrls(SwaggerConverter.java:259) [openapi-beta-19.zap:?]
    at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.readOpenAPISpec(SwaggerConverter.java:182) [openapi-beta-19.zap:?]
    at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.getRequestModels(SwaggerConverter.java:159) [openapi-beta-19.zap:?]
    at org.zaproxy.zap.extension.openapi.ExtensionOpenApi$1.run(ExtensionOpenApi.java:289) [openapi-beta-19.zap:?]
22612 [ZAP-Import-OpenAPI-1] WARN  org.zaproxy.zap.extension.openapi.ExtensionOpenApi - Unable to obtain any server URL from the definition.
org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerException: Unable to obtain any server URL from the definition.
    at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.createApiUrls(SwaggerConverter.java:272) ~[openapi-beta-19.zap:?]
    at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.readOpenAPISpec(SwaggerConverter.java:182) ~[openapi-beta-19.zap:?]
    at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.getRequestModels(SwaggerConverter.java:159) ~[openapi-beta-19.zap:?]
    at org.zaproxy.zap.extension.openapi.ExtensionOpenApi$1.run(ExtensionOpenApi.java:289) [openapi-beta-19.zap:?]

Finally, replacing localhost with the correct endpoint host-name does run correctly. But, since the host changes often, it should be obtained by the configuration, not the specification. Or is this a wrong assumption?

Thank you.

stishkin commented 3 years ago

We are using the following Python script in order to use ZAP https://github.com/zaproxy/zaproxy/blob/main/docker/zap-api-scan.py

And we use the following flag to set the hostname -O the hostname to override in the (remote) OpenAPI spec

There is OpenAPI add-on to ZAP that seem to expose openapitargeturl that might support the scenario that you described in the bug: https://www.zaproxy.org/docs/desktop/addons/openapi-support/

We need to do some investigation on how to expose that setting

Sticcia commented 3 years ago

I don't see why the -O parameter will only override if targeted against a remote specification and not with a path to a local file. I created a bug on the ZAP repository: https://github.com/zaproxy/zaproxy/issues/6673.

stishkin commented 3 years ago

zaproxy/zaproxy#6673

got closed as dup of

zaproxy/zaproxy#5510