Skip to content

Commit

Permalink
bundles_sync/08_11_24
Browse files Browse the repository at this point in the history
  • Loading branch information
alphadev4 committed Nov 8, 2024
1 parent 9757849 commit 981b0df
Show file tree
Hide file tree
Showing 7 changed files with 450 additions and 95 deletions.
253 changes: 190 additions & 63 deletions helpers/aws/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1148,8 +1148,7 @@ var checkTags = function(cache, resourceName, resourceList, region, results, set
});
};


function checkSecurityGroup(securityGroup, cache, region) {
function checkSecurityGroup(securityGroup, cache, region, checkENIs = true) {
let allowsAllTraffic;
for (var p in securityGroup.IpPermissions) {
var permission = securityGroup.IpPermissions[p];
Expand All @@ -1171,15 +1170,84 @@ function checkSecurityGroup(securityGroup, cache, region) {
}
}

if (allowsAllTraffic) {
if (allowsAllTraffic && checkENIs) {
return checkNetworkInterface(securityGroup.GroupId, securityGroup.GroupName, '', region, null, securityGroup, cache, true);
}
return false;
return allowsAllTraffic;
}

var checkNetworkExposure = function(cache, source, subnetId, securityGroups, region, results) {
var getAttachedELBs = function(cache, source, region, resourceId, lbField, lbAttribute) {
let elbs = [];

// check classice ELBs
var describeLoadBalancers = helpers.addSource(cache, source,
['elb', 'describeLoadBalancers', region]);

if (describeLoadBalancers && !describeLoadBalancers.err && describeLoadBalancers.data && describeLoadBalancers.data.length) {
elbs = describeLoadBalancers.data.filter(lb => lb[lbField] && lb[lbField].some(instance => instance[lbAttribute] === resourceId));
}

// check ALBs/NLBs

var describeLoadBalancersv2 = helpers.addSource(cache, source,
['elbv2', 'describeLoadBalancers', region]);

if (describeLoadBalancersv2 && !describeLoadBalancersv2.err && describeLoadBalancersv2.data && describeLoadBalancersv2.data.length) {
describeLoadBalancersv2.data.forEach(function(lb) {
lb.targetGroups = [];
var describeTargetGroups = helpers.addSource(cache, source,
['elbv2', 'describeTargetGroups', region, lb.DNSName]);

if (describeTargetGroups && !describeTargetGroups.err && describeTargetGroups.data && describeTargetGroups.data.TargetGroups && describeTargetGroups.data.TargetGroups.length) {
describeTargetGroups.data.TargetGroups.forEach(function(tg) {
var describeTargetHealth = helpers.addSource(cache, source,
['elbv2', 'describeTargetHealth', region, tg.TargetGroupArn]);

if (describeTargetHealth && !describeTargetHealth.err && describeTargetHealth.data
&& describeTargetHealth.data.TargetHealthDescriptions && describeTargetHealth.data.TargetHealthDescriptions.length) {
describeTargetHealth.data.TargetHealthDescriptions.forEach(healthDescription => {
if (healthDescription.Target && healthDescription.Target.Id &&
healthDescription.Target.Id === resourceId) {
lb.targetGroups.push({targetgroupName: tg.TargetGroupName, targetGroupArn: tg.TargetGroupArn});
}
});
}
});
}

if (lb.targetGroups && lb.targetGroups.length) {
let hasListener = false;
var describeListeners = helpers.addSource(cache, source,
['elbv2', 'describeListeners', region, lb.DNSName]);
if (describeListeners && describeListeners.data && describeListeners.data.Listeners && describeListeners.data.Listeners.length) {
describeListeners.data.Listeners.forEach(listener => {
if (!hasListener) {
hasListener = listener.DefaultActions.some(action =>
action.TargetGroupArn && lb.targetGroups.some(tg => tg.targetGroupArn === action.TargetGroupArn)
);
}

});
}
if (hasListener) {
elbs.push(lb);
}
}
});
}

return elbs;
};

var checkNetworkExposure = function(cache, source, subnets, securityGroups, elbs, region, results, resource) {

var internetExposed = '';
var isSubnetPrivate = false;

// Check public endpoint access for specific resources like EKS
if (resource && resource.resourcesVpcConfig && resource.resourcesVpcConfig.endpointPublicAccess) {
return 'public endpoint access';
}
// Scenario 1: check if resource is in a private subnet
let subnetRouteTableMap, privateSubnets;
var describeSubnets = helpers.addSource(cache, source,
Expand All @@ -1193,80 +1261,139 @@ var checkNetworkExposure = function(cache, source, subnetId, securityGroups, reg
} else if (!describeSubnets || describeSubnets.err || !describeSubnets.data) {
helpers.addResult(results, 3,
'Unable to query for subnets: ' + helpers.addError(describeSubnets), region);
} else if (describeSubnets.data.length && subnetId) {
} else if (describeSubnets.data.length && subnets.length) {
subnetRouteTableMap = getSubnetRTMap(describeSubnets.data, describeRouteTables.data);
privateSubnets = getPrivateSubnets(subnetRouteTableMap, describeSubnets.data, describeRouteTables.data);
if (privateSubnets && privateSubnets.length && privateSubnets.find(subnet => subnet === subnetId)) {
if (privateSubnets && privateSubnets.length) {
isSubnetPrivate = !subnets.some(subnet => !privateSubnets.includes(subnet.id));
}

// if it's in a private subnet and has no ELBs attached then its not exposed
if (isSubnetPrivate && (!elbs || !elbs.length)) {
return '';
}
// If the subnet is not private we will check if security groups and Network ACLs allow internal traffic
}

// If the subnet is not private we will check if security groups and Network ACLs allow internal traffic

// Scenario 2: check if security group allows all traffic
var describeSecurityGroups = helpers.addSource(cache, source,
['ec2', 'describeSecurityGroups', region]);

if (!isSubnetPrivate) {
if (!describeSecurityGroups || describeSecurityGroups.err || !describeSecurityGroups.data) {
helpers.addResult(results, 3,
'Unable to query for security groups: ' + helpers.addError(describeSecurityGroups), region);
} else if (describeSecurityGroups.data.length && securityGroups && securityGroups.length) {
let instanceSGs = describeSecurityGroups.data.filter(sg => securityGroups.find(isg => isg.GroupId === sg.GroupId));
for (var group of instanceSGs) {
let exposedSG = checkSecurityGroup(group, cache, region);
if (exposedSG) {
internetExposed += internetExposed ? `, ${exposedSG}` : exposedSG;
}
}
}


if (!describeSecurityGroups || describeSecurityGroups.err || !describeSecurityGroups.data) {
helpers.addResult(results, 3,
'Unable to query for security groups: ' + helpers.addError(describeSecurityGroups), region);
} else if (describeSecurityGroups.data.length && securityGroups && securityGroups.length) {
let instanceSGs = describeSecurityGroups.data.filter(sg => securityGroups.find(isg => isg.GroupId === sg.GroupId));
for (var group of instanceSGs) {
let exposedSG = checkSecurityGroup(group, cache, region);
if (!exposedSG) {
return '';
} else {
internetExposed += exposedSG;
// if security group allows all traffic we need to check NACLs
if (internetExposed.length) {
let subnetIds = subnets.map(s => s.id);
// Scenario 3: check if Network ACLs associated with the resource allow all traffic
var describeNetworkAcls = helpers.addSource(cache, source,
['ec2', 'describeNetworkAcls', region]);

if (!describeNetworkAcls || describeNetworkAcls.err || !describeNetworkAcls.data) {
helpers.addResult(results, 3,
`Unable to query for Network ACLs: ${helpers.addError(describeNetworkAcls)}`, region);
} else if (describeNetworkAcls.data.length && subnetIds) {
let naclDeny = true;
for (let subnetId of subnetIds) {
let instanceACL = describeNetworkAcls.data.find(acl => acl.Associations.find(assoc => assoc.SubnetId === subnetId));
if (instanceACL && instanceACL.Entries && instanceACL.Entries.length) {
const allowRules = instanceACL.Entries.filter(entry =>
entry.Egress === false &&
entry.RuleAction === 'allow' &&
(entry.CidrBlock === '0.0.0.0/0' || entry.Ipv6CidrBlock === '::/0')
);

const denyIPv4 = instanceACL.Entries.find(entry =>
entry.Egress === false &&
entry.RuleAction === 'deny' &&
entry.CidrBlock === '0.0.0.0/0'
);

const denyIPv6 = instanceACL.Entries.find(entry =>
entry.Egress === false &&
entry.RuleAction === 'deny' &&
entry.Ipv6CidrBlock === '::/0'
);

let exposed = allowRules.some(allowRule => {
return !instanceACL.Entries.some(denyRule => {
return (
denyRule.Egress === false &&
denyRule.RuleAction === 'deny' &&
(
(allowRule.CidrBlock && denyRule.CidrBlock === allowRule.CidrBlock) ||
(allowRule.Ipv6CidrBlock && denyRule.Ipv6CidrBlock === allowRule.Ipv6CidrBlock)
) &&
denyRule.Protocol === allowRule.Protocol &&
(
denyRule.PortRange ?
(allowRule.PortRange &&
denyRule.PortRange.From === allowRule.PortRange.From &&
denyRule.PortRange.To === allowRule.PortRange.To) : true
) &&
denyRule.RuleNumber < allowRule.RuleNumber
);
});
});

// exposed - if NACL has an allow all rule
if (exposed) {
internetExposed += `, nacl ${instanceACL.NetworkAclId}`;
}

// not exposed - if NACL has a deny rule
if (exposed || !denyIPv4 || !denyIPv6) {
naclDeny = false;
}
} else {
naclDeny = false;
}
}

// not exposed - if all NACLs have deny rules
if (naclDeny) {
return '';
}
}

}
}

// if there are no explicit allow or deny rules, we look at ELBs


// Scenario 3: check if Network ACLs associated with the resource allow all traffic
var describeNetworkAcls = helpers.addSource(cache, source,
['ec2', 'describeNetworkAcls', region]);
if (elbs && elbs.length) {
for (const lb of elbs) {

if (!describeNetworkAcls || describeNetworkAcls.err || !describeNetworkAcls.data) {
helpers.addResult(results, 3,
`Unable to query for Network ACLs: ${helpers.addError(describeNetworkAcls)}`, region);
} else if (describeNetworkAcls.data.length && subnetId) {
let instanceACL = describeNetworkAcls.data.find(acl => acl.Associations.find(assoc => assoc.SubnetId === subnetId));
if (instanceACL && instanceACL.Entries && instanceACL.Entries.length) {

const allowRules = instanceACL.Entries.filter(entry =>
entry.Egress === false &&
entry.RuleAction === 'allow' &&
(entry.CidrBlock === '0.0.0.0/0' || entry.Ipv6CidrBlock === '::/0')
);


// Checking if there's a deny rule with lower rule number
let exposed = allowRules.some(allowRule => {
// Check if there's a deny with a lower rule number
return !instanceACL.Entries.some(denyRule => {
return (
denyRule.Egress === false &&
denyRule.RuleAction === 'deny' &&
(
(allowRule.CidrBlock && denyRule.CidrBlock === allowRule.CidrBlock) ||
(allowRule.Ipv6CidrBlock && denyRule.Ipv6CidrBlock === allowRule.Ipv6CidrBlock)
) &&
denyRule.Protocol === allowRule.Protocol &&
(
denyRule.PortRange ?
(allowRule.PortRange &&
denyRule.PortRange.From === allowRule.PortRange.From &&
denyRule.PortRange.To === allowRule.PortRange.To) : true
) &&
denyRule.RuleNumber < allowRule.RuleNumber
);
});
});
if (exposed) {
internetExposed += `> nacl ${instanceACL.NetworkAclId}`;
} else {
internetExposed = '';
let isLBPublic = false;
if (lb.Scheme && lb.Scheme.toLowerCase() === 'internet-facing') {
if (lb.SecurityGroups && lb.SecurityGroups.length && describeSecurityGroups &&
!describeSecurityGroups.err && describeSecurityGroups.data && describeSecurityGroups.data.length) {
let elbSGs = describeSecurityGroups.data.filter(sg => lb.SecurityGroups.includes(sg.GroupId));
for (var elbSG of elbSGs) {
let exposedSG = checkSecurityGroup(elbSG, cache, region, false);
if (exposedSG) {
isLBPublic = true;
}
}
}
}

if (isLBPublic) {
internetExposed += internetExposed.length ? `, elb ${lb.LoadBalancerName}`: `elb ${lb.LoadBalancerName}`;
}
}
}
Expand Down Expand Up @@ -1312,6 +1439,6 @@ module.exports = {
processFieldSelectors: processFieldSelectors,
checkNetworkInterface: checkNetworkInterface,
checkNetworkExposure: checkNetworkExposure,

getAttachedELBs: getAttachedELBs
};

33 changes: 28 additions & 5 deletions helpers/azure/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -775,20 +775,43 @@ function checkSecurityGroup(securityGroups) {
return {exposed: true};
}

function checkNetworkExposure(cache, source, networkInterfaces, securityGroups, region, results) {
function checkNetworkExposure(cache, source, networkInterfaces, securityGroups, location, results, lbNames) {
let exposedPath = '';

if (securityGroups && securityGroups.length) {
// Scenario 1: check if security group allow all inbound traffic
let exposedSG = checkSecurityGroup(securityGroups);
if (exposedSG && exposedSG.exposed) {
if (exposedSG.nsg) {
exposedPath += `nsg ${exposedSG.nsg}`
return `nsg ${exposedSG.nsg}`
} else {
return '';
}
}
}

return exposedPath
if (lbNames && lbNames.length) {
const loadBalancers = shared.addSource(cache, source,
['loadBalancers', 'listAll', location]);

if (loadBalancers && !loadBalancers.err && loadBalancers.data && loadBalancers.data.length) {
let resourceLBs = loadBalancers.data.filter(lb => lbNames.includes(lb.id));
if (resourceLBs && resourceLBs.length) {
for (let lb of resourceLBs) {
let isPublic = false;
if (lb.frontendIPConfigurations && lb.frontendIPConfigurations.length) {
isPublic = lb.frontendIPConfigurations.some(ipConfig => ipConfig.properties
&& ipConfig.properties.publicIPAddress && ipConfig.properties.publicIPAddress.id);
if (isPublic && ((lb.nboundNatRules && nboundNatRules.length) || (lb.loadBalancingRules && lb.loadBalancingRules.length))) {
exposedPath += `lb ${lb.name}`;
break;
}
}
}
}
}
}
return exposedPath;
}

module.exports = {
Expand All @@ -803,7 +826,7 @@ module.exports = {
remediateOpenPorts: remediateOpenPorts,
remediateOpenPortsHelper: remediateOpenPortsHelper,
checkMicrosoftDefender: checkMicrosoftDefender,
checkFlexibleServerConfigs: checkFlexibleServerConfigs,
checkNetworkExposure: checkNetworkExposure,
checkFlexibleServerConfigs:checkFlexibleServerConfigs,
checkNetworkExposure: checkNetworkExposure

};
Loading

0 comments on commit 981b0df

Please sign in to comment.