Determining Windows application ports

Situation: we wanted to determine all network ports used by various Windows applications. Our solution consisted of capturing all network traffic with WinDump while executing the applications, and analyzing the traffic with a UNIX shell script. Cygwin was installed on the Windows machines to provide us with the UNIX shell and utilities used to analyze the network traffic.

The goal of the solution was to provide a client with a set of firewall rules needed for the Windows applications to function in a firewalled environment. The solution is not perfect: the network captures include all traffic, some of which is not generated by the application. However, after running the application packet captures through the analyzer script, it should become obvious which traffic was generated by the applications.

1. On a Windows machine, install WinPCap, WinDump, and Cygwin.

2. Open up a Command Prompt, and run WinDump -n -w application_name
The -n disables DNS reverse-lookups, and -w writes the output in binary format.

3. Thoroughly test the application.

4. Stop the WinDump capture.

5. Repeat steps 2 through 4 for all applicable Windows applications.

6. Run Cygwin, and analyze one or more application_name binary WinDump capture(s) with the following Bourne shell script.

Before executing the script, change the values of IP_ADDRESS, DB_ADDRESS, WINDUMP, USE_NSLOOKUP, and DNS_DATA. In this example, nslookup is used to determine hostname information instead of searching the $DNS_DATA file.
#!/bin/sh

# The script requires the IP address of the machine that ran
# the packet capture and the WINDUMP capture file in binary
# format as arguments
if [ "$#" -lt 1 ] ; then
echo "Usage: $0 WINDUMP_capture_file(s)"
exit 1
fi

# Declare variables

# IP address of machine that ran packet capture
IP_ADDRESS=192.168.1.100

# Subnet directed broadcast address of machine that ran packet capture
# Ex. 192.168.1.51/25 (255.255.255.128 subnet mask) = 192.168.1.127
# Ex. 192.168.1.152/25 (255.255.255.128 subnet mask) = 192.168.1.255
DB_ADDRESS=192.168.1.127

# Path to WinDump executable
WINDUMP=/cygdrive/c/windump/WinDump.exe

# If $USE_NSLOOKUP is "true", use "nslookup" for DNS resolution
# Otherwise, set $USE_NSLOOKUP to "false" to search for hostnames in $DNS_DATA
USE_NSLOOKUP=true
DNS_DATA=/cygdrive/c/windump/DNS_data

# Berkeley Packet Format (BPF) filters

# Outbound traffic

# Interested in traffic from the host's IP address (src host $1)
# Interested in IP traffic (ip)
# Not interested in broadcast traffic (dst host 255.255.255.255)
# Not interested in directed broadcast traffic (dst host $DB_ADDRESS)
# Not interested in multicast traffic (dst net 224.0.0.0/24)

# Inbound traffic

# Interested in TCP SYN packets destined to $IP_ADDRESS

for FILE in $@
do
# Outbound traffic
$WINDUMP -n -r $FILE "\
src host $IP_ADDRESS and \
ip and \
not (dst host 255.255.255.255) and \
not (dst host $DB_ADDRESS) and \
not (dst net 224.0.0/24)" 2>/dev/null \
| awk '{if ($6 ~ /UDP,/) PROTO = "udp"; else PROTO = "tcp"} {print $5"\t"PROTO"\t"FILE}' FILE=$FILE | sort | uniq -c | sort -n >> $$_outbound.tmp

# Inbound traffic
$WINDUMP -n -r $FILE 2>/dev/null \
| awk '$6 == "S" && $8 == "win" && $5 ~ IP_ADDRESS {print $3"\ttcp\t"FILE"\t"$5}' FILE=$FILE IP_ADDRESS=$IP_ADDRESS | sort | uniq -c | sort -n >> $$_inbound.tmp
done

# Generate report sorted by occurrence(s) of network traffic
printf "Outbound traffic\n\n"
printf "%-4s %-10s %-15s %-22s %s\n" "Mtch" "App" "Destination" "Prot/Port/Srv" "Hostname"
printf "%-4s %-10s %-15s %-22s %s\n" "----" "----------" "---------------" "----------------------" "--------"

while read LINE
do
set $LINE
COUNT=$1
DST_IP=`echo $2 | cut -d. -f1-4`
DST_PORT=`echo $2 | cut -d. -f5 | tr -d ':'`
PROTO=$3
FILE=$4
SERVICE=`grep -w "${DST_PORT}/${PROTO}" /etc/services | awk '{print $1}'`
# If $USE_NSLOOKUP is true, use "nslookup" for DNS resolution
# Otherwise, search for hostnames in $DNS_DATA
if [ "$USE_NSLOOKUP" = true ] ; then
HOSTNAME=`nslookup $DST_IP 2>/dev/null | awk 'NR == 4 && $1 ~ /^Address:/ {print $2}'`
else
HOSTNAME=`grep $DST_IP $DNS_DATA | awk '{print $1}' | head -n1`
fi
if [ -n "$SERVICE" ] ; then
printf "%-4s %-10s %-15s %-22s %s\n" $COUNT $FILE $DST_IP "${PROTO}/${DST_PORT} (${SERVICE})" $HOSTNAME
else
printf "%-4s %-10s %-15s %-22s %s\n" $COUNT $FILE $DST_IP "${PROTO}/${DST_PORT}" $HOSTNAME
fi
done < $$_outbound.tmp

printf "\nInbound traffic\n\n"
printf "%-4s %-10s %-15s %-22s %s\n" "Sess" "App" "Source" "Prot/Port/Srv" "Hostname"
printf "%-4s %-10s %-15s %-22s %s\n" "----" "----------" "---------------" "----------------------" "--------"

while read LINE
do
set $LINE
COUNT=$1
SRC_IP=`echo $2 | cut -d. -f1-4`
DST_PORT=`echo $5 | cut -d. -f5 | tr -d ':'`
PROTO=$3
FILE=$4
SERVICE=`grep -w "${DST_PORT}/${PROTO}" /etc/services | awk '{print $1}'`
# If $USE_NSLOOKUP is true, use "nslookup" for DNS resolution
# Otherwise, search for hostnames in $DNS_DATA
if [ "$USE_NSLOOKUP" = true ] ; then
HOSTNAME=`nslookup $DST_IP 2>/dev/null | awk 'NR == 4 && $1 ~ /^Address:/ {print $2}'`
else
HOSTNAME=`grep $DST_IP $DNS_DATA | awk '{print $1}' | head -n1`
fi
if [ -n "$SERVICE" ] ; then
printf "%-4s %-10s %-15s %-22s %s\n" $COUNT $FILE $SRC_IP "${PROTO}/${DST_PORT} (${SERVICE})" $HOSTNAME
else
printf "%-4s %-10s %-15s %-22s %s\n" $COUNT $FILE $SRC_IP "${PROTO}/${DST_PORT}" $HOSTNAME
fi
done < $$_inbound.tmp

# Remote temporary file
rm $$_outbound.tmp
rm $$_inbound.tmp
Example:

./analyze_traffic app1 app2
Outbound traffic

Mtch App        Destination     Prot/Port/Srv          Hostname
---- ---------- --------------- ---------------------- --------
1    app1       192.168.65.144  udp/137 (netbios-ns)
1    app1       192.168.73.66   tcp/53 (domain)        host1.example.com
1    app1       192.168.20.247  tcp/443 (https)
2    app1       192.168.65.222  tcp/5432               host2.example.com
3    app1       192.168.248.15  tcp/8082               host3.example.com
4    app1       192.168.65.222  tcp/1084               host2.example.com
9    app1       192.168.9.17    tcp/1601               host4.example.com
9    app1       192.168.9.45    tcp/3593
96   app1       192.168.74.67   tcp/8080               host5.example.com
988  app1       192.168.65.222  tcp/4194               host2.example.com
1    app2       192.168.9.89    tcp/4621
2    app2       192.168.74.67   tcp/8080               host5.example.com
8    app2       192.168.9.39    tcp/1790

Inbound traffic

Sess App        Source          Prot/Port/Srv          Hostname
---- ---------- --------------- ---------------------- --------
1    app1       192.168.9.17    tcp/445 (microsoft-ds) host4.example.com
1    app1       192.168.9.45    tcp/445 (microsoft-ds)
1    app2       192.168.9.39    tcp/445 (microsoft-ds)

Explanation:

"Outbound traffic" is traffic initiated from IP_ADDRESS to "Destination," and associated response traffic from "Destination" to IP_ADDRESS. Outbound traffic is sorted by application and by the number of matches for the type of traffic. Both TCP and UDP traffic is listed in the "Outbound traffic" section.

"Inbound traffic" is traffic initiated from "Source" to IP_ADDRESS.  Inbound traffic is sorted by application and by the number of sockets created by the source to the destination; this does not include the actual number of packets in the "inbound traffic" exchange. Only TCP traffic is listed in the "Inbound traffic" section.

Back to brandonhutchinson.com.
Last modified: 10/11/2004