====== Tcpdump via API ====== The script uses the ability to initiate commands on a BigIP via the RESTAPI. tcpdum has a special flag "--f5 ssl", introduced in version 15.0, which makes it save the master secret inside the pcap file. This enables Wireshark to decyrpt TLS connections and give access to L7 information. The flag needs to be turned on via the db variable "tcpdump.sslprovider" before it collects the master secrets and it is automatically reset to off after reboot. As this can pose as a security risk we only have it turned on while running the tcpdump and when the command has finished it gets turned off again. The script requires that you have an account with admin privileges and the host the script runs from can access the BigIP. The decryption locally is done via tshark, so that needs to be installed as well. #!/bin/bash # Utility functions. It takes two parameters, first is the text and the second is the default value. # If no default value is supplied it will loop until something is entered. function prompt_user { read -p "${1} (default: [${2}]): " input echo "${input:-${2}}" } function prompt_bigip_address { read -p "BIG-IP address [default: https://10.1.1.10]: " BIGIP # Assign a default value if nothing is entered BIGIP="${BIGIP:-https://10.1.1.10}" # Make sure that the address is prefixed with https if only an IP address is entered BIGIP="https://${BIGIP#https://}" } function prompt_credentials { read -p "BIG-IP username [default: admin]: " USER USER="${USER:-admin}" read -s -p "BIG-IP password: " PASS echo "" } function get_token { # Authenticate and get auth token TOKEN=$(curl -skf -H "Content-Type: application/json" -d '{"username":"'$USER'","password":"'$PASS'","loginProviderName":"tmos"}' "$BIGIP/mgmt/shared/authn/login" | grep -oP '(?<="token":")[^"]+') } function delete_token { # Delete token curl -sk -H "X-F5-Auth-Token: $TOKEN" -X DELETE "$BIGIP/mgmt/shared/authz/tokens/$TOKEN"| jq -r '.|{"Deleted token": .token}' } function toggle_ssl_provider { # Toggle the "sys db tcpdump.sslprovider" variable local value=${1} curl -sk -X PATCH -H "Content-Type: application/json" -H "X-F5-Auth-Token: $TOKEN" "$BIGIP/mgmt/tm/sys/db/tcpdump.sslprovider" -d '{"value": "'$value'"}' } function download_file { # Download the pcap file from the filesystem "/share/images/encrypt_autocap_*.pcap" local file="${1}" message="${2}" curl -skf -H "X-F5-Auth-Token: $TOKEN" "$BIGIP/mgmt/cm/autodeploy/software-image-downloads/$file" -o "$file" if [ "$?" -eq 0 ]; then echo -e "\t$message" else echo -e "\tDOWNLOAD FAILED!!!" fi } function delete_file { # Delete the pcap file from the filesystem "/share/images/encrypt_autocap_*.pcap" local file="${1}" message="${2}" curl -skf -X POST -H "X-F5-Auth-Token: $TOKEN" -H "Content-Type: application/json" "$BIGIP/mgmt/tm/util/unix-rm" -d '{"command": "run", "utilCmdArgs": "/shared/images/'$file'"}' if [ "$?" -eq 0 ]; then echo -e "\t$message" else echo -e "\tDELETE FAILED!!!" fi } # Main function function main { # Get user inputs partition=$(prompt_user "Which partition: " "Common") vip_name="" while [[ -z $vip_name ]]; do vip_name=$(prompt_user "Virtual name" "") done duration=$(prompt_user "Duration in seconds for capture: " "30") filters=$(prompt_user "Capture filters in addition to vip [ex. \"and (port 80 or port 443)\"]: ") # Prep variables for execution datestring=$(date +%Y%m%d-%H%M%S) tcpdump_file="autocap_$datestring.pcap" tcpdump_file_encrypt="encrypt_$tcpdump_file" tcpdump_file_decrypt="decrypt_$tcpdump_file" pms_file="pms_$datestring.key" payload="payload.json" # Regular expression to match an IP address IP_REGEX='^((25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})$' # Get the IP of the virtual server virtual_ip=$(curl -skf -H "X-F5-Auth-Token: $TOKEN" "$BIGIP/mgmt/tm/ltm/virtual/~$partition~$vip_name" | jq -r '.destination | split(":") | .[0]'|awk -F/ '{print $3}') # Check if virtual IP is a valid IP address if [[ ! $virtual_ip =~ $IP_REGEX ]]; then echo "Error: virtual IP '$virtual_ip' is not a valid IP address - Did you spell the VS correctly?" exit 1 fi # Build command execution string and dump it into a payload file as a json array to be read by curl tcpdump_bash_string=(timeout -s SIGKILL $duration tcpdump -s0 -nni 0.0:nnnp --f5 ssl:v host $virtual_ip $filters -w /shared/images/$tcpdump_file_encrypt) echo "{\"command\":\"run\",\"utilCmdArgs\":\"-c '${tcpdump_bash_string[@]}'\"}" > $payload # Run tcpdump echo -e "\tStarting tcpdump...please reproduce your issue now." output=$(curl -sk -X POST -H "Content-Type: application/json" -H "X-F5-Auth-Token: $TOKEN" "$BIGIP/mgmt/tm/util/bash" -d @$payload) #curl -skf -X POST -H "Content-Type: application/json" -H "X-F5-Auth-Token: $TOKEN" "$BIGIP/mgmt/tm/util/bash" -d '{"command":"run","utilCmdArgs":"-c "'${tcpdump_bash_string[@]}'""}' sleep 5 echo -e "\ttcpdump complete...continuing." # Download tcpdump capture from BIG-IP echo -e "\nDownloading tcpdump capture from BIG-IP..." download_file $tcpdump_file_encrypt "\tDownload complete!" # Delete tcpdump capture on BIG-IP echo -e "\nDeleting tcpdump capture on BIG-IP..." delete_file $tcpdump_file_encrypt "\tDeletion complete!" # Extract session keys from tcpdump capture echo -e "\nExtracting session keys from tcpdump capture..." tshark -r $tcpdump_file_encrypt -Y f5ethtrailer.tls.keylog -Tfields -e f5ethtrailer.tls.keylog > $pms_file echo -e "\tSession keys extracted!" # Create a decrypted tcpdump capture from the encrypted capture + session keys file echo -e "\nCreating decrypted tcpdump capture..." editcap --inject-secrets tls,$pms_file $tcpdump_file_encrypt $tcpdump_file_decrypt echo -e "\tDecrypted tcpdump capture created!" echo -e "\nCleanup..." rm -f $payload $pms_file echo -e "\nComplete!" } prompt_bigip_address prompt_credentials get_token main delete_token