{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "# Zeek Network Data to Scikit-Learn\n", "In this notebook we're going to be using the zat Python module and explore the functionality that enables us to easily go from Zeek data to Pandas to Scikit-Learn. Once we get our data in a form that is usable by Scikit-Learn we have a wide array of data analysis and machine learning algorithms at our disposal.\n", "\n", "
\n", "\n", "### Software\n", "- zat: https://github.com/SuperCowPowers/zat\n", "- Pandas: https://github.com/pandas-dev/pandas\n", "- Scikit-Learn: http://scikit-learn.org/stable/index.html\n", "\n", "### Techniques\n", "
\n", "\n", "- One Hot Encoding: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.get_dummies.html\n", "- t-SNE: https://distill.pub/2016/misread-tsne/\n", "- Kmeans: http://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html\n", "\n", "### Thanks\n", "- The DataFrameToMatrix() class is inspired by a great talk from Tom Augspurger at PyData Chicago 2016: https://youtu.be/KLPtEBokqQ0\n", "\n", "### Code Availability\n", "All this code in this notebook is from the examples/bro_to_scikit.py file in the zat repository (https://github.com/SuperCowPowers/zat). If you have any questions/problems please don't hesitate to open up an Issue in GitHub or even better submit a PR. :) \n", "\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "zat: 0.3.6\n", "Pandas: 0.25.1\n", "Numpy: 1.16.4\n", "Scikit Learn Version: 0.21.2\n" ] } ], "source": [ "# Third Party Imports\n", "import pandas as pd\n", "import sklearn\n", "from sklearn.manifold import TSNE\n", "from sklearn.decomposition import PCA\n", "from sklearn.discriminant_analysis import LinearDiscriminantAnalysis\n", "from sklearn.cluster import KMeans\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "# Local imports\n", "import zat\n", "from zat.log_to_dataframe import LogToDataFrame\n", "from zat.dataframe_to_matrix import DataFrameToMatrix\n", "\n", "# Good to print out versions of stuff\n", "print('zat: {:s}'.format(zat.__version__))\n", "print('Pandas: {:s}'.format(pd.__version__))\n", "print('Numpy: {:s}'.format(np.__version__))\n", "print('Scikit Learn Version:', sklearn.__version__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Quickly go from Zeek log to Pandas DataFrame" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
uidid.orig_hid.orig_pid.resp_hid.resp_pprototrans_idqueryqclassqclass_name...rcodercode_nameAATCRDRAZanswersTTLsrejected
ts
2013-09-15 23:44:27.631940126CZGShC2znK1sV7jdI7192.168.33.1010304.2.2.353udp44949guyspy.com1C_INTERNET...0NOERRORFFTT054.245.228.19136.000000F
2013-09-15 23:44:27.696868896CZGShC2znK1sV7jdI7192.168.33.1010304.2.2.353udp50071www.guyspy.com1C_INTERNET...0NOERRORFFTT0guyspy.com,54.245.228.1911000.000000,36.000000F
2013-09-15 23:44:28.060639143CZGShC2znK1sV7jdI7192.168.33.1010304.2.2.353udp39062devrubn8mli40.cloudfront.net1C_INTERNET...0NOERRORFFTT054.230.86.87,54.230.86.18,54.230.87.160,54.230...60.000000,60.000000,60.000000,60.000000,60.000...F
2013-09-15 23:44:28.141794920CZGShC2znK1sV7jdI7192.168.33.1010304.2.2.353udp7312d31qbv1cthcecs.cloudfront.net1C_INTERNET...0NOERRORFFTT054.230.86.87,54.230.86.18,54.230.84.20,54.230....60.000000,60.000000,60.000000,60.000000,60.000...F
2013-09-15 23:44:28.422703981CZGShC2znK1sV7jdI7192.168.33.1010304.2.2.353udp41872crl.entrust.net1C_INTERNET...0NOERRORFFTT0cdn.entrust.net.c.footprint.net,192.221.123.25...4993.000000,129.000000,129.000000,129.000000F
\n", "

5 rows × 22 columns

\n", "
" ], "text/plain": [ " uid id.orig_h id.orig_p \\\n", "ts \n", "2013-09-15 23:44:27.631940126 CZGShC2znK1sV7jdI7 192.168.33.10 1030 \n", "2013-09-15 23:44:27.696868896 CZGShC2znK1sV7jdI7 192.168.33.10 1030 \n", "2013-09-15 23:44:28.060639143 CZGShC2znK1sV7jdI7 192.168.33.10 1030 \n", "2013-09-15 23:44:28.141794920 CZGShC2znK1sV7jdI7 192.168.33.10 1030 \n", "2013-09-15 23:44:28.422703981 CZGShC2znK1sV7jdI7 192.168.33.10 1030 \n", "\n", " id.resp_h id.resp_p proto trans_id \\\n", "ts \n", "2013-09-15 23:44:27.631940126 4.2.2.3 53 udp 44949 \n", "2013-09-15 23:44:27.696868896 4.2.2.3 53 udp 50071 \n", "2013-09-15 23:44:28.060639143 4.2.2.3 53 udp 39062 \n", "2013-09-15 23:44:28.141794920 4.2.2.3 53 udp 7312 \n", "2013-09-15 23:44:28.422703981 4.2.2.3 53 udp 41872 \n", "\n", " query qclass \\\n", "ts \n", "2013-09-15 23:44:27.631940126 guyspy.com 1 \n", "2013-09-15 23:44:27.696868896 www.guyspy.com 1 \n", "2013-09-15 23:44:28.060639143 devrubn8mli40.cloudfront.net 1 \n", "2013-09-15 23:44:28.141794920 d31qbv1cthcecs.cloudfront.net 1 \n", "2013-09-15 23:44:28.422703981 crl.entrust.net 1 \n", "\n", " qclass_name ... rcode rcode_name AA TC RD RA \\\n", "ts ... \n", "2013-09-15 23:44:27.631940126 C_INTERNET ... 0 NOERROR F F T T \n", "2013-09-15 23:44:27.696868896 C_INTERNET ... 0 NOERROR F F T T \n", "2013-09-15 23:44:28.060639143 C_INTERNET ... 0 NOERROR F F T T \n", "2013-09-15 23:44:28.141794920 C_INTERNET ... 0 NOERROR F F T T \n", "2013-09-15 23:44:28.422703981 C_INTERNET ... 0 NOERROR F F T T \n", "\n", " Z \\\n", "ts \n", "2013-09-15 23:44:27.631940126 0 \n", "2013-09-15 23:44:27.696868896 0 \n", "2013-09-15 23:44:28.060639143 0 \n", "2013-09-15 23:44:28.141794920 0 \n", "2013-09-15 23:44:28.422703981 0 \n", "\n", " answers \\\n", "ts \n", "2013-09-15 23:44:27.631940126 54.245.228.191 \n", "2013-09-15 23:44:27.696868896 guyspy.com,54.245.228.191 \n", "2013-09-15 23:44:28.060639143 54.230.86.87,54.230.86.18,54.230.87.160,54.230... \n", "2013-09-15 23:44:28.141794920 54.230.86.87,54.230.86.18,54.230.84.20,54.230.... \n", "2013-09-15 23:44:28.422703981 cdn.entrust.net.c.footprint.net,192.221.123.25... \n", "\n", " TTLs \\\n", "ts \n", "2013-09-15 23:44:27.631940126 36.000000 \n", "2013-09-15 23:44:27.696868896 1000.000000,36.000000 \n", "2013-09-15 23:44:28.060639143 60.000000,60.000000,60.000000,60.000000,60.000... \n", "2013-09-15 23:44:28.141794920 60.000000,60.000000,60.000000,60.000000,60.000... \n", "2013-09-15 23:44:28.422703981 4993.000000,129.000000,129.000000,129.000000 \n", "\n", " rejected \n", "ts \n", "2013-09-15 23:44:27.631940126 F \n", "2013-09-15 23:44:27.696868896 F \n", "2013-09-15 23:44:28.060639143 F \n", "2013-09-15 23:44:28.141794920 F \n", "2013-09-15 23:44:28.422703981 F \n", "\n", "[5 rows x 22 columns]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a Pandas dataframe from a Zeek log\n", "log_to_df = LogToDataFrame()\n", "bro_df = log_to_df.create_dataframe('../data/dns.log')\n", "\n", "# Print out the head of the dataframe\n", "bro_df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "## So... what just happened?\n", "**Yep it was quick... the two little lines of code above turned a Zeek log (any log) into a Pandas DataFrame. The zat package also supports streaming data from dynamic/active logs, handles log rotations and in general tries to make your life a bit easier when doing data analysis and machine learning on Zeek data.**\n", "\n", "**Now that we have the data in a dataframe there are a million wonderful things we could do for data munging, processing and analysis but that will have to wait for another time/notebook.**" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# Using Pandas we can easily and efficiently compute additional data metrics\n", "# Here we use the vectorized operations of Pandas/Numpy to compute query length\n", "bro_df['query_length'] = bro_df['query'].str.len()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## DNS records are a mix of numeric and categorical data\n", "When we look at the dns records some of the data is numerical and some of it is categorical so we'll need a way of handling both data types in a generalized way. zat has a DataFrameToMatrix class that handles a lot of the details and mechanics of combining numerical and categorical data, we'll use below." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
AARARDTCZrejectedprotoqclass_nameqtype_namercode_namequery_length
ts
2013-09-15 23:44:27.631940126FTTF0FudpC_INTERNETANOERROR10.0
2013-09-15 23:44:27.696868896FTTF0FudpC_INTERNETANOERROR14.0
2013-09-15 23:44:28.060639143FTTF0FudpC_INTERNETANOERROR28.0
2013-09-15 23:44:28.141794920FTTF0FudpC_INTERNETANOERROR29.0
2013-09-15 23:44:28.422703981FTTF0FudpC_INTERNETANOERROR15.0
\n", "
" ], "text/plain": [ " AA RA RD TC Z rejected proto qclass_name \\\n", "ts \n", "2013-09-15 23:44:27.631940126 F T T F 0 F udp C_INTERNET \n", "2013-09-15 23:44:27.696868896 F T T F 0 F udp C_INTERNET \n", "2013-09-15 23:44:28.060639143 F T T F 0 F udp C_INTERNET \n", "2013-09-15 23:44:28.141794920 F T T F 0 F udp C_INTERNET \n", "2013-09-15 23:44:28.422703981 F T T F 0 F udp C_INTERNET \n", "\n", " qtype_name rcode_name query_length \n", "ts \n", "2013-09-15 23:44:27.631940126 A NOERROR 10.0 \n", "2013-09-15 23:44:27.696868896 A NOERROR 14.0 \n", "2013-09-15 23:44:28.060639143 A NOERROR 28.0 \n", "2013-09-15 23:44:28.141794920 A NOERROR 29.0 \n", "2013-09-15 23:44:28.422703981 A NOERROR 15.0 " ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# These are the features we want (note some of these are categorical :)\n", "features = ['AA', 'RA', 'RD', 'TC', 'Z', 'rejected', 'proto', 'qclass_name', \n", " 'qtype_name', 'rcode_name', 'query_length']\n", "feature_df = bro_df[features]\n", "feature_df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Transformers\n", "**We'll now use a zat scikit-learn tranformer class to convert the Pandas DataFrame to a numpy ndarray (matrix). Yes it's awesome... I'm not sure it's Optimus Prime awesome.. but it's still pretty nice.**" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Normalizing column Z...\n", "Normalizing column query_length...\n" ] } ], "source": [ "# Use the zat DataframeToMatrix class (handles categorical data)\n", "# You can see below it uses a heuristic to detect category data. When doing\n", "# this for real we should explicitly convert before sending to the transformer.\n", "to_matrix = dataframe_to_matrix.DataFrameToMatrix()\n", "bro_matrix = to_matrix.fit_transform(feature_df)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "\n", "## Scikit-Learn\n", "**Now that we have a numpy ndarray(matrix) we're ready to rock with scikit-learn...**" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
queryprotoxycluster
ts
2013-09-15 23:44:27.631940126guyspy.comudp39.936161-18.8965490
2013-09-15 23:44:27.696868896www.guyspy.comudp24.9455573.4082480
2013-09-15 23:44:28.060639143devrubn8mli40.cloudfront.netudp-28.3039422.0648170
2013-09-15 23:44:28.141794920d31qbv1cthcecs.cloudfront.netudp-22.6339846.7048060
2013-09-15 23:44:28.422703981crl.entrust.netudp18.326878-2.0184990
\n", "
" ], "text/plain": [ " query proto x y cluster\n", "ts \n", "2013-09-15 23:44:27.631940126 guyspy.com udp 39.936161 -18.896549 0\n", "2013-09-15 23:44:27.696868896 www.guyspy.com udp 24.945557 3.408248 0\n", "2013-09-15 23:44:28.060639143 devrubn8mli40.cloudfront.net udp -28.303942 2.064817 0\n", "2013-09-15 23:44:28.141794920 d31qbv1cthcecs.cloudfront.net udp -22.633984 6.704806 0\n", "2013-09-15 23:44:28.422703981 crl.entrust.net udp 18.326878 -2.018499 0" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Now we're ready for scikit-learn!\n", "# Just some simple stuff for this example, KMeans and TSNE projection\n", "kmeans = KMeans(n_clusters=5).fit_predict(bro_matrix)\n", "projection = TSNE().fit_transform(bro_matrix)\n", "\n", "# Now we can put our ML results back onto our dataframe!\n", "bro_df['x'] = projection[:, 0] # Projection X Column\n", "bro_df['y'] = projection[:, 1] # Projection Y Column\n", "bro_df['cluster'] = kmeans\n", "bro_df[['query', 'proto', 'x', 'y', 'cluster']].head() # Showing the scikit-learn results in our dataframe" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [], "source": [ "# Plotting defaults\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "plt.rcParams['font.size'] = 18.0\n", "plt.rcParams['figure.figsize'] = 15.0, 7.0" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "image/png": "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Mcdo7dq1B73++uuva8OGDbrgggsOrCBK0mWXXabPfvazuuWWW3TppZce9Gd6+eWX9b3vfU/r1q3LaO6vvfaa/uqv/irha3V1dfrzn/+c0fcHfKmra3o73swK1l6+uLcdr73drW6tWlW4+SI5UQtYgiysVYpn4rMG8AUCS7/Zvt3dZUtHVZU7wefB22+/rSOPPDIvP8tTWVmpZ599Vs8884yOP/74lMffd9992rt3rz796U9r586dB7129tln69vf/ra2bt160EpnTU2NLrroooTfL5W2KSMjIyqdpf9bLBbTSLJFFoCgCECuODIQlYAF/sdnDeAb5Fj6zeioVJxmvF9U5MbnwaJFizQ0NJSXn+W59dZbtWvXLp1wwgk69thjtW7dOj344IPav39/UuOfe+45SdLpp5+u2trag74++MEPSpLeeOONg8Yce+yxKioqynju5eXl2rt3b8LXxsbGVJ5sPi0QBAHJFQcQcHzWAL7CiqXflJW5fIBZVrfmNDnpxufB8ccfr0ceeUQvvfRSRtthZxbW8STqf/nRj35UPT09euihh9TR0aGtW7fq3nvv1Zo1a7R161aVlJTM+bO8XMgf/OAHWrp0acJjZv5ZshXwHXXUUerr60v4Wl9fn+rq6rLycwBfCEiuOCBrp7f0bt8+vaW3sdH13py5rRL+wmcN4CsEln7T2OiSzBcsSH3s4KDLb8mD8847T4888ojuuece3XjjjWl/n5qaGg0MDBzy/EsvvTTr8WvXrtXatWtlrdXVV1+tm266SQ8++KDOP//8OX/Wu971LknSkiVLdPrpp6c953ScfPLJ+tGPfqRXX331oAI+r776ql577TWdc845eZ0PkFMByRVHxFHsJfj4rAF8ha2wftPc7E5qqW7PsNaNa27OzbxmWLdunRobG3XzzTfrwQcfTHjMU089pTvvvHPO77NixQo9//zzB63m7d27V3fcccdBx01OTmpwcPCg54wxWjlVIj0+OF24cGHCYPXjH/+4SktLdd1112k0wZbh3bt3z7pdNZFU2o383d/9nSS3nTee9/9///d/n/TPBXwvILniiLCuLlfEZdcuFzzW1bkbul6hl7o697xX7KWrq9AzRiJ81gC+woql39TXT5/MamqSH+edHFPdDpKm8vJy/eIXv9CZZ56pj33sYzrjjDP0wQ9+UIsXL1Z/f7+2bdumX/7yl/rSl7405/e54oor9JOf/ESnn366LrnkEu3bt09btmw5ZAvq0NCQli5dqnPOOUcrV67UEUccoZdffll33XWXqqurdfbZZx849pRTTtHWrVv1jW98Q8uWLZMxRhdccIGOPvpo3XXXXVq3bp2OO+44tba2qr6+Xv39/frjH/+oBx54QH/605/UkOTdy1TajZx55pk666yzdMstt2j37t163/vep9/97ne69957tXbtWq3O00ozkBejo27lJx15zBVHRFHsJTz4rAF8hcDSb4xx227a292HZTI5fiMj0vCw6xmWx1yQ5cuX6/e//72++93v6v7771d7e7uGh4dVU1OjpqYmbd68WZ/4xCfm/B7vf//7tWnTJt1444364he/qLq6Ol166aVqamrSaaedduC48vJyfe5zn9Ovf/1rbd26VcPDwwcCzWuuuUZHHXXUgWPvvPNOXX755Wpvbz9QYOiCCy6QJF100UVasWKFbr75Zn33u9/V4OCglixZosbGRt1www16xzvekYO/KednP/uZvva1r+mHP/yhtmzZorq6On31q1/V1VdfnbOfCRREQHLFEUGZFntpayPn0k/4rAF8xSSz2gKpqanJdnZ2znnMc889p+OOOy47PzC+J1N1deITmdeTaXjY9WSa2haKcMrq+wvIpc2bXY5aOkWp+vpcrviFF2Z/XkBPjwsOUy3K4xX5aWsjJ89P+KwB8s4Y85S1tinRa6xY+tWqVdK11x5aWKCoyN1lGxx0d+nq691KJdtzAPhFc7MrfGJt6hfvecwVRwRR7CVc+Kw5PCofI48ILP1s+XJ3d9T7QNixY/oDYfVqqaVFWraMDwQA/hKQXHFEEMVewoXPmrlR+Rh5RmDpd8a4u6PcIQUQFAHKFUfEUOwlXPismV18StXMVUmv+rGXUtXe7lKqVq0q3HwRCrQbAQBk3/Ll7kKlv18aGJi9hZK17vWdO93x3DVHLpWVSRMT6Y2l2Is/8VlzqPjKxzU1swfQXuXj2lpX+bi7O7/zROgQWAIAcsPLFa+udlux+vqkPXuksTH32Nfnnq+udq0cKECGXGtsdDUK0jE4KK1Ykd35IDv4rJmWaeVjinoiA2yFBQDkDrni8BOKvYQXnzVOb6/7SjV/1AvKe3tJv0LaCCwBALlFrvjhUbkxPyj2Em581lD5GAVFYAkAQCFRuTF/KPaC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m4JyPjj++OP1yCOP6KWXXspoO+zMwjqeRP0vP/rRj6qnp0cPPfSQOjo6tHXrVt17771as2aNtm7dqpKSkjl/lre6+IMf/EBLly5NeMzMP0t5shWUACAdVG5EtjU2umbXCxakPnZw0BV1AYA0BDKwDLOgnA/OO+88PfLII7rnnnt04403pv19ampqNDBwaGvSl156adbj165dq7Vr18paq6uvvlo33XSTHnzwQZ1//vlz/qx3vetdkqQlS5bMuWoJAHnlVW7s7XWJ8jt2uO0nZWXuQ72lRVq2jO2vSA6FoQAUSCBzLMOsudl9rqeaupfv88G6devU2Niom2++WQ8++GDCY5566indeeedc36fFStW6Pnnn1df33THl7179+qOO+446LjJyUkNzijNb4zRypUrJemg4HThwoUJg9WPf/zjKi0t1XXXXafRBHuGd+/erb17DyksPKtU2o0AwJy8yo0XXii1t0u33OIeL7zQrVYSVCJZ8YWhUkFhKAAZYsXSZ4JSKLC8vFy/+MUvdOaZZ+pjH/uYzjjjDH3wgx/U4sWL1d/fr23btumXv/ylvvSlL835fa644gr95Cc/0emnn65LLrlE+/bt05YtWw7Zgjo0NKSlS5fqnHPO0cqVK3XEEUfo5Zdf1l133aXq6mqdffbZB4495ZRTtHXrVn3jG9/QsmXLZIzRBRdcoKOPPlp33XWX1q1bp+OOO06tra2qr69Xf3+//vjHP+qBBx7Qn/70JzUkWVY31XYjt99++4HgeHx8XL29vfra174mSTrppJMO+jMAAJAWrzBUe7sr2pBMSodXGGrDBm5iAEiboaplcpqammxn59ztLp977jkdd9xxGf+s7m53PqitTf58sHOntHFj/tNvRkZG9N3vflf333+/nn32WQ0PD6umpkZNTU264IIL9IlPfOJA8ZuWlhb19PSop6fnoO+xefNm3XjjjXr55ZdVV1enSy+9VE1NTTrttNP0L//yL/rUpz6lffv26brrrtOvf/1rvfjiixoeHtbSpUt16qmn6pprrjmwzVWSXnjhBV1++eV6/PHHDxQYin+f//a3v9XNN9+s3/72txocHNSSJUvU2Nios846S5dffrliU9WTGhoa1NDQoIcffjjhn72hoSGlwNI7PpELL7xQmzZtmnN8tt5fAIAI6OpKvTDU1C4gAJiNMeYpa21TwtcILJOTz8BS4nyAQxFYAgBS0t2dXGGo1lYKQwFIylyBJVthfYpCgQCAyLB2unjR9u3TxYsaG13xAPJM00NhKAB5RGDpY5wPAAChl2hVLRZzd08fe8xVOGVVLX1eYagk6wcAQLoILH2O8wEAILTi8z5mrkqWlrreW17eR3u7y/tYtapw8wUAzIrAEgAA5F93twsqD1epzhhXJj0Wk26/vTCV6hBMbLEG8orAEgAA5Je1bvtrRUVy5c8ld9zChW5cWxsBAebGFmsg7+YVegIAACBienvdV3V1auOqq6fHArPp6nJbp70m33V1blu1t726rm66aXh7uzseQMYILAEAQH51dLhVpFRXHY1x4zo6cjMvBF/8FuuamtnfY94W69pat8W6uzu/8wRCiMASAADk1/btbmtiOqqqXJl0YKZMt1jT2x3ICIElAADIr9FRqTjNMg9FRW48MBNbrIGCIrAEAAD5VVYmTUykN3Zy0o0HZmKLNVBQBJYAACC/GhulwcH0xg4OSitWZHc+CAe2WAMFRWAJAADyq7nZtX1INafNWjeuuTk380KwscUaKCj6WPqctVa9u3vV0dOh7W9t1+jEqMqKy9S4uFHNDc2qr6yXCUgvr5aWFvX09Kinp6fQUwEAFFJ9/XS7h5qa5Md57SPq63M3NwRXWZm78VBamvpYtlgDGWPF0se6B7rV9nCb2h5u02OvPKbxyXHFimIanxzXY688duC17oHClcgeGRnRrbfeqjVr1qimpkbz58/XkUceqY985CPatGmTJtLNoclAW1ubHnjggbz/3Ll0dXXpC1/4glatWqXq6mpVV1fr5JNP1p133qnx8fFCTw8A8ssY15h+aEgaGUluzMiINDzsxgXkhiryjC3WQEERWPpU1+tdan+0XbvGdqm+sl51i+q0oGSBSotLtaBkgeoW1am+sl67xnap/dF2db2e/+a+3d3dWrlypa688krFYjFdc801uvvuu3XVVVdpfHxcF110kTZu3Jj3eV1//fW+Cyxvuukmbdq0SatWrdKNN96oG264QYsXL9bll1+us846S5YS5wCiZvlyaf16qb9fGhiYfVuste71nTvd8cuX53eeCA62WAMFxVZYH+oe6NZtT9ym2vJalc+fvQ+TMUY1ZTWKFcd0+xO3a+OajVpek58T7ujoqM466yy99NJLuv/++3Xuuece9PqXv/xlPfnkk3ryySfzMp98GRoaUkVFRcrj1q9fr02bNikWix147oorrtDatWv1ox/9SP/+7/+us846K5tTBQD/W7VKuvZa10Owt9dV5qyqcvluk5P/f3v3Hh1lle55/LtzrSSEJAWIAVdSDYE0pwWFE20cyRAF8SgddTVi03aCg6KHi6BHGxQ408b2hPFCO6xGQRAVTI9ttzBC63jGMSpB5hyHazMiEAxQxTRNK5ckJJCQ254/KolJqIRcqyrw+6xVq8y+vO9T8aVST+397u0dRaqu9k59nT9fSaW0TVOsRQJKI5ZBxlpL3t48YiNi20wqm4oOj6ZPRB/y9ub5beRr7dq1FBYW8uSTT16UVDa44YYbmDNnTpvHcblcZGRkXFS+ZcsWjDGsW7eusayyspKcnBxSU1OJjo4mPj6ekSNHsmDBAgDcbnfj/abr16/HGNP4aCo/P59JkyYRHx+Pw+Fg1KhRvPbaa63GtmfPHm6//Xbi4uIYNWpUY/3hw4c5ePBgm6+vwc0339wsqWzws5/9DIB9+/a16zgiIpedlBTIyfE+xo2DiAioqvI+jxsHzz7rrVNSKZeiKdYiAaURyyDjKfXgKfWQHNexb80SHAmNfV3xrp4JrokNGzYA8Mgjj/T4uRrMnTuXN998k+nTp/PEE09QU1PDN998w2effQbAgAEDyMvLIzs7m/T0dJ+xrVmzhlmzZjF27FiWLFlCTEwMn3zyCbNnz+bw4cO89NJLzdofO3aMW2+9lalTpzJlyhTKy8sb6yZMmIDH4+lSMv+Xv/wFgIEDB3b6GCIivZ4x4HJ5HyJd0TDFesUKiI2FhATfCaO13pHK8nJNsRbpJkosg0yBu4DwkPAOr/RqjCE8JJwCdwGu6109E1wT+/bto2/fvgwZMqTHz9Xg/fff54477mD9+vU+62NiYsjKyiI7O5shQ4aQlZXVrP7EiRPMnz+fadOm8c477zSWz5kzh8cee4yXX36Z2bNnN3tNR48e5fXXX2fmzJnd/nrKy8t56aWXiIuL4+677+7244uIiFyRNMVaJCA0FTbIFJ4uJN7Ruc194x3xHDrtn819z54926l7DbsiLi6Or7/+utPTRjds2MCFCxd46KGHOHXqVLNHZmYmdXV15OfnN+vjdDqZMWOGz+O53e5Oj1bW1taSlZXF0aNHWbVqFc6O3AsiIiIibdMUaxG/04hlkKmoqcARevG9eO0RGhJKRY1/Nvft27cvZWVlfjlXg+XLl5Odnc3IkSMZMmQIt9xyC5mZmWRmZhIScunvSA4cOADAxIkTW23z7bffNvt56NChhIaGdi3wFurq6njwwQfZvHkzubm5/PznP+/W44uIiAiaYi3iZ0osg0xUWBTVtdVE0vHNfWvraokK88/mvtdeey1bt27lyJEjXZoO29qUX1/7X95999243W4++ugjCgoKyM/P54033iA9PZ38/HwiIiLaPFfD6OLbb79NYmKizzYtX0t0dPsWUGqvuro6Zs6cydtvv80zzzwTkO1YRERERES6mxLLIJPaL5Vtx7YRExHT4b4llSWMSxrXA1FdbMqUKWzdupW1a9eydOnSTh/H6XRy5syZi8qPHDnSavusrCyysrKw1vL000/z4osvsnnzZqZOndrmuYYNGwZA//792xy17CkNSeVbb73FP//zP5OTk+P3GEREpBey1nuvYEEBFBZCRQVERUFqqnfvxeRkrWgqIgGneyyDzHjXeKrrqjt87561luq6asa7/LO578yZM0lNTWXZsmVs3rzZZ5tdu3axcuXKNo8zfPhwDh48yPHjxxvLLly4wKuvvtqsXW1tLSUlJc3KjDGMHj0aoFly2qdPH5/J6n333UdkZCTPPPMMFRUXTxkuLS3lwoULbcbbVEe2G7HW8vDDD/PWW2+xePFinnvuuXafR0RErmBFRd/fK7htm3fRGYfD+7xt2/d1RUWBjVNErngasQwyyXHJJMclU1xZjDOq/Qu6FFcWN/b1h+joaD788EMmT57MPffcw6RJk7jtttvo168fJ0+e5PPPP+fjjz9m4cKFbR7n0Ucf5d1332XixInMmjWLqqoq8vLyLpqCWlZWRmJiInfddRejR4/mqquualz4JiEhgczMzMa2Y8eOJT8/nxdeeIGkpCSMMUybNo1rrrmGVatWMXPmTEaMGEF2djbJycmcPHmSr776ik2bNrF//35c7bwXoyPbjSxYsIA333yT6667jhEjRvC73/2uWf3QoUO56aab2nVeERG5Quze/f22GS1HJSMjISbm+20zcnO922aMGRO4eEXkiqbEMsgYY8i+LpvcL3JxhDmIDr/0PX7nq89TXlXO/B/P7/A2JV2RkpLCnj17WL16NRs3biQ3N5fy8nKcTidpaWmsX7+e+++/v81j3Hzz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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# Now use dataframe group by cluster\n", "cluster_groups = bro_df.groupby('cluster')\n", "\n", "# Plot the Machine Learning results\n", "fig, ax = plt.subplots()\n", "colors = {0:'red', 1:'blue', 2:'green', 3:'orange', 4:'purple', 5:'black'}\n", "for key, group in cluster_groups:\n", " group.plot(ax=ax, kind='scatter', x='x', y='y', alpha=0.5, s=250,\n", " label='Cluster: {:d}'.format(key), color=colors[key])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Lets Investigate the 5 clusters of DNS data\n", "**We cramed a bunch of features into the clustering algorithm. The features were both numerical and categorical. So did the clustering 'do the right thing'? Well first some caveats and disclaimers:** \n", "- We're obviously working with a small amount of Zeek DNS data\n", "- This is an example to show how the tranformations work (from Zeek to Pandas to Scikit)\n", "- The DNS data is real data but for this example and others we obviously pulled in 'weird' stuff on purpose\n", "- We knew that the K in KMeans should be 5 :)\n", "\n", "**Okay will all those caveats lets look at how the clustering did on both numeric and categorical data combined**\n", "### Cluster details\n", "- Cluster 0: (42 observations) Looks like 'normal' DNS requests\n", "- Cluster 1: (11 observations) All the queries are '-' (Zeek for NA/not found/etc)\n", "- Cluster 2: ( 6 observations) The protocol is TCP instead of the normal UDP\n", "- Cluster 3: ( 4 observations) All the DNS queries are exceptionally long\n", "- Cluster 4: ( 4 observations) The reserved Z bit is set to 1 (required to be 0)\n", "\n", "## Numerical + Categorical = AOK\n", "With our example data we've successfully gone from Zeek logs to Pandas to scikit-learn. The clusters appear to make sense and certainly from an investigative and threat hunting perspective being able to cluster the data and use PCA for dimensionality reduction might come in handy depending on your use case " ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Cluster 0: 42 observations\n", " query Z proto qtype_name cluster\n", "ts \n", "2013-09-15 23:44:27.631940126 guyspy.com 0 udp A 0\n", "2013-09-15 23:44:27.696868896 www.guyspy.com 0 udp A 0\n", "2013-09-15 23:44:28.060639143 devrubn8mli40.cloudfront.net 0 udp A 0\n", "2013-09-15 23:44:28.141794920 d31qbv1cthcecs.cloudfront.net 0 udp A 0\n", "2013-09-15 23:44:28.422703981 crl.entrust.net 0 udp A 0\n", "\n", "Cluster 1: 3 observations\n", " query Z proto qtype_name cluster\n", "ts \n", "2013-09-15 23:44:50.827882051 NaN 0 udp NaN 1\n", "2013-09-15 23:44:50.829301834 NaN 0 udp NaN 1\n", "2013-09-15 23:44:51.026231050 NaN 0 udp NaN 1\n", "\n", "Cluster 2: 3 observations\n", " query Z proto qtype_name cluster\n", "ts \n", "2013-09-15 23:48:05.897021055 j.maxmind.com 0 tcp A 2\n", "2013-09-15 23:48:06.897021055 j.maxmind.com 0 tcp A 2\n", "2013-09-15 23:48:07.897021055 j.maxmind.com 0 tcp A 2\n", "\n", "Cluster 3: 3 observations\n", " query Z proto qtype_name cluster\n", "ts \n", "2013-09-15 23:48:02.497021198 superlongcrazydnsqueryforoutlierdetectionj.max... 0 udp A 3\n", "2013-09-15 23:48:02.597021103 xyzqsuperlongcrazydnsqueryforoutlierdetectionj... 0 udp A 3\n", "2013-09-15 23:48:02.697021008 abcsuperlongcrazydnsqueryforoutlierdetectionj.... 0 udp A 3\n", "\n", "Cluster 4: 3 observations\n", " query Z proto qtype_name cluster\n", "ts \n", "2013-09-15 23:48:02.897021055 j.maxmind.com 1 udp A 4\n", "2013-09-15 23:48:04.897021055 j.maxmind.com 1 udp A 4\n", "2013-09-15 23:48:04.997021198 j.maxmind.com 1 udp A 4\n" ] } ], "source": [ "# Now print out the details for each cluster\n", "pd.set_option('display.width', 1000)\n", "show_fields = ['query', 'Z', 'proto', 'qtype_name', 'cluster']\n", "for key, group in cluster_groups:\n", " print('\\nCluster {:d}: {:d} observations'.format(key, len(group)))\n", " print(group[show_fields].head())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Wrap Up\n", "Well that's it for this notebook, we'll have an upcoming notebook that addresses some of the issues that we overlooked in this simple example. We use Isolation Forest for anomaly detection which works well for high dimensional data. The notebook will cover both training and streaming evalution against the model.\n", "\n", "If you liked this notebook please visit the [zat](https://github.com/SuperCowPowers/zat) project for more notebooks and examples." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 2 }