Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/AkhtarAmir/scans into spe…
Browse files Browse the repository at this point in the history
…c/cloudfront
  • Loading branch information
AkhtarAmir committed Mar 5, 2021
2 parents 0720b3f + 9f518b6 commit 837bb5b
Show file tree
Hide file tree
Showing 48 changed files with 1,118 additions and 884 deletions.
11 changes: 6 additions & 5 deletions collectors/azure/collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ var calls = {
securityContacts: {
list: {
url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Security/securityContacts?api-version=2017-08-01-preview',
ignoreLocation: true
}
},
subscriptions: {
Expand Down Expand Up @@ -444,10 +445,10 @@ var collect = function(AzureConfig, settings, callback) {
var regionsToLoop = parseCollection(subCallObj.reliesOnPath, collection);
if (regionsToLoop && Object.keys(regionsToLoop).length) {
// Loop through regions
async.eachOf(regionsToLoop, function(regionObj, region, regionCb) {
async.eachOfLimit(regionsToLoop, 5, function(regionObj, region, regionCb) {
if (regionObj && regionObj.data && regionObj.data.length) {
if (!collectionObj[region]) collectionObj[region] = {};
async.each(regionObj.data, function(regionData, regionDataCb) {
async.eachLimit(regionObj.data, 10, function(regionData, regionDataCb) {
var localReq = {
url: subCallObj.url,
post: subCallObj.post,
Expand Down Expand Up @@ -523,7 +524,7 @@ var collect = function(AzureConfig, settings, callback) {
async.eachOf(regionsToLoop, function(regionObj, region, regionCb) {
if (!collectionObj[region]) collectionObj[region] = {};
// Loop through the resources
async.eachOf(regionObj, function(resourceObj, resourceId, resourceCb){
async.eachOfLimit(regionObj, 5, function(resourceObj, resourceId, resourceCb){
function processResource(resourceData, resourceDataCb) {
var localReq = {
url: subCallObj.url,
Expand Down Expand Up @@ -561,14 +562,14 @@ var collect = function(AzureConfig, settings, callback) {
}

if (Array.isArray(resourceObj)) {
async.each(resourceObj, function(resourceData, resourceDataCb) {
async.eachLimit(resourceObj, 10, function(resourceData, resourceDataCb) {
processResource(resourceData, resourceDataCb);
}, function(){
resourceCb();
});
} else {
if (resourceObj && resourceObj.data && resourceObj.data.length) {
async.each(resourceObj.data, function(resourceData, resourceDataCb) {
async.eachLimit(resourceObj.data, 10, function(resourceData, resourceDataCb) {
processResource(resourceData, resourceDataCb);
}, function() {
resourceCb();
Expand Down
10 changes: 7 additions & 3 deletions collectors/oracle/collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var async = require('async');

var helpers = require(__dirname + '/../../helpers/oracle');

const regionSubscriptionService = {name: 'regionSubscription', call: 'list', region: helpers.regions(false).default};
var regionSubscriptionService;

var globalServices = [
'core'
Expand Down Expand Up @@ -396,6 +396,10 @@ var processCall = function(OracleConfig, collection, settings, regions, call, se
if (!collection[service][callKey]) collection[service][callKey] = {};

async.eachLimit(regions[service], helpers.MAX_REGIONS_AT_A_TIME, function(region, regionCb) {
if (region === 'default') {
region = OracleConfig.region ? OracleConfig.region : 'us-ashburn-1';
}

if (settings.skip_regions &&
settings.skip_regions.indexOf(region) > -1 &&
globalServices.indexOf(service) === -1) return regionCb();
Expand Down Expand Up @@ -458,7 +462,6 @@ var processCall = function(OracleConfig, collection, settings, regions, call, se
var getRegionSubscription = function(OracleConfig, collection, settings, calls, service, callKey, region, serviceCb) {

var LocalOracleConfig = JSON.parse(JSON.stringify(OracleConfig));
LocalOracleConfig.region = region;
LocalOracleConfig.service = service;

if (!collection[service]) collection[service] = {};
Expand All @@ -482,9 +485,10 @@ var getRegionSubscription = function(OracleConfig, collection, settings, calls,
// Loop through all of the top-level collectors for each service
var collect = function(OracleConfig, settings, callback) {
var collection = {};

OracleConfig.region = OracleConfig.region ? OracleConfig.region : 'us-ashburn-1';
OracleConfig.maxRetries = 5;
OracleConfig.retryDelayOptions = {base: 300};
regionSubscriptionService = {name: 'regionSubscription', call: 'list', region: OracleConfig.region};

var regions = helpers.regions(settings.govcloud);

Expand Down
10 changes: 5 additions & 5 deletions engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ var async = require('async');
var exports = require('./exports.js');
var suppress = require('./postprocess/suppress.js');
var output = require('./postprocess/output.js');
var gslRunner = require('./helpers/gsl.js');
var aslRunner = require('./helpers/asl.js');

/**
* The main function to execute CloudSploit scans.
Expand Down Expand Up @@ -193,11 +193,11 @@ var engine = function(cloudConfig, settings) {
setTimeout(function() { pluginDone(err, maximumStatus); }, 0);
};

if (plugin.gsl) {
console.log(`INFO: Using custom GSL for plugin: ${plugin.title}`);
if (plugin.asl) {
console.log(`INFO: Using custom ASL for plugin: ${plugin.title}`);
// Inject APIs and resource maps
plugin.gsl.apis = plugin.apis;
gslRunner(collection, plugin.gsl, resourceMap, postRun);
plugin.asl.apis = plugin.apis;
aslRunner(collection, plugin.asl, resourceMap, postRun);
} else {
plugin.run(collection, settings, postRun);
}
Expand Down
282 changes: 282 additions & 0 deletions helpers/asl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
var parse = function(obj, path) {
if (typeof path == 'string') path = path.split('.');
if (Array.isArray(path) && path.length) {
var localPath = path.shift();
if (obj[localPath] || typeof obj[localPath] === 'boolean') {
return parse(obj[localPath], path);
} else {
return 'not set';
}
} else {
return obj;
}
};

var transform = function(val, transformation) {
if (transformation == 'DATE') {
return new Date(val);
} else if (transformation == 'INTEGER') {
return parseInt(val);
} else if (transformation == 'STRING') {
return val.toString();
} else if (transformation == 'DAYSFROM') {
// Return the number of days between the date and now
var now = new Date();
var then = new Date(val);
var timeDiff = then.getTime() - now.getTime();
var diff = Math.round(timeDiff / (1000 * 3600 * 24));
return diff;
} else if (transformation == 'COUNT') {
return val.length;
} else if (transformation == 'EACH') {
return val;
} else if (transformation == 'TOLOWERCASE') {
return val.toLowerCase();
} else {
return val;
}
};

function evaluateConditions(obj, conditions){
var preVal = {}; // place to hold the result evaluated till now
for (let i in conditions){
let condition = conditions[i];
let value = validate(obj,condition);

if (!condition.logical){
// no logical operation means
// first element of the conditions
if ( i == 0){
// first element in the condition list,so set the preVal
preVal = value;
}
// error as no logical condition and not the first element
else{
//err
console.error('No logical operator found and this is not the first element');
}
}
else{
if ( i == 0){
// first element in the condition list,and with logical operation. Error case
console.error('logical operator found in first element');
}
else{
// this is not first element in array and also logical op is here. use the preVal and evaluate it
if(preVal){
//as this is not first element in array preVal should be set.
//other wise the condition is not properly formed as AND OR are binary ops
if( condition.logical === 'OR'){
preVal.status = preVal.status || value.status;
}
else if (condition.logical === 'AND'){
preVal.status = preVal.status && value.status;
}
else{
// unsupported operator.
console.error('wrong logical operator mentioned');
}
preVal.message = preVal.message.concat(', ',value.message);
}
else{
//condition is not properly formed as AND OR are binary ops
console.error('condition is malformed');
}
}
}
}

return preVal;
}

var validate = function(obj, condition) {
var result = 0;
var message = [];
var override = false;

// Extract the values for the conditions

if (condition.property) {
var conditionResult = 0;
condition.parsed = parse(obj, condition.property);

// Transform the property if required
if (condition.transform) {
condition.parsed = transform(condition.parsed, condition.transform);
}

// Compare the property with the operator
if (condition.parsed === 'not set'){
conditionResult = 2;
message.push(`${condition.property}: not set to any value`);
}
else if (condition.op) {
if (condition.op == 'EQ') {
if (condition.parsed == condition.value) {
message.push(`${condition.property}: ${condition.parsed} matched: ${condition.value}`);
} else {
conditionResult = 2;
message.push(`${condition.property}: ${condition.parsed} did not match: ${condition.value}`);
}
} else if (condition.op == 'GT') {
if (condition.parsed > condition.value) {
message.push(`${condition.property}: count of ${condition.parsed} was greater than: ${condition.value}`);
} else {
conditionResult = 2;
message.push(`${condition.property}: count of ${condition.parsed} was not greater than: ${condition.value}`);
}
} else if (condition.op == 'NE') {
if (condition.parsed !== condition.value) {
message.push(`${condition.property}: ${condition.parsed} is not: ${condition.value}`);
} else {
conditionResult = 2;
message.push(`${condition.property}: ${condition.parsed} is: ${condition.value}`);
}
} else if (condition.op == 'MATCHES') {
var userRegex = RegExp(condition.value);
if (userRegex.test(condition.parsed)) {
message.push(`${condition.property}: ${condition.parsed} matches the regex: ${condition.value}`);
} else {
conditionResult = 2;
message.push(`${condition.property}: ${condition.parsed} does not match the regex: ${condition.value}`);
}
} else if (condition.op == 'EXISTS') {
if (condition.parsed !== 'not set') {
message.push(`${condition.property}: set to ${condition.parsed}`);
} else {
conditionResult = 2;
message.push(`${condition.property}: ${condition.parsed}`);
}
} else if (condition.op == 'ISTRUE') {
if (condition.parsed) {
message.push(`${condition.property} is true`);
} else {
conditionResult = 2;
message.push(`${condition.property} is false`);
}
} else if (condition.op == 'ISFALSE') {
if (!condition.parsed) {
message.push(`${condition.property} is false`);
} else {
conditionResult = 2;
message.push(`${condition.property} is true`);
}
} else if (condition.op == 'CONTAINS') {
if (condition.parsed.includes(condition.value)) {
message.push(`${condition.property}: ${condition.value} found in ${condition.parsed}`);
} else {
conditionResult = 2;
message.push(`${condition.value} not found in ${condition.parsed}`);
}
}
} else if (condition.transform && condition.transform == 'EACH' && condition.conditions) {
// Recurse into the same function
var subProcessed = [];
condition.parsed.forEach(function(parsed) {
subProcessed.push(validate(parsed, condition.conditions));
});
subProcessed.forEach(function(sub) {
if (sub.status) conditionResult = sub.status;
if (sub.message) message.push(sub.message);
});
}
if (condition.invert) conditionResult = (conditionResult ? 0 : 2);

if (condition.override && !conditionResult) override = true;
if (conditionResult) result = conditionResult;
}


if (result && override) result = 0;

if (!message.length) {
message = ['The resource matched all required conditions'];
}

return {
status: result,
message: message.join(', ')
};
};

var asl = function(source, input, resourceMap, callback) {
if (!source || !input) return callback('No source or input provided');
if (!input.apis || !input.apis[0]) return callback('No APIs provided for input');
if (!input.conditions || !input.conditions.length) return callback('No conditions provided for input');

// Split apis into service:api
// TODO: support conditions that use different APIs
var service = input.conditions[0].service;
var api = input.conditions[0].api;
var resourcePath;
if (resourceMap &&
resourceMap[service] &&
resourceMap[service][api]) {
resourcePath = resourceMap[service][api];
}

if (!source[service]) return callback(`Source data did not contain service: ${service}`);
if (!source[service][api]) return callback(`Source data did not contain API: ${api}`);

var results = [];

for (var region in source[service][api]) {
var regionVal = source[service][api][region];
if (typeof regionVal !== 'object') continue;
if (regionVal.err) {
results.push({
status: 3,
message: regionVal.err.message || 'Error',
region: region
});
} else if (regionVal.data) {
// It's an array, loop
regionVal.data.forEach(function(regionData) {
var validated = evaluateConditions(regionData, input.conditions);
var parsedResource = parse(regionData, resourcePath);
if (typeof parsedResource !== 'string') parsedResource = null;

results.push({
status: validated.status,
resource: parsedResource,
message: validated.message,
region: region
});
});
} else {
for (var resourceName in regionVal) {
var resourceObj = regionVal[resourceName];
if (resourceObj.err) {
results.push({
status: 3,
resource: resourceName,
message: resourceObj.err.message || 'Error',
region: region
});
} else if (!resourceObj.data) {
results.push({
status: 3,
resource: resourceName,
message: 'No data returned',
region: region
});
} else {
var validated = evaluateConditions(resourceObj.data, input.conditions);
var parsedResource = parse(resourceObj.data, resourcePath);
if (typeof parsedResource !== 'string') parsedResource = null;

results.push({
status: validated.status,
resource: parsedResource ? parsedResource : resourceName,
message: validated.message,
region: region
});
}
}
}
}

callback(null, results, source[service][api]);
};

module.exports = asl;
Loading

0 comments on commit 837bb5b

Please sign in to comment.