{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "## Anomaly Exploration (understanding 'Odd')\n", "In this notebook we're going to be using the bat Python module for processing, transformation and anomaly detection on Bro network data. We're going to look at 'normal' http traffic and demonstrate the use of Isolation Forests for anomaly detection. We'll then explore those anomalies with clustering and PCA.\n", "\n", "**Software**\n", "- bat: https://github.com/SuperCowPowers/bat\n", "- Pandas: https://github.com/pandas-dev/pandas\n", "- Scikit-Learn: http://scikit-learn.org/stable/index.html\n", "\n", "**Techniques**\n", "- One Hot Encoding: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.get_dummies.html\n", "- Isolation Forest: http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html\n", "- PCA: http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html\n", "\n", "**Related Notebooks**\n", "- Bro to Scikit-Learn: https://github.com/SuperCowPowers/bat/blob/master/notebooks/Bro_to_Scikit_Learn.ipynb\n", "\n", "**Note:** A previous version of this notebook used a large http log (1 million rows) but we wanted people to be able to run the notebook themselves, so we've changed it to run on the local example http.log." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "bat: 0.2.1\n", "Pandas: 0.19.2\n", "Numpy: 1.12.1\n", "Scikit Learn Version: 0.18.1\n" ] } ], "source": [ "import bat\n", "from bat import log_to_dataframe\n", "from bat import dataframe_to_matrix\n", "print('bat: {:s}'.format(bat.__version__))\n", "import pandas as pd\n", "print('Pandas: {:s}'.format(pd.__version__))\n", "import numpy as np\n", "print('Numpy: {:s}'.format(np.__version__))\n", "import sklearn\n", "from sklearn.ensemble import IsolationForest\n", "from sklearn.decomposition import PCA\n", "from sklearn.cluster import KMeans\n", "print('Scikit Learn Version:', sklearn.__version__)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Successfully monitoring ../data/http.log...\n", "Read in 150 Rows...\n" ] }, { "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", "
filenamehostid.orig_hid.orig_pid.resp_hid.resp_pinfo_codeinfo_msgmethodorig_fuids...response_body_lenstatus_codestatus_msgtagstrans_depthtsuiduriuser_agentusername
0-guyspy.com192.168.33.10103154.245.228.19180--GET-...184301Moved Permanently(empty)12013-09-15 19:44:27.668082CyIaMO7IheOh38Zsi/Mozilla/4.0 (compatible; MSIE 8.0; Windows NT ...-
1-www.guyspy.com192.168.33.10103254.245.228.19180--GET-...100631200OK(empty)12013-09-15 19:44:27.731702CoyZrY2g74UvMMgp4a/Mozilla/4.0 (compatible; MSIE 8.0; Windows NT ...-
2-www.guyspy.com192.168.33.10103254.245.228.19180--GET-...55817404Not Found(empty)22013-09-15 19:44:28.092922CoyZrY2g74UvMMgp4a/wp-content/plugins/slider-pro/css/advanced-sl...Mozilla/4.0 (compatible; MSIE 8.0; Windows NT ...-
3-www.guyspy.com192.168.33.10104054.245.228.19180--GET-...887200OK(empty)12013-09-15 19:44:28.150301CiCKTz4e0fkYYazBS3/wp-content/plugins/contact-form-7/includes/cs...Mozilla/4.0 (compatible; MSIE 8.0; Windows NT ...-
4-www.guyspy.com192.168.33.10104154.245.228.19180--GET-...10068200OK(empty)12013-09-15 19:44:28.150602C1YBkC1uuO9bzndRvh/wp-content/plugins/slider-pro/css/slider/adva...Mozilla/4.0 (compatible; MSIE 8.0; Windows NT ...-
\n", "

5 rows × 27 columns

\n", "
" ], "text/plain": [ " filename host id.orig_h id.orig_p id.resp_h \\\n", "0 - guyspy.com 192.168.33.10 1031 54.245.228.191 \n", "1 - www.guyspy.com 192.168.33.10 1032 54.245.228.191 \n", "2 - www.guyspy.com 192.168.33.10 1032 54.245.228.191 \n", "3 - www.guyspy.com 192.168.33.10 1040 54.245.228.191 \n", "4 - www.guyspy.com 192.168.33.10 1041 54.245.228.191 \n", "\n", " id.resp_p info_code info_msg method orig_fuids ... response_body_len \\\n", "0 80 - - GET - ... 184 \n", "1 80 - - GET - ... 100631 \n", "2 80 - - GET - ... 55817 \n", "3 80 - - GET - ... 887 \n", "4 80 - - GET - ... 10068 \n", "\n", " status_code status_msg tags trans_depth \\\n", "0 301 Moved Permanently (empty) 1 \n", "1 200 OK (empty) 1 \n", "2 404 Not Found (empty) 2 \n", "3 200 OK (empty) 1 \n", "4 200 OK (empty) 1 \n", "\n", " ts uid \\\n", "0 2013-09-15 19:44:27.668082 CyIaMO7IheOh38Zsi \n", "1 2013-09-15 19:44:27.731702 CoyZrY2g74UvMMgp4a \n", "2 2013-09-15 19:44:28.092922 CoyZrY2g74UvMMgp4a \n", "3 2013-09-15 19:44:28.150301 CiCKTz4e0fkYYazBS3 \n", "4 2013-09-15 19:44:28.150602 C1YBkC1uuO9bzndRvh \n", "\n", " uri \\\n", "0 / \n", "1 / \n", "2 /wp-content/plugins/slider-pro/css/advanced-sl... \n", "3 /wp-content/plugins/contact-form-7/includes/cs... \n", "4 /wp-content/plugins/slider-pro/css/slider/adva... \n", "\n", " user_agent username \n", "0 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT ... - \n", "1 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT ... - \n", "2 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT ... - \n", "3 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT ... - \n", "4 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT ... - \n", "\n", "[5 rows x 27 columns]" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a Pandas dataframe from the Bro HTTP log\n", "bro_df = log_to_dataframe.LogToDataFrame('../data/http.log')\n", "print('Read in {:d} Rows...'.format(len(bro_df)))\n", "bro_df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "\n", "## So... what just happened?\n", "*Yep it was quick... the two little lines of code above turned a Bro log (any log) into a Pandas DataFrame. The bat 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 Bro 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": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# We're going to pick some features that might be interesting\n", "# some of the features are numerical and some are categorical\n", "features = ['id.resp_p', 'method', 'resp_mime_types', 'request_body_len']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Our HTTP features are a mix of numeric and categorical data\n", "When we look at the http 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. bat 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": 4, "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", "
id.resp_pmethodresp_mime_typesrequest_body_len
080GETtext/html0
180GETtext/html0
280GETtext/html0
380GETtext/plain0
480GETtext/plain0
\n", "
" ], "text/plain": [ " id.resp_p method resp_mime_types request_body_len\n", "0 80 GET text/html 0\n", "1 80 GET text/html 0\n", "2 80 GET text/html 0\n", "3 80 GET text/plain 0\n", "4 80 GET text/plain 0" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Show the dataframe with mixed feature types\n", "bro_df[features].head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "## Transformers\n", "*We'll now use a 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": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Changing column method to category...\n", "Changing column resp_mime_types to category...\n", "Normalizing column id.resp_p...\n", "Normalizing column request_body_len...\n", "(150, 12)\n" ] }, { "data": { "text/plain": [ "array([[ 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 1., 0.]])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Use the bat 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(bro_df[features], normalize=True)\n", "print(bro_matrix.shape)\n", "bro_matrix[:1]" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "IsolationForest(bootstrap=False, contamination=0.2, max_features=1.0,\n", " max_samples='auto', n_estimators=100, n_jobs=1, random_state=None,\n", " verbose=0)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Train/fit and Predict anomalous instances using the Isolation Forest model\n", "odd_clf = IsolationForest(contamination=0.20) # Marking 20% odd\n", "odd_clf.fit(bro_matrix)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(32, 4)\n" ] }, { "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", "
id.resp_pmethodresp_mime_typesrequest_body_len
10680GETapplication/x-dosexec0
10780GETapplication/x-dosexec0
10980GETapplication/x-dosexec0
11280GETapplication/x-dosexec0
11380GETapplication/x-dosexec0
\n", "
" ], "text/plain": [ " id.resp_p method resp_mime_types request_body_len\n", "106 80 GET application/x-dosexec 0\n", "107 80 GET application/x-dosexec 0\n", "109 80 GET application/x-dosexec 0\n", "112 80 GET application/x-dosexec 0\n", "113 80 GET application/x-dosexec 0" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Now we create a new dataframe using the prediction from our classifier\n", "odd_df = bro_df[features][odd_clf.predict(bro_matrix) == -1]\n", "print(odd_df.shape)\n", "odd_df.head()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Changing column method to category...\n", "Changing column resp_mime_types to category...\n", "Normalizing column id.resp_p...\n", "Normalizing column request_body_len...\n" ] } ], "source": [ "# Now we're going to explore our odd dataframe with help from KMeans and PCA algorithms\n", "odd_matrix = to_matrix.fit_transform(odd_df)" ] }, { "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", "
id.resp_pmethodresp_mime_typesrequest_body_lenxycluster
10680GETapplication/x-dosexec01.112838-0.6157741
10780GETapplication/x-dosexec01.112838-0.6157741
10980GETapplication/x-dosexec01.112838-0.6157741
11280GETapplication/x-dosexec01.112838-0.6157741
11380GETapplication/x-dosexec01.112838-0.6157741
\n", "
" ], "text/plain": [ " id.resp_p method resp_mime_types request_body_len x \\\n", "106 80 GET application/x-dosexec 0 1.112838 \n", "107 80 GET application/x-dosexec 0 1.112838 \n", "109 80 GET application/x-dosexec 0 1.112838 \n", "112 80 GET application/x-dosexec 0 1.112838 \n", "113 80 GET application/x-dosexec 0 1.112838 \n", "\n", " y cluster \n", "106 -0.615774 1 \n", "107 -0.615774 1 \n", "109 -0.615774 1 \n", "112 -0.615774 1 \n", "113 -0.615774 1 " ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Just some simple stuff for this example, KMeans and PCA\n", "kmeans = KMeans(n_clusters=4).fit_predict(odd_matrix) # Change this to 3/5 for fun\n", "pca = PCA(n_components=3).fit_transform(odd_matrix)\n", "\n", "# Now we can put our ML results back onto our dataframe!\n", "odd_df['x'] = pca[:, 0] # PCA X Column\n", "odd_df['y'] = pca[:, 1] # PCA Y Column\n", "odd_df['cluster'] = kmeans\n", "odd_df.head()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Plotting defaults\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "plt.rcParams['font.size'] = 14.0\n", "plt.rcParams['figure.figsize'] = 15.0, 6.0\n", "\n", "# Helper method for scatter/beeswarm plot\n", "def jitter(arr):\n", " stdev = .02*(max(arr)-min(arr))\n", " return arr + np.random.randn(len(arr)) * stdev" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "image/png": "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\nuva6det4/PHHefLJJ1m9ejX5+fksWrSIEALr169Pu42vvPIKv/71r7nkkkuO+TnT5XBWSZIkSf2z\nuyF5DansW73c0gN1+7l36dq1a4kxMmnSpH5dpycbNmxg6NChXH311RQVFVFZWcnkyZOBZFhpQUEB\neXl5jBw5sqvOY489RoyRRx55pGt46oMPPsjw4cNZsmQJs2fPBmD//v0sXryYESNGdNUtLi5mwoQJ\n5OTkHLVtp59+Ops3b6a1tZW77rqLm2++eSAfvUeGSEmSJEn9824tZOX0fcXVEJJ679b2O0TGAejN\n7M3MmTOprKxk7NixzJo1i8suu4xPfvKTFBUV9Vpn5cqVrFu37rAyzc3NvP32213vTz/99G4BEuDa\na6/l2muvTattL774Irt27eI//uM/uOOOOxg7dixz5szpw9P1nSFSkiRJUv+8Xw85xzhcNKcE3n+z\n300488wzCSGwZs2atANYpxDCYSG0paWl689FRUWsWrWK5cuX8/zzz7NgwQLuvPNOfvOb33Daaaf1\neM329namTJnCE088cdi5srKyrj8PHTq0T2091NixYwE455xzaGpqoqamZtBDpHMiJUmSJPVP2x4I\nx9g/FbKT+v1UVlbGrFmzuP/++9m1a9dh57dv395r3YqKChobG7veNzU1dXsPkEqlmD59OgsWLOC1\n115j9+7dLFmyBIDc3Fza2tq6lZ86dSpr166lvLyc8ePHd3sdHCIHUnt7O/v27RuUax/MEClJkiSp\nf7ILILYeW93YltQfAAsXLiTGSHV1NU8++ST19fW88cYbfP/73+fcc8/ttd706dNZuHAhdXV1vPLK\nK8ydO5f8/Pyu80uWLOHee+/llVdeoaGhgccff5ydO3d2zb+sqqri9ddfp76+ni1bttDS0sINN9zA\niBEjuOaaa6itrWXdunUsX76cL3/5y91WaO3J008/zcSJE9m4cWOvZe677z6WLFnCW2+9xVtvvcW/\n/uu/cs899/DZz362j9+1vnM4qyRJkqT++dAE2Lwi2Qeyr1q2Q8VFA9KMcePGsWrVKr75zW9yxx13\nsHHjRoYNG8bkyZN56KGHeq337W9/m8997nNMmzaNESNG8K1vfYs1a9Z0nS8pKeGZZ57hG9/4Bs3N\nzZxxxhk8/PDDXHzxxQDcdNNNLFu2jOrqanbt2sULL7zAtGnTWL58OV/5yle47rrr2LFjB6eddhqX\n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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Jitter so we can see instances that are projected coincident in 2D\n", "odd_df['jx'] = jitter(odd_df['x'])\n", "odd_df['jy'] = jitter(odd_df['y'])\n", "\n", "# Now use dataframe group by cluster\n", "cluster_groups = odd_df.groupby('cluster')\n", "\n", "# Plot the Machine Learning results\n", "colors = {0:'green', 1:'blue', 2:'red', 3:'orange', 4:'purple', 5:'brown'}\n", "fig, ax = plt.subplots()\n", "for key, group in cluster_groups:\n", " group.plot(ax=ax, kind='scatter', x='jx', y='jy', alpha=0.5, s=250,\n", " label='Cluster: {:d}'.format(key), color=colors[key])" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Cluster 0: 7 observations\n", " id.resp_p method resp_mime_types request_body_len\n", "133 80 OPTIONS text/plain 0\n", "134 80 OPTIONS text/plain 0\n", "135 80 OPTIONS text/plain 0\n", "136 80 OPTIONS text/plain 0\n", "137 80 OPTIONS text/plain 0\n", "\n", "Cluster 1: 8 observations\n", " id.resp_p method resp_mime_types request_body_len\n", "106 80 GET application/x-dosexec 0\n", "107 80 GET application/x-dosexec 0\n", "109 80 GET application/x-dosexec 0\n", "112 80 GET application/x-dosexec 0\n", "113 80 GET application/x-dosexec 0\n", "\n", "Cluster 2: 10 observations\n", " id.resp_p method resp_mime_types request_body_len\n", "140 80 POST text/plain 69823\n", "141 80 POST text/plain 69993\n", "142 80 POST text/plain 71993\n", "143 80 POST text/plain 70993\n", "144 80 POST text/plain 72993\n", "\n", "Cluster 3: 7 observations\n", " id.resp_p method resp_mime_types request_body_len\n", "126 8080 GET text/plain 0\n", "127 8080 GET text/plain 0\n", "128 8080 GET text/plain 0\n", "129 8080 GET text/plain 0\n", "130 8080 GET text/plain 0\n" ] } ], "source": [ "# Now print out the details for each cluster\n", "pd.set_option('display.width', 1000)\n", "for key, group in cluster_groups:\n", " print('\\nCluster {:d}: {:d} observations'.format(key, len(group)))\n", " print(group[features].head())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "### Categorical variables that are anomalous\n", "- Cluster 0: http method of OPTIONS (instead of normal GET/POST)\n", "- Cluster 1: application/x-dosexec mime_types\n", "- Cluster 3: response port of 8080 (instead of 80)\n", "\n", "### Numerical variable outliers\n", "- Cluster 2: The request_body_len values are outliers (for this demo dataset)\n", "\n", "*The important thing here is that both categorical and numerical variables were properly handled and the machine learning algorithm 'did the right thing' when marking outliers (for categorical and numerical fields)*" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "For this small demo dataset almost all request_body_len are 0\n", "Cluster 2 represents outliers\n" ] }, { "data": { "image/png": "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\n167dpn4uhfXX35BrxgesskkH77P7om9jw4YNWbFixaJvh22jLrNHTWaTusweNZlN6jJ71GTxrVmz\nZl1rbdWW2m3VEM2t1Z9z944keyT57e1ZV2vtjCRnJMmqVava6tWrt7t/k3bq2e/Lay+e6C4ctCue\nvHrRtzE3N5dZ/FlZ7tRl9qjJbFKX2aMms0ldZo+azI6JDdHsw927kvxqkoe31r4zsvjqJDsl2Wvs\nbSv7ZQAAAGyniQS8qtolybvThbs1rbXx0LYuyU8ycjGW/hYJByW5cBJ9AAAAWO62anxhVa1Ics/+\n5W2S7FtVhyS5PsmVSf53ksOSPCZJq6q9+7Y3tNY2ttZuqKo3J3lNVa1P8p0kr0vyhSQfm9inAQAA\nWMa29gjeqiSf66ddk7ysf/7yJHdPd++7u6U7UnfVyPTEkXWckOTv0x3puyDJhiSPaa39dLs/BQAA\nAFt9H7y5JLWZJptbNr+OHyU5vp8AAACYsMW6Dx4AAABLTMADAAAYCAEPAABgIAQ8AACAgRDwAAAA\nBkLAAwAAGAgBDwAAYCAEPAAAgIEQ8AAAAAZCwAMAABgIAQ8AAGAgBDwAAICBEPAAAAAGQsADAAAY\nCAEPAABgIAQ8AACAgRDwAAAABkLAAwAAGAgBDwAAYCAEPAAAgIEQ8AAAAAZCwAMAABgIAQ8AAGAg\nBDwAAICBEPAAAAAGQsADAAAYCAEPAABgIAQ8AACAgRDwAAAABkLAAwAAGAgBDwAAYCAEPAAAgIEQ\n8AAAAAZiqwJeVT2kqt5fVd+uqlZVx44tr6o6uaqurKqNVTVXVfcba7NnVb29qm7op7dX1R4T/CwA\nAADL2tYewVuR5JIkz0uycYHlL0hyYpLjkxyWZH2S86pqt5E270zygCS/2U8PSPL2W9dtAAAAxu28\nNY1aa+ckOSdJquqs0WVVVUlOSPKq1tp7+3lPSxfyjknypqo6KF2oe3Br7dN9m2cm+WRV3bu19uXJ\nfBwAAIDlaxLn4B2QZO8k587PaK1tTHJ+kiP6WYcn2ZDkwpH3XZDkxpE2AAAAbIetOoK3BXv3j9eM\nzb8myT4jba5trbX5ha21VlXrR97/c6rquCTHJcnKlSszNzc3ga5O1spdkxMPvnna3dhhLEUNN2zY\nMJM/K8udusweNZlN6jJ71GQ2qcvsUZPZMYmAtyhaa2ckOSNJVq1a1VavXj3dDi3g1LPfl9dePLO7\n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\n1Q8AAICh2nkJt7VXkp2SXDM2/5okjxhvXFXHJTmuf7mhqr68uN27VfZKct20O7GjqFcvyWbUZDap\ny+xRk9l7TB2LAAAI1ElEQVSkLrNHTWaTusyYPx5QTZboO+utsd/WNFrKgLdNWmtnJDlj2v3YnKq6\nqLW2atr94BZqMpvUZfaoyWxSl9mjJrNJXWaPmsyOpTwH77okP02ycmz+yiRXL2E/AAAABmnJAl5r\n7cdJ1iU5amzRUemupgkAAMB2WOohmq9L8vaq+r9JLkjyrCR3S/LXS9yPSZnpIaTLlJrMJnWZPWoy\nm9Rl9qjJbFKX2aMmM6Jaa0u7wapnJ3lBkrsmuSTJf2utnb+knQAAABigJQ94AAAALI6lvtE5AAAA\ni0TAuxWq6tlVdXlV3VRV66rqyGn3aUdVVQ+pqvdX1berqlXVsWPLq6pOrqorq2pjVc1V1f3G2uxZ\nVW+vqhv66e1VtcdYm4Or6p/6dXy7qv60qmqszeOr6otV9aP+8XcX7YPPsKp6cVV9tqq+X1XXVtUH\nqur+Y23UZQlV1XOq6gt9Tb5fVZ+uqkePLFePKev/3bSqOm1knrossX5/t7Hp6pHlajIlVXXXqnpr\ndf+v3NTvk4eOLFebJVRVVyzwb6VV1YdG2mz2+25V3a6qTq2q66rqxuq+z919rM2+1X2PuLFv91dV\ndduxNg/t139TVX29qp61uJ9+GWitmbZhSvLEJD9J8owkByU5NcmGJPtOu2874pTkt5K8MskTkvww\nybFjy1+Y5AdJHp/k/knek+TKJLuNtPlwkkuTHN5Plyb5wMjyO6a7Fcd7+nU8oV/niSNtDk9yc5KX\n9nV9af/6gdPeR1OoyUeT/H6/rw5O8vf9/vtldZlaTX4nyaOS3DPJgUle0f8e+lX1mP6U5EFJLk/y\nL0lOG5mvLktfi5OTfCnJ3iPTndVk6nXZI8nXk7wtyW8kOSDJw5McpDZTq8mdx/6d/HqSf0/ytH75\nFr/vJvlffY2OSvKAJHNJPp9kp375Tkku7uc/oG93ZZJTR9ZxQJIb+/Uf1G/vJ0keP+19tCNPU+/A\njjYl+UySM8fmfTXJX0y7bzv61P/iOHbkdSW5KslLR+bt2v+yfmb/+qAkLcl/HGnz4H7evfvXf5Tk\n+0l2HWlzUpJv55bzUN+d5Lyx/nwsybumvV+mPSVZke4elo9Rl9mZklyf5JnqMfU67J7ka0nW9F9i\nTuvnq8t06nFykks2sUxNpleXVya5YDPL1Wb6NXppku/N77ts4ftu/7vvx0mePLL8HulC4tH960f1\nr+8x0uYpSW5Kcsf+9auTfHVsO3+T5NPT3ic78mSI5jboDykfmuTcsUXnJjli6Xs0eAek+6vSz/Z3\na21jkvNzy/4+PF0wHL2X4gXp/ho02uaT/XvnfTTdLTr2H2kzXtePRl2TZLd0w7m/279Wlymqqp2q\n6r+kC94XRj2m7Ywkf9da+8TYfHWZnl/ph/ldXlVrq+pX+vlqMj2PTfKZqnp3Va2vqs9X1XNHhk6q\nzRT1dXh6kne01jZu5ffdQ5Pskp+v2beSXJafr8dl/fx5H01yu/79820Wqseqqtplez7XcibgbZu9\n0h1uvmZs/jXpfjExWfP7dHP7e+8k17b+Tz5J0j9fP9ZmoXVkK9qoa3JKuiEXn+5fq8sU9OeVbEjy\no3T3Dv3d1trFUY+pqapnpBs2e9ICi9VlOj6T5Ngkv5luqNfeSS6sqjtFTabpV5I8O90wzaPT/b/y\nqiTP6ZerzXQdlS5kn9m/3prvu3unG91z3RbajK/juv59W6rHzn0/uBWW+kbnwA6kql6XbgjMg1tr\nP512f5a5Lyc5JN2wmCckeWtVrZ5qj5axqrp3umFnD26t/WTa/aHTWvvw6Ouq+ud0oeJpSf55Kp0i\n6Q4oXNRae3H/+nNVda90Ae+0Tb+NJfKMJJ9trf3LtDvCZDiCt23m/+qwcmz+ynQn9TJZ8/t0c/v7\n6iR3Hr1CVv/8LmNtFlpHtqLNsq1rVb0+yZOSPKy19vWRReoyBa21H7fW/rW1tq7/kvT5JP8t6jEt\nh6f76/KlVXVzVd2c5KFJnt0//07fTl2mqLW2Id2FOO4V/1am6aokXxybd1mSffvnajMlVXWXdBfy\nOnNk9tZ837063VG+8aNs423G1zF/dHBL9bg5v3h0kK0k4G2D1tqPk6xLdyh71FH5+THhTMbl6f7h\n/2x/V9XtkxyZW/b3p9Odi3T4yPsOT3KHsTZH9u+dN38lpytG2qhrr6pOyS3h7ktji9VlNtwm3XkM\n6jEd/5DuKrOHjEwXJVnbP/9K1GXq+v12n3QBw7+V6bkgyb3H5h2Y5Bv9c7WZnmPTDf1/1/yMrfy+\nuy7d1S5Ha3b3dBfDGa3HQWO3Tjiq3966kTYLbecioyO2w7Sv8rKjTekuG/vjJH+Y7of4lHQn/e43\n7b7tiFO6X9bzX45+mORP++f79stfmOSGJI9Ld8njtVn4sskX55bLJl+cn79s8u7p/uNY26/jcemu\nsjV62eQj0v216EXpvgy8ON0vrmV12eR+X5ze75+H5ecvobxipI26LG1NXpXui87+6ULFX6S7Mtmj\n1GN2poxcRVNdplaDv0x3JPWAJA9M8sF+f+2nJlOty2H9539puvNWf6+vw3NG2qjN0tel0v0x6swF\nlm3x+2662yT8W5JHpLvNwiey8G0S/rFf/oh0VzRd6DYJb+i384f9dt0mYXtqO+0O7IhTuhOFr8gt\nf4F4yLT7tKNOSVanu8Tx+HRWv7zSXfb6qnSX1f2nJPcfW8eeSd7R/xL/fv98j7E2B6e7GtdN/br+\nLP0lk0faPCHd/ZN+nG7oyOOmvX+mVJOF6tGSnDzSRl2WtiZnpftL94/SXVDgY+kvQ60eszPlFwOe\nuix9DeZDwY/TfZF8b5L7qsn0pySPTnevyJvShYo/Ht1najOVmqxJ9//7b2xi+Wa/76YbRXJquiHp\nP0zygYzcEqFvs2+6P7T8sG/3V0luN9bmoUn+X7+dy5M8a9r7Zkef5u8JAgAAwA7OOXgAAAADIeAB\nAAAMhIAHAAAwEAIeAADAQAh4AAAAAyHgAQAADISABwAAMBACHgAAwEAIeAAAAAPx/wHVEJi/8UOV\nRQAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Distribution of the request body length\n", "bro_df[['request_body_len']].hist()\n", "print('\\nFor this small demo dataset almost all request_body_len are 0\\nCluster 2 represents outliers')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "\n", "## The anomalies identified by the model might be fine/expected\n", "Looking at the anomalous clusters for this small demo http log reveals four clusters that may be perfectly fine. So\n", "here we're not equating anomalous with 'bad'. The use of an anomaly detection algorithm can bring latent issues to the attention of threat hunters and system administrations. The results might be expected or a misconfigured appliance or something more nefarious that needs attention from security.\n", "\n", "\n", "If you liked this notebook please visit [SCP Labs](https://github.com/SuperCowPowers/scp-labs) for more notebooks and examples, or visit our company page for consulting and development services [SuperCowPowers](https://www.supercowpowers.com)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n" ], "text/plain": [ "" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# This cell is simply for adding some CSS (Ignore it :)\n", "from IPython.core.display import HTML\n", "def css_styling():\n", " styles = open(\"styles/custom.css\", \"r\").read()\n", " return HTML(styles)\n", "css_styling()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.9.6" } }, "nbformat": 4, "nbformat_minor": 2 }