Skip to content

Commit

Permalink
Removing netifaces due to lack of maintainer (#519)
Browse files Browse the repository at this point in the history
* removed dependency on netifaces entirely by using psutil and manually parsing /proc/net/route to figure out default gateway

* Checking if /proc/net/route is accessible. before commiting to parse it

* changed to using pyroute2 instead of manually parsing /proc/net/route and psutil for interface enum

* added pyroute2 as a dependency

* fixed bug in subnets appending

* added windows support using a powershell snippet for interface enum
  • Loading branch information
danielsagi authored Aug 25, 2022
1 parent a578726 commit eb31026
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 8 deletions.
86 changes: 79 additions & 7 deletions kube_hunter/modules/discovery/hosts.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import json
import os
import sys
import socket
import logging
import itertools
import requests

from enum import Enum
from netaddr import IPNetwork, IPAddress, AddrFormatError
from netifaces import AF_INET, ifaddresses, interfaces, gateways

from kube_hunter.conf import get_config
from kube_hunter.modules.discovery.kubernetes_client import list_all_k8s_cluster_nodes
Expand Down Expand Up @@ -137,7 +139,9 @@ def execute(self):
elif self.is_aws_pod_v2():
subnets, cloud = self.aws_metadata_v2_discovery()

subnets += self.gateway_discovery()
gateway_subnet = self.gateway_discovery()
if gateway_subnet:
subnets.append(gateway_subnet)

should_scan_apiserver = False
if self.event.kubeservicehost:
Expand Down Expand Up @@ -217,7 +221,26 @@ def is_azure_pod(self):
# for pod scanning
def gateway_discovery(self):
"""Retrieving default gateway of pod, which is usually also a contact point with the host"""
return [[gateways()["default"][AF_INET][0], "24"]]
# read the default gateway directly from /proc
# netifaces currently does not have a maintainer. so we backported to linux support only for this cause.
# TODO: implement WMI queries for windows support
# https://stackoverflow.com/a/6556951
if sys.platform in ["linux", "linux2"]:
try:
from pyroute2 import IPDB

ip = IPDB()
gateway_ip = ip.routes["default"]["gateway"]
ip.release()
return [gateway_ip, "24"]
except Exception as x:
logging.debug(f"Exception while fetching default gateway from container - {x}")
finally:
ip.release()
else:
logging.debug("Not running in a linux env, will not scan default subnet")

return False

# querying AWS's interface metadata api v1 | works only from a pod
def aws_metadata_v1_discovery(self):
Expand Down Expand Up @@ -338,13 +361,62 @@ def scan_interfaces(self):

# generate all subnets from all internal network interfaces
def generate_interfaces_subnet(self, sn="24"):
for ifaceName in interfaces():
for ip in [i["addr"] for i in ifaddresses(ifaceName).setdefault(AF_INET, [])]:
if not self.event.localhost and InterfaceTypes.LOCALHOST.value in ip.__str__():
if sys.platform == "win32":
return self.generate_interfaces_subnet_windows()
elif sys.platform in ["linux", "linux2"]:
return self.generate_interfaces_subnet_linux()

def generate_interfaces_subnet_linux(self, sn="24"):
try:
from pyroute2 import IPRoute

ip = IPRoute()
for i in ip.get_addr():
# whitelist only ipv4 ips
if i["family"] == socket.AF_INET:
ipaddress = i[0].get_attr("IFA_ADDRESS")
# TODO: add this instead of hardcoded 24 subnet, (add a flag for full scan option)
# subnet = i['prefixlen']

# unless specified explicitly with localhost scan flag, skip localhost ip addresses
if not self.event.localhost and ipaddress.startswith(InterfaceTypes.LOCALHOST.value):
continue

ip_network = IPNetwork(f"{ipaddress}/{sn}")
for ip in ip_network:
yield ip
except Exception as x:
logging.debug(f"Exception while generating subnet scan from local interfaces: {x}")
finally:
ip.release()

def generate_interfaces_subnet_windows(self, sn="24"):
from subprocess import check_output

local_subnets = (
check_output(
"powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy bypass -Command "
' "& {'
"Get-NetIPConfiguration | Get-NetIPAddress | Where-Object {$_.AddressFamily -eq 'IPv4'}"
" | Select-Object -Property IPAddress, PrefixLength | ConvertTo-Json "
' "}',
shell=True,
)
.decode()
.strip()
)
try:
subnets = json.loads(local_subnets)
for subnet in subnets:
if not self.event.localhost and subnet["IPAddress"].startswith(InterfaceTypes.LOCALHOST.value):
continue
for ip in IPNetwork(f"{ip}/{sn}"):
ip_network = IPNetwork(f"{subnet['IPAddress']}/{sn}")
for ip in ip_network:
yield ip

except Exception as x:
logging.debug(f"ERROR: Could not extract interface information using powershell - {x}")


# for comparing prefixes
class InterfaceTypes(Enum):
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ zip_safe = False
packages = find:
install_requires =
netaddr
netifaces
pyroute2
requests
PrettyTable
urllib3>=1.24.3
Expand Down

0 comments on commit eb31026

Please sign in to comment.