Interacting with Cisco APIs

An architecture that implements REST allows for requests to be made to access and manipulate textual representations of webservices. The most common protocol to use as transport for this HTTP, but there are several methods available with which to make these requests.
This post will focus on the Cisco PSIRT openVuln API (https://developer.cisco.com/psirt/) (again!), and all but the last method would be applicable for any other REST API.
No matter which method you choose the steps are always the same, query cloudsso.cisco.com using your credentials to obtain an authorization token. Use the received authorization token with each REST call to the API that you make.

CURL

Omar Santos has provided an succinct example so I won’t cover old ground, you can find it here:
https://community.cisco.com/t5/services-documents/accessing-the-cisco-psirt-openvuln-api-using-curl/ta-p/3652897

Postman

https://www.getpostman.com/

A great tool which undoubted I am only scratching the surface of, with many dropdowns and plenty of textfields. Thankfully to get it working you only need to fill out some of the details.

To obtain an authorization token follow these steps:
Set the call to ‘POST’ provide the URL https://cloudsso.cisco.com/as/token.oauth2. Add the following Header:

'Content-Type: application/x-www-form-urlencoded'

Under the Body section you will need the credentials given from https://apiconsole.cisco.com. Add the following key:value pairs,

{ grant-type: client_credentials', 
  client_id: <API_TOKEN_CLIENT_ID>, 
  client_secret: <API_TOKEN_CLIENT_PASS> 
}

Click the Send button and you should receive a result back:


Now we have an authorization token we can make a query to the openVuln API. There are a range of queries which can be made: https://developer.cisco.com/docs/psirt/#!api-reference/api-reference . We will take a look vulnerabilities affecting a single release.
Create a new tab and in the URL type:

https://api.cisco.com/security/advisories/ios/

In the Params section add:

{ version: 15.0(2)SE1 }

You will notice that the URL is appended with the query “?version=15.0(2)SE1”

In the Headers tab we will now use the Authorization token:

{ Authorization: Bearer <token_from_previous_step>,
Accept: application/json
}

Click the Send button. After a little bit of whirring you will receive an exhaustive list of vulnerabilities in JSON format.
Great!…but wouldn’t it be nice if we were in a position to start parsing that data straight away? To the Python…

Python – requests

http://docs.python-requests.org/en/master

The requests library for Python provides the same level of interaction with a REST API as Postman, but now we can issue calls and parse data structures inline with our other code.
Getting the Authorization Token is as simple as:

import json
import requests

def get_api_token(url):
    response = requests.post(url, verify=False, data={"grant_type": "client_credentials"},
                             headers={"Content-Type": "application/x-www-form-urlencoded"},
                             params={"client_id": API_TOKEN_CLIENT_ID, "client_secret": API_TOKEN_CLIENT_PASS})

    if response is not None:
        return json.loads(response.text)["access_token"]

    return None

Once we have the token from the previous method we can then use it (up until its lifetime expires) on various API calls. Here we make a call to find all the advisories affecting a particular IOS versions. For the sake of brevity, I am creating a new token within the method:

API_GET_ADVISORIES = "https://api.cisco.com/security/advisories/ios/?version={0}"

def get_advisories_by_release(token, ver):   requests.packages.urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    response = requests.get(API_GET_ADVISORIES.format(ver), verify=False,
                            headers={"Authorization": "Bearer {0}".format(token), "Accept": "application/json"})

    if response.status_code == 200:
        return json.loads(response.text)

    return None

This will return the same output that we saw earlier in Postman, a list of dictionaries. Each one containing the details of a vulnerability. So lets combine out methods, take the received response and do something useful with it:

def main():
    version = "12.2(55)SE10"
    res = get_advisories_by_release(get_api_token(https://cloudsso2.cisco.com/as/token.oauth2), version)

    print("Release {0} has {1} advisories".format(version, len(res))

OpenVulnQuery

https://github.com/CiscoPSIRT/openVulnAPI

OpenVulnQuery is a library available via pip which acts as a wrapper for requests calls whilst providing methods to filter and present the output whilst hopefully reducing the amount of code you have to type. Lets see….

Obtaining the Authorization Token abstracts a good deal of the process away, instead of using the token hash explicitly you make your REST calls via a returned object, an instance of OpenVulnQueryClient:

from openVulnQuery import query_client
query_client = query_client.OpenVulnQueryClient(client_id=API_TOKEN_CLIENT_ID, client_secret=API_TOKEN_CLIENT_PASS)

That is already a great reduction in code. Let get make a REST call and output the results as before:

from openVulnQuery import query_client

def main():
    version = "12.2(55)SE10"
    query_client = query_client.OpenVulnQueryClient(client_id=API_TOKEN_CLIENT_ID, client_secret=API_TOKEN_CLIENT_PASS)
    advisories = query_client.get_by_ios_xe('ios', version)

    print("Release {0} has {1} advisories".format(version, len(advisories))

Evaluation of methods

Certainly accessing information via REST can be easily achieved by the methods detailed above and you decision should be steered by the tools you have available. Curl is useful but I can’t imagine a working environment where I may just have that available. Postman is excellent for quickly working out query input values and inspecting the output. As for this corner case of accessing PSIRT information use of libraries such as openVulnAPI should be encouraged as it saves you from covering old ground but its availability in your work environment or perhaps its requirement for Python >3.x may prevent you from using it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: