Netskope Deprecated

Cloud access security broker that enables to find, understand, and secure cloud apps. Deprecated. Use Netskope (API v1) instead.

Network Security · Netskope

Details

IDNetskope
ProviderNetskope
CategoryNetwork Security
From Version5.0.0
Supported ModulesAgentix XSIAM

README

Use the Netskope integration to manage your Netskope events and alerts.

This integration was integrated and tested with Netskope v51.

Prerequisites

You need to obtain the following Netskope information.

  • Netskope tenant URL
  • Tenant API token

Configure the Netskope Integration on Cortex XSOAR

  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for Netskope.
  3. Click Add instance to create and configure a new integration instance.
    • Name: a textual name for the integration instance.
    • URL of Netskope Tenant: for example, https://tenant.goskope.com
    • Tenant API Token: paste the token that you copied.
    • Do not validate server certificate (unsecure)
    • Use system proxy settings
  4. Click Test to validate the URLs and connection.

Commands

You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook. After you successfully execute a command, a DBot message appears in the War Room with the command details.

  1. Get Netskope events: netskope-events
  2. Get Netskope alerts: netskope-alerts

1. Get Netskope events: netskope-events


Retrieve events from your Netskope environment.

Command Example

!netskope-events type=application timeperiod=Last24Hours

Input
Input Parameter Description
query Filter query, for example, foo@test.com
timeperiod Query time period (for example, last 60 minutes, last 24 hours)
starttime Query start time: timestamp or dd-mm-yyyyTHH:MM:SSZ (e.g., 31-12-1999T11:59:59Z)

 

endtime

Query end time: timestamp or dd-mm-yyyyTHH:MM:SSZ (e.g., 31-12-1999T11:59:59Z)

type

Event type

  • Application
  • Page
  • Audit
limit

Maximum number of events returned (useful for pagination in combination with skip)

Must be an integer less than 5,000.

skip Skip over specific events (useful for pagination in combination with limit)

 

Context Output
Path Description
Netskope.Events.App Application name
Netskope.Events.Timestamp Event timestamp
Netskope.Events.Activity Event activity
Netskope.Events.Object Document/object from the event
Netskope.Events.hostname Device hostname
Netskope.Events.AppCategory Netskope application category (for example, Cloud Storage, Webmail, and so on)
Netskope.Events.device_classification Device classification (for example, managed vs. unmanaged)
Netskope.Events.User User
Netskope.Events.from_user Login IDs for cloud applications
Netskope.Events.to_user Destination user IDs
Netskope.Events.SourceIP Source IP
Netskope.Events.AccessMethod Access method (for example, client, reverse proxy, Secure Forwarder, and so on)
Netskope.Events.url URL
Netskope.Events.ID Event ID

 

Raw Output
{  
   "AccessMethod":"API Connector",
   "Activity":"HeadBucket",
   "App":"Amazon Web Services",
   "AppCategory":"IaaS/PaaS",
   "DeviceClassification":null,
   "FromUser":null,
   "Hostname":null,
   "ID":"1382a493090c36ba14bfc2bc",
   "Object":"nstrail",
   "SourceIP":"8.36.116.16",
   "Timestamp":"Mon May 21 2018 13:26:30 GMT+0300 (IDT)",
   "ToUser":null,
   "URL":null,
   "User":"assumed-role/ctaudit/AssumeRoleSession1"
}

2. Get Netskope alerts: netskope-alerts


Retrieve alerts from your Netskope environment.

Command Example

!netskope-alerts type=Malware timeperiod=Last60Days

Input
Input Parameter Description
type Alert type
timeperiod Query time period (for example, last 60 minutes, last 24 hours)
starttime

Query start time: timestamp or dd-mm-yyyyTHH:MM:SSZ (e.g., 31-12-1999T11:59:59Z)

endtime

Query end time: timestamp or dd-mm-yyyyTHH:MM:SSZ (e.g., 31-12-1999T11:59:59Z)

query Valid event query described in the query language document

 

Context Output
Path Description
Netskope.Alerts.App Application name
Netskope.Alerts.Timestamp Alert timestamp
Netskope.Alerts.Policy Name of policy triggered
Netskope.Alerts.DLPFile Name of DLP file that triggered
Netskope.Alerts.Hostname Hostname
Netskope.Alerts.ID Alert ID

 

Raw Output
{  
   "App":"Microsoft Office 365 OneDrive for Business",
   "DLPFile":null,
   "DLPProfile":null,
   "Hostname":"Ashutosh’s MacBook Pro",
   "ID":"f95e5638432f538365d5b256",
   "Policy":null,
   "Timestamp":"Mon May 21 2018 13:29:34 GMT+0300 (IDT)"
}

Configuration parameters

  • url — URL of Netskope Tenant (e.g. https://tenant.goskope.com) (required)
  • token — Tenant API Token (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • isFetch — Fetch incidents
  • incidentType — Incident type
  • firstFetch — Timeframe for initial fetch
  • maxFetch — Maximum number of events to fetch per fetch

Commands (2)

  • netskope-alerts

    Gets a list of alerts

  • netskope-events

    Gets a list of events

var SERVER_URL = params.url.replace(/[\/]+$/, '');
var BASE_URL = SERVER_URL + '/api/v1/';
var TOKEN = params.token;

function sendRequest(method, api, stringifyData) {
    var requestUrl = BASE_URL + api;
    var result = http(
        requestUrl,
        {
            Method: method,
            Headers: {
                'Content-Type': ['application/json'],
                'Accept': ['application/json']
            }
        },
        params.insecure,
        params.proxy
        );
    if (result.StatusCode < 200 && result.StatusCode > 299) {
        throw 'Failed to perform request ' + path + ', request status code: ' + result.StatusCode + ', body: ' + result.Body;
    }
    if (result.Body === '') {
        throw 'No content received.' + requestUrl + result;
    }
    var body;
    try {
        // if fetching incidents, stringify long numbers to not round down long ids, e.g:
        // "dlp_incident_id":3747385551915191779 --> "dlp_incident_id":"3747385551915191779"
        if (stringifyData) {
            stringifyBody = result.Body.replace(/([\[:]){1}(\d{11,})([,\}\]])/g, "$1\"$2\"$3");
            return JSON.parse(stringifyBody)
        }
        body = JSON.parse(result.Body);
    } catch (ex) {
        throw 'Error parsing reply - ' + result.Body + ' - ' + ex;
    }
    return body;
}

function normalizeTimestamp(timestamp) {
    return Date(timestamp);
}

function translateTimeperiod(timeperiod){
    var timeperiodTranslator = {
        'Last60Minutes': '3600',
        'Last24Hours': '86400',
        'Last7Days': '604800',
        'Last30Days': '2592000',
        'Last60Days': '5184000',
        'Last90Days': '7776000'
    };
    return timeperiodTranslator[timeperiod];
}

function translateMonthName(monthName) {
    var monthTranslator = {
        'january': 1,
        'february': 2,
        'march': 3,
        'april': 4,
        'may': 5,
        'june': 6,
        'july': 7,
        'august': 8,
        'september': 9,
        'october': 10,
        'november': 11,
        'december': 12
    };
    return monthTranslator[monthName];
}

/**
* convert string formatted time to timestamp.
* Note: Accept 2 string formats: "dd-mm-yyyyTHH:MM:SSZ" or "Month Day, Year HH:MM:SS".
* @param {string} strDate - string formatted array
* @return {string} timestamp
*/
function toTimestamp(strDate){
    // accept: 31-12-1999T14:35:20Z
    var dateTuple = strDate.match('^(\\d{2})-(\\d{2})-(\\d{4})T(\\d{2}):(\\d{2}):(\\d{2})Z$');
    var timestamp;
    if (dateTuple !== null) {
        // first element is the entire match, then the individual matches.
        // months in Date JS are an integer between 0 and 11.
        timestamp = new Date(dateTuple[3], dateTuple[2] - 1, dateTuple[1], dateTuple[4], dateTuple[5], dateTuple[6]);
        return timestamp.getTime()/1000;
    }

    // accept: December 31, 1999 14:35:20
    dateTuple = strDate.toLowerCase().match('^(january|february|march|april|may|june|july|august|september|october|november|december) (\\d{1,2}), (\\d{4}) (\\d{2}):(\\d{2}):(\\d{2})$');
    if (dateTuple !== null) {
        timestamp = new Date(dateTuple[3], translateMonthName(dateTuple[1]) - 1, dateTuple[2], dateTuple[4], dateTuple[5], dateTuple[6]);
        return timestamp.getTime()/1000;
    }
    return strDate;
}

function getAlerts(stringifyData) {
    var queryArgs = {
        token: TOKEN,
        type: encodeURIComponent(args.type)
    };
    if (args.starttime && args.endtime) {
        queryArgs.starttime = toTimestamp(args.starttime);
        queryArgs.endtime = toTimestamp(args.endtime);
        if (args.timeperiod) {
            queryArgs.timeperiod = translateTimeperiod(args.timeperiod);
        }
        if (args.query) {
            queryArgs.query = encodeURIComponent(args.query);
        }
    } else if (args.timeperiod) {
        queryArgs.timeperiod = translateTimeperiod(args.timeperiod);
        if (args.query) {
            queryArgs.query = encodeURIComponent(args.query);
        }
    } else {
        throw 'Not given enough arguments to filter events by.';
    }

    var cmdUrl = 'alerts' + encodeToURLQuery(queryArgs);
    logInfo('Getting/Fetching Netskope Alerts (to be incidents) with ' + String(cmdUrl));
    var result = sendRequest('GET', cmdUrl, stringifyData);
    return result;
}

function getAlertsCommand() {
    result = getAlerts(false)
    var retArray = [];
    result.data.forEach(function(arrayItem) {
        var id = arrayItem._id;
        var app =  arrayItem.app;
        var timestamp =  normalizeTimestamp(arrayItem.timestamp);
        var dlp_profile =  arrayItem.dlp_profile;
        var dlp_file =  arrayItem.dlp_file;
        var hostname =  arrayItem.hostname;
        var policy =  arrayItem.policy;
        retArray.push({'ID': id, 'App' : app, 'Timestamp' : timestamp, 'DLPProfile' : dlp_profile, 'DLPFile' : dlp_file, 'Hostname' : hostname, 'Policy' : policy});
    });
    var ec = {
        "Netskope.Alerts(val.ID && val.ID === obj.ID)" : retArray
    };
    headers = ['ID', 'Timestamp', 'DLPProfile', 'DLPFile', 'Hostname', 'Policy'];
    return {
        Type: entryTypes.note,
        ContentsFormat: formats.json,
        Contents: result.data,
        ReadableContensFormat: formats.markdown,
        HumanReadable: tableToMarkdown('Netskope Alerts', retArray, headers),
        EntryContext: ec
    };
}

function getEvents() {
    var queryArgs = {
        token: TOKEN,
        type: encodeURIComponent(args.type)
    };
    if (args.starttime && args.endtime) {
        queryArgs.starttime = toTimestamp(args.starttime);
        queryArgs.endtime = toTimestamp(args.endtime);
        if (args.timeperiod) {
            queryArgs.timeperiod = translateTimeperiod(args.timeperiod);
        }
        if (args.query) {
            queryArgs.query = encodeURIComponent(args.query);
        }
    } else if (args.timeperiod) {
        queryArgs.timeperiod = translateTimeperiod(args.timeperiod);
        if (args.query) {
            queryArgs.query = encodeURIComponent(args.query);
        }
    } else {
        throw 'Not given enough arguments to filter events by.';
    }

    var cmdUrl = 'events' + encodeToURLQuery(queryArgs);
    var result = sendRequest('GET', cmdUrl);
    var retArray = [];
    result.data.forEach(function(arrayItem) {
        var id = arrayItem._id;
        var app =  arrayItem.app;
        var timestamp = normalizeTimestamp(arrayItem.timestamp);
        var activity =  arrayItem.activity;
        var object =  arrayItem.object;
        var hostname =  arrayItem.hostname;
        var category =  arrayItem.category;
        var device_classification =  arrayItem.device_classification;
        var user =  arrayItem.user;
        var from_user =  arrayItem.from_user;
        var to_user =  arrayItem.to_user;
        var srcip =  arrayItem.srcip;
        var access_method =  arrayItem.access_method;
        var url =  arrayItem.url;
        retArray.push({'ID': id, 'App' : app, 'Timestamp' : timestamp, 'Activity' : activity, 'Object' : object, 'Hostname' : hostname, 'AppCategory' : category, 'DeviceClassification' : device_classification, 'User' : user, 'FromUser' : from_user, 'ToUser' : to_user, 'SourceIP' : srcip, 'AccessMethod' : access_method, 'URL' : url});
    });
    var ec = {
        "Netskope.Events(val.ID && val.ID === obj.ID)" : retArray
    };
    headers = ['ID', 'App', 'Timestamp', 'Activity', 'Object', 'Hostname', 'AppCategory', 'DeviceClassification', 'User',
               'FromUser', 'ToUser', 'SourceIP', 'AccessMethod', 'URL'];
    return {
        Type: entryTypes.note,
        ContentsFormat: formats.json,
        Contents: result.data,
        ReadableContensFormat: formats.markdown,
        HumanReadable: tableToMarkdown('Netskope Events', retArray, headers),
        EntryContext: ec
    };
}

function now() {
    return parseInt(new Date().getTime()/1000);
}

function fetchAlerts() {
    lastRun = getLastRun();
    last_run = parseInt(lastRun.lastTime);
    if (isNaN(last_run)) {
        last_run = now() - parseInt(translateTimeperiod(params.firstFetch));
    }

    args = {};
    args.type = "";
    args.starttime = last_run.toString();
    args.endtime = now().toString();
    alerts = getAlerts(true).data;
    var incidents = [];
    var latestIncidedentTimeString = null;
    var latestIncidedentTimeInt = null;
    if (typeof alerts !== 'undefined') {
        alerts.reverse();  // alerts are fetched in descending order, reversing to process older first
        for (var i = 0; i < alerts.length; i++) {
            item = alerts[i];
            incident = {};
            d = new Date(item.timestamp);
            incident.occurred = d.toISOString();
            incident.name = item.alert_type + " - " + item.alert_name;
            incident.rawJSON = JSON.stringify(item);
            incidents.push(incident);
            if (latestIncidedentTimeInt == null || parseInt(item.timestamp) > latestIncidedentTimeInt) {
                latestIncidedentTimeInt = parseInt(item.timestamp);
                latestIncidedentTimeString = item.timestamp
            }
            if (incidents.length >= Math.min(50, params.maxFetch)) {
                break;
            }
        }
    }
    var incidentsLimitReached = (incidents.length >= Math.min(50, params.maxFetch));
    lastTime = incidentsLimitReached ? latestIncidedentTimeString : args.endtime;
    lastRun = {'lastTime': lastTime};
    setLastRun(lastRun);
    logInfo('Netskope lastRun is: ' + String(args.endtime));
    return JSON.stringify(incidents);
}

switch (command) {
    case 'test-module':
        var queryArgs = {
            token: TOKEN,
            type: 'application',
            timeperiod: '3600',
            limit: '1'
        };
        var cmdUrl = 'events' + encodeToURLQuery(queryArgs);
        result = sendRequest('GET', cmdUrl);
        if (result.status != "error") {
            return 'ok';
        }
        return result;
    case 'fetch-incidents':
        return fetchAlerts();
    case 'netskope-events':
        return getEvents();
    case 'netskope-alerts':
        return getAlertsCommand();
}