Full Packet Capture (ipynb)
Contents
Full Packet Capture (ipynb)#
Steps below includes the implementation of necessary infrastructure (e.g. network, subnet, load balancer, compute instance(s), packet mirroring policy) at the analyst project to receive the captured packets.
Also includes setting up the target resource(s) (e.g. tagging, firewall rules) where packets would be captured from
Network traffic would be mirrored from target resource(s) to implemented infrastructure
Actual packet capture to
pcap
file still requires SSH into receiving compute instance and performingtcpdump
References
Install Dependencies#
Install the dependencies ipywidgets
and pandas
. Skip the next cell if they had already been installed.
!pip3 install ipywidgets pandas
Imports and Configuration#
import ipywidgets as widgets
import json
import os
import pandas as pd
from IPython.display import HTML, display
# extend width of widgets
display(HTML('''<style>
.widget-label { min-width: 28ex !important; font-weight:bold; }
</style>'''))
# extend width and max rows of pandas output
pd.set_option('display.max_colwidth', None)
pd.set_option('display.max_rows', None)
# [OPTIONAL] authenticate using your service account
!gcloud auth activate-service-account --key-file <json_key_file>
Define Environment Variables#
Specify the following information
Source Project
- Project id of target project (that contains potentially compromised compute instance)
# create text boxes for user input
src_project = widgets.Text(description = "Source Project: ", disabled=False, layout=widgets.Layout(width='40%'))
display(src_project)
# store user input in environment variables for use in subsequent comamnds
os.environ['SRC_PROJECT'] = src_project.value
# get zone, network, ip of VMs of interest in target (src) project
!gcloud compute instances list \
--project $SRC_PROJECT \
--format="table( \
name, \
zone.basename(), \
networkInterfaces[].network.basename(), \
networkInterfaces[].subnetwork.basename(), \
networkInterfaces[].networkIP, \
status)"
Specify the following information
Fields |
Description |
---|---|
Source (Target) |
|
|
Region of the compute instance to capture packets from (e.g. |
|
Zone of the compute instance to capture packets from (e.g. |
|
Name of network that contains the compute instance to capture packets from |
|
IP address range of network that contains the compute instance to capture packets from |
|
Name of compute instance to capture packets from |
Destination (Analyst) |
|
|
Project id of project where the compute instance to receive the packets would be created |
|
Name of network where the compute instance to receive the packets would be created |
|
Name of subnet where the compute instance to receive the packets would be created |
|
Subnet range of above subnet |
|
Name of instance group where the compute instance to receive the packets would be created |
|
Name of the created compute instance that would receive the packets |
|
IP address that would be used to SSH into the created compute instance that would receive the packets |
Network |
|
|
Name of tag to place on the compute instance to capture packets from |
|
Name of VPC network peering connection between the target network and the analyst network |
|
Name of health check (for load balancer which receives mirrored traffic) |
|
Name of backend (for load balancer which receives mirrored traffic) |
|
Name of frontend (for load balancer which receives mirrored traffic) |
|
Name of packet mirroring policy |
# create text boxes for user input
print("====== SOURCE (TARGET)======")
src_region = widgets.Text(description = "Source Region: ", disabled=False, layout=widgets.Layout(width='40%'))
src_zone = widgets.Text(description = "Source Zone: ", disabled=False, layout=widgets.Layout(width='40%'))
src_network = widgets.Text(value='default', description = "Source Network: ", disabled=False, layout=widgets.Layout(width='40%'))
src_ip_range = widgets.Text(description = "Source IP Range: ", disabled=False, layout=widgets.Layout(width='40%'))
src_vm = widgets.Text(description = "Source VM: ", disabled=False, layout=widgets.Layout(width='40%'))
display(src_region, src_zone, src_network, src_ip_range, src_vm)
print("====== DESTINATION (ANALYST)======")
dst_project = widgets.Text(description = "Destination Project: ", disabled=False, layout=widgets.Layout(width='40%'))
dst_network = widgets.Text(value='pc-network', description = "Destination Network: ", disabled=False, layout=widgets.Layout(width='40%'))
dst_subnet = widgets.Text(value='pc-subnet', description = "Destination Subnet: ", disabled=False, layout=widgets.Layout(width='40%'))
dst_subnet_range = widgets.Text(value='10.1.2.0/24', description = "Destination Subnet Range: ", disabled=False, layout=widgets.Layout(width='40%'))
dst_instance_grp = widgets.Text(value='pc-grp', description = "Destination Instance Grp: ", disabled=False, layout=widgets.Layout(width='40%'))
dst_vm = widgets.Text(value='pc-vm-1', description = "Destination VM: ", disabled=False, layout=widgets.Layout(width='40%'))
dst_ssh_ip = widgets.Text(description = "Destination SSH IP: ", disabled=False, layout=widgets.Layout(width='40%'))
display(dst_project, dst_network, dst_subnet, dst_subnet_range, dst_instance_grp, dst_vm, dst_ssh_ip, layout=widgets.Layout(width='40%'))
print("====== NETWORK ======")
mirror_network_tag = widgets.Text(value='pc-tag', description = "Mirror Network Tag: ", disabled=False, layout=widgets.Layout(width='40%'))
peering_name = widgets.Text(value='pc-peering', description = "VPC Peering Name: ", disabled=False, layout=widgets.Layout(width='40%'))
lb_hc_name = widgets.Text(value='pc-hc-ilb', description = "LB Health Check Name: ", disabled=False, layout=widgets.Layout(width='40%'))
lb_be_name = widgets.Text(value='pc-be-ilb', description = "LB Backend Name: ", disabled=False, layout=widgets.Layout(width='40%'))
lb_fe_name = widgets.Text(value='pc-fe-ilb', description = "LB Frontend Name: ", disabled=False, layout=widgets.Layout(width='40%'))
pm_policy_name = widgets.Text(value='pc-pmp', description = "Packet Mirroring Policy Name: ", disabled=False, layout=widgets.Layout(width='40%'))
display(mirror_network_tag, peering_name, lb_hc_name, lb_be_name, lb_fe_name, pm_policy_name)
# store user input in environment variables for use in subsequent comamnds
os.environ['SRC_REGION'] = src_region.value
os.environ['SRC_ZONE'] = src_zone.value
os.environ['SRC_NETWORK'] = src_network.value
os.environ['SRC_IP_RANGE'] = src_ip_range.value
os.environ['SRC_VM'] = src_vm.value
os.environ['DST_PROJECT'] = dst_project.value
os.environ['DST_NETWORK'] = dst_network.value
os.environ['DST_SUBNET'] = dst_subnet.value
os.environ['DST_SUBNET_RANGE'] = dst_subnet_range.value
os.environ['DST_INSTANCE_GRP'] = dst_instance_grp.value
os.environ['DST_SSH_IP'] = dst_ssh_ip.value
os.environ['DST_VM'] = dst_vm.value
os.environ['NETWORK_TAG'] = mirror_network_tag.value
os.environ['PEERING_NAME'] = peering_name.value
os.environ['FW_LB_RULE_NAME'] = dst_network.value + '-' + 'allow-lb-access'
os.environ['FW_HC_RULE_NAME'] = dst_network.value + '-' + 'allow-health-check'
os.environ['FW_SSH_RULE_NAME'] = dst_network.value + '-' + 'allow-ssh'
os.environ['FW_EGRESS_RULE_NAME'] = src_network.value + '-' + 'allow-all-egress'
os.environ['LB_HC_NAME'] = lb_hc_name.value
os.environ['LB_BE_NAME'] = lb_be_name.value
os.environ['LB_FE_NAME'] = lb_fe_name.value
os.environ['PM_POLICY_NAME'] = pm_policy_name.value
Create VPC Peering#
# create VPC network at analyst (dst) project
!gcloud compute networks create $DST_NETWORK \
--project $DST_PROJECT \
--subnet-mode=custom
print()
# create subnet in created VPC network at analyst (dst) project
!gcloud compute networks subnets create $DST_SUBNET \
--project $DST_PROJECT \
--network=$DST_NETWORK \
--range=$DST_SUBNET_RANGE \
--region=$SRC_REGION
# create VPC network peering connection from analyst (dst) project/network to target (src) project/network
!gcloud compute networks peerings create $PEERING_NAME \
--project $DST_PROJECT \
--network=$DST_NETWORK \
--peer-project $SRC_PROJECT \
--peer-network $SRC_NETWORK
print()
# create VPC network peering connection from target (src) project/network to analyst (dst) project/network
!gcloud compute networks peerings create $PEERING_NAME \
--project $SRC_PROJECT \
--network=$SRC_NETWORK \
--peer-project $DST_PROJECT \
--peer-network $DST_NETWORK
Setup Destination Collector#
# create VM instance group at analyst (dst) project
!gcloud compute instance-groups unmanaged create $DST_INSTANCE_GRP \
--project $DST_PROJECT \
--zone $SRC_ZONE
# following actions are performed at analyst (dst) project
# create VM instance for collection (modify as required)
!gcloud compute instances create $DST_VM \
--project $DST_PROJECT \
--zone $SRC_ZONE \
--machine-type=e2-highmem-4 \
--subnet=$DST_SUBNET \
--tags=allow-ssh,allow-health-check \
--create-disk=auto-delete=yes,boot=yes,device-name=$DST_VM,image-family=debian-10,image-project=debian-cloud,mode=rw,size=60,type=pd-ssd
print()
# add VM instance(s) to instance group
!gcloud compute instance-groups unmanaged add-instances $DST_INSTANCE_GRP \
--project $DST_PROJECT \
--zone=$SRC_ZONE \
--instances=$DST_VM
# duplicate as required
Create Firewall Rules#
# create firewall rules at analyst (dst) project
# allow all ingress traffic from target (src) project/network/VM
!gcloud compute firewall-rules create $FW_LB_RULE_NAME \
--project $DST_PROJECT \
--network=$DST_NETWORK \
--action=allow \
--direction=ingress \
--source-ranges=$SRC_IP_RANGE \
--rules=tcp,udp,icmp
print()
# allow all ingress traffic from health check IPs
!gcloud compute firewall-rules create $FW_HC_RULE_NAME \
--project $DST_PROJECT \
--network=$DST_NETWORK \
--action=allow \
--direction=ingress \
--target-tags=allow-health-check \
--source-ranges=130.211.0.0/22,35.191.0.0/16 \
--rules=tcp,udp,icmp
print()
# allow all ingress SSH traffic from specified IPs
!gcloud compute firewall-rules create $FW_SSH_RULE_NAME \
--project $DST_PROJECT \
--network=$DST_NETWORK \
--action=allow \
--direction=ingress \
--target-tags=allow-ssh \
--source-ranges=$DST_SSH_IP \
--rules=tcp,udp,icmp
# list egress firewall rules at target (src) project
!gcloud compute firewall-rules list \
--project $SRC_PROJECT \
--format='json' > src_fw_rules.json
with open('./src_fw_rules.json') as infile:
src_fw_rules_df = pd.json_normalize(json.load(infile))
desired_columns = ['name', 'network', 'priority', 'direction', 'targetTags', 'destinationRanges', 'denied', 'allowed']
columns = list(set(src_fw_rules_df.columns) & set(desired_columns))
display(src_fw_rules_df[columns]
.loc[src_fw_rules_df['direction'] == 'EGRESS']
.loc[src_fw_rules_df['network'].str.contains(src_network.value)])
# [optional] create allow all egress firewall rule at target (src) project
!gcloud compute firewall-rules create $FW_EGRESS_RULE_NAME \
--project $SRC_PROJECT \
--network=$SRC_NETWORK \
--action=allow \
--direction=egress \
--target-tags=$NETWORK_TAG \
--destination-ranges=0.0.0.0/0 \
--rules=tcp,udp,icmp
Implement Load Balancer#
# create a new regional HTTP health-check at analyst (dst) project
!gcloud compute health-checks create http $LB_HC_NAME \
--project $DST_PROJECT \
--region=$SRC_REGION \
--port=80
print()
# create backend service at analyst (dst) project
!gcloud compute backend-services create $LB_BE_NAME \
--project $DST_PROJECT \
--load-balancing-scheme=internal \
--protocol=tcp \
--region=$SRC_REGION \
--health-checks=$LB_HC_NAME \
--health-checks-region=$SRC_REGION
print()
# add instance group to backend service at analyst (dst) project
!gcloud compute backend-services add-backend $LB_BE_NAME \
--project $DST_PROJECT \
--region=$SRC_REGION \
--instance-group=$DST_INSTANCE_GRP \
--instance-group-zone=$SRC_ZONE
print()
# create forwarding rule at analyst (dst) project
!gcloud compute forwarding-rules create $LB_FE_NAME \
--project $DST_PROJECT \
--region=$SRC_REGION \
--load-balancing-scheme=internal \
--backend-service=$LB_BE_NAME \
--ports=all \
--is-mirroring-collector \
--network=$DST_NETWORK \
--subnet=$DST_SUBNET
Implement Packet Mirroring#
# tag vm to capture packets from at target (src) project
!gcloud compute instances add-tags $SRC_VM \
--project $SRC_PROJECT \
--zone $SRC_ZONE \
--tags $NETWORK_TAG
# duplicate as required
# create packet mirroring policy at analyst (dst) project
!gcloud compute packet-mirrorings create $PM_POLICY_NAME \
--project $DST_PROJECT \
--region=$SRC_REGION \
--network=projects/$SRC_PROJECT/global/networks/$SRC_NETWORK \
--mirrored-tags=$NETWORK_TAG \
--collector-ilb=$LB_FE_NAME
Capture Packets#
SSH into
$DST_VM
-gcloud compute ssh $DST_VM -project $DST_PROJECT -zone $SRC_ZONE
Install tcpdump -
sudo apt-get update
,sudo apt install tcpdump -y
sudo /usr/sbin/tcpdump port not 22 -w pc.pcap
Cleanup#
# at target (src) project
# delete firewall rule
!gcloud compute firewall-rules delete $FW_EGRESS_RULE_NAME --project $SRC_PROJECT --quiet
print()
# delete VPC peering
!gcloud compute networks peerings delete $PEERING_NAME \
--project $SRC_PROJECT \
--network=$SRC_NETWORK
print()
# remove tag from VM
!gcloud compute instances remove-tags $SRC_VM \
--project $SRC_PROJECT \
--zone $SRC_ZONE \
--tags $NETWORK_TAG
# at analyst (dst) project
# delete packet mirroring policy
!gcloud compute packet-mirrorings delete $PM_POLICY_NAME --quiet \
--project $DST_PROJECT \
--region=$SRC_REGION
print()
# delete LB forwarding rule
!gcloud compute forwarding-rules delete $LB_FE_NAME --quiet \
--project $DST_PROJECT \
--region=$SRC_REGION
print()
# delete LB backend service
!gcloud compute backend-services delete $LB_BE_NAME --quiet \
--project $DST_PROJECT \
--region=$SRC_REGION
print()
# delete LB health check
!gcloud compute health-checks delete $LB_HC_NAME --quiet \
--project $DST_PROJECT \
--region=$SRC_REGION
print()
# delete firewall rules
!gcloud compute firewall-rules delete $FW_HC_RULE_NAME --project $DST_PROJECT --quiet
print()
!gcloud compute firewall-rules delete $FW_LB_RULE_NAME --project $DST_PROJECT --quiet
print()
!gcloud compute firewall-rules delete $FW_SSH_RULE_NAME --project $DST_PROJECT --quiet
print()
# delete VM(s)
!gcloud compute instances delete $DST_VM --quiet \
--project $DST_PROJECT \
--zone $SRC_ZONE
print()
# delete VM instance group
!gcloud compute instance-groups unmanaged delete $DST_INSTANCE_GRP --quiet \
--project $DST_PROJECT \
--zone $SRC_ZONE
print()
# delete subnet
!gcloud compute networks subnets delete $DST_SUBNET --quiet \
--project $DST_PROJECT \
--region $SRC_REGION
print()
# delete network
!gcloud compute networks delete $DST_NETWORK --project $DST_PROJECT --quiet
print()
# remove files
!rm ./src_fw_rules.json