Skip to content

Instantly share code, notes, and snippets.

@nullenc0de
Created February 19, 2025 03:12
Show Gist options
  • Save nullenc0de/a076a1a2ba01d7bedebf9ea57acf243f to your computer and use it in GitHub Desktop.
Save nullenc0de/a076a1a2ba01d7bedebf9ea57acf243f to your computer and use it in GitHub Desktop.
Egress_segment.sh
#!/bin/bash
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Function to discover networks
discover_networks() {
echo "Discovering network segments..."
declare -gA SEGMENTS
# Read local routes
while read -r line; do
if [[ $line =~ ^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+) ]]; then
network="${BASH_REMATCH[1]}"
# Skip loopback and default routes
if [[ $network != "127.0.0.0/8" && $network != "0.0.0.0/0" ]]; then
# Try to determine segment type based on IP range
if [[ $network == "10.152.10.0/24" ]]; then
SEGMENTS["CDE"]=$network
elif [[ $network == "192.168."* ]]; then
SEGMENTS["DMZ"]=$network
elif [[ $network == "10.191."* ]]; then
if [[ $network == "10.191.10.0/24" ]]; then
SEGMENTS["Corporate"]=$network
elif [[ $network == "10.191.20.0/24" ]]; then
SEGMENTS["Development"]=$network
fi
fi
fi
fi
done < <(ip route show)
echo "Discovered segments:"
for segment in "${!SEGMENTS[@]}"; do
echo " $segment: ${SEGMENTS[$segment]}"
done
}
# Function to determine allowed paths based on common rules
determine_allowed_paths() {
echo "Determining allowed communication paths..."
declare -ga ALLOWED_PATHS=()
# Add standard paths based on best practices
if [[ -n "${SEGMENTS[Corporate]}" && -n "${SEGMENTS[CDE]}" ]]; then
ALLOWED_PATHS+=("Corporate:CDE:443") # HTTPS access to CDE
fi
if [[ -n "${SEGMENTS[DMZ]}" && -n "${SEGMENTS[CDE]}" ]]; then
ALLOWED_PATHS+=("DMZ:CDE:443") # HTTPS access from DMZ to CDE
fi
if [[ -n "${SEGMENTS[Corporate]}" && -n "${SEGMENTS[DMZ]}" ]]; then
ALLOWED_PATHS+=("Corporate:DMZ:80") # HTTP access to DMZ
ALLOWED_PATHS+=("Corporate:DMZ:443") # HTTPS access to DMZ
fi
echo "Determined allowed paths:"
for path in "${ALLOWED_PATHS[@]}"; do
echo " $path"
done
}
# Initialize network configuration
discover_networks
determine_allowed_paths
# Allow manual override of detected configuration
if [[ -f "network_config.txt" ]]; then
echo "Found network_config.txt - loading manual configuration..."
source network_config.txt
fi
# Define egress test ports
declare -a TEST_PORTS=(
"21" # FTP
"22" # SSH
"23" # Telnet
"25" # SMTP
"53" # DNS
"80" # HTTP
"443" # HTTPS
"3389" # RDP
"8080" # Alt HTTP
"8443" # Alt HTTPS
)
# Test domains for egress
EGRESS_TEST_DOMAIN="letmeoutofyour.net"
RESPONSE_CHECK="w00tw00t"
echo -e "${BLUE}Starting PCI DSS v4.0 Network Testing...${NC}"
echo "Testing from IP: $(ip route get 1 | awk '{print $(NF-2);exit}')"
echo "----------------------------------------"
# Function to test TCP connectivity
test_tcp() {
local host=$1
local port=$2
timeout 2 nc -zv -w 2 $host $port &>/dev/null
return $?
}
# Function to get a random IP from a subnet
get_random_ip() {
local subnet=$1
local network=$(echo $subnet | cut -d/ -f1)
local netmask=$(echo $subnet | cut -d/ -f2)
local prefix=$(echo $network | cut -d. -f1-3)
local random_last=$((RANDOM % 254 + 1))
echo "${prefix}.${random_last}"
}
# Function to test egress connectivity
test_egress() {
local port=$1
local protocol=$2
echo -e "\n${YELLOW}Testing egress on port $port ($protocol)${NC}"
case $protocol in
"TCP")
# Try HTTP/HTTPS connection
if [[ $port == "80" || $port == "443" ]]; then
response=$(curl -s -m 5 ${protocol,,}://$EGRESS_TEST_DOMAIN:$port 2>/dev/null)
if [[ $response == *"$RESPONSE_CHECK"* ]]; then
echo -e "${RED}WARNING: Egress allowed on port $port${NC}"
return 0
fi
fi
# Try direct TCP connection
if nc -zv -w 5 $EGRESS_TEST_DOMAIN $port 2>/dev/null; then
echo -e "${RED}WARNING: Egress allowed on port $port${NC}"
return 0
fi
;;
"UDP")
# Try UDP connection
echo "Testing UDP..." | nc -u -w 5 $EGRESS_TEST_DOMAIN $port &>/dev/null
if [[ $? -eq 0 ]]; then
echo -e "${RED}WARNING: UDP egress allowed on port $port${NC}"
return 0
fi
;;
esac
echo -e "${GREEN}Egress blocked on port $port${NC}"
return 1
}
echo -e "\n${BLUE}Phase 1: Testing Network Segmentation${NC}"
# Test allowed paths
for path in "${ALLOWED_PATHS[@]}"; do
IFS=':' read -r source_seg dest_seg port <<< "$path"
echo -e "\nTesting $source_seg to $dest_seg on port $port"
source_ip=$(get_random_ip "${SEGMENTS[$source_seg]}")
dest_ip=$(get_random_ip "${SEGMENTS[$dest_seg]}")
if test_tcp $dest_ip $port; then
echo -e "${GREEN}SUCCESS - Connection allowed as expected${NC}"
else
echo -e "${RED}FAIL - Expected connection blocked${NC}"
fi
done
# Test segment isolation
for source_seg in "${!SEGMENTS[@]}"; do
for dest_seg in "${!SEGMENTS[@]}"; do
if [ "$source_seg" != "$dest_seg" ]; then
# Skip allowed paths
skip=false
for allowed in "${ALLOWED_PATHS[@]}"; do
IFS=':' read -r as ds port <<< "$allowed"
if [ "$source_seg" == "$as" ] && [ "$dest_seg" == "$ds" ]; then
skip=true
break
fi
done
if [ "$skip" == "false" ]; then
source_ip=$(get_random_ip "${SEGMENTS[$source_seg]}")
dest_ip=$(get_random_ip "${SEGMENTS[$dest_seg]}")
echo -e "\nTesting isolation between $source_seg and $dest_seg"
for port in "${TEST_PORTS[@]}"; do
if test_tcp $dest_ip $port; then
echo -e "${RED}FAIL - Unexpected access allowed on port $port${NC}"
else
echo -e "${GREEN}SUCCESS - Connection blocked as expected on port $port${NC}"
fi
done
fi
fi
done
done
echo -e "\n${BLUE}Phase 2: Testing Egress Controls${NC}"
# Test egress using letmeoutofyour.net
echo "Testing egress using $EGRESS_TEST_DOMAIN"
# Test TCP ports
for port in "${TEST_PORTS[@]}"; do
test_egress $port "TCP"
done
# Test UDP ports
for port in "${TEST_PORTS[@]}"; do
test_egress $port "UDP"
done
# Test DNS exfiltration
echo -e "\n${YELLOW}Testing DNS Exfiltration${NC}"
if host "test.$EGRESS_TEST_DOMAIN" &>/dev/null; then
echo -e "${RED}WARNING: DNS queries to external domains allowed${NC}"
else
echo -e "${GREEN}SUCCESS - DNS queries restricted${NC}"
fi
echo -e "\n${BLUE}Testing Complete${NC}"
echo "Review results against network diagrams and PCI requirements"
echo "Remember to test from multiple network segments for comprehensive coverage"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment