From ceb4f0335a700afaed3b6f92861834c2692cf5a1 Mon Sep 17 00:00:00 2001 From: wisepythagoras <55108282+wisepythagoras@users.noreply.github.com> Date: Sun, 9 Feb 2020 15:29:18 -0500 Subject: [PATCH] Initial commit --- .gitignore | 103 +++++++++++++++ LICENSE | 21 +++ README.md | 84 ++++++++++++ classifier-nb.dmp | Bin 0 -> 5456 bytes config.json | 11 ++ defense.js | 97 ++++++++++++++ example-fingerprints/fingerprints.csv | 121 +++++++++++++++++ gather_and_train.py | 74 +++++++++++ graph.py | 40 ++++++ graphs/.RData | Bin 0 -> 41680 bytes graphs/graph-screenshot.png | Bin 0 -> 36927 bytes metadata/jjay-1 | 35 +++++ metadata/jjay-2 | 40 ++++++ metadata/jjay-3 | 39 ++++++ mysources.json | 29 ++++ package.json | 12 ++ packet.py | 28 ++++ pcaps/capture.sh | 22 ++++ pcaps/mass.sh | 29 ++++ predict.py | 63 +++++++++ utils.py | 182 ++++++++++++++++++++++++++ 21 files changed, 1030 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 classifier-nb.dmp create mode 100644 config.json create mode 100644 defense.js create mode 100644 example-fingerprints/fingerprints.csv create mode 100755 gather_and_train.py create mode 100644 graph.py create mode 100644 graphs/.RData create mode 100644 graphs/graph-screenshot.png create mode 100644 metadata/jjay-1 create mode 100644 metadata/jjay-2 create mode 100644 metadata/jjay-3 create mode 100644 mysources.json create mode 100644 package.json create mode 100644 packet.py create mode 100755 pcaps/capture.sh create mode 100755 pcaps/mass.sh create mode 100755 predict.py create mode 100644 utils.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f74b184 --- /dev/null +++ b/.gitignore @@ -0,0 +1,103 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +*.pcap + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5dce3a2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Constantine Apostolou + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1b36326 --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# Website Fingerprinting + +Website fingerprinting is a method of Tor or VPN packet inspection that aims to collect enough features and information from individual sessions that could aid in identifying the activity of anonymized users. + +## Introduction + +For this experiment Tor is required. It can be installed by running the following commands: + +``` bash +# For Debian or Ubuntu +sudo apt install tor lynx + +# For Fedora +sudo yum install tor lynx +``` + +By installing Tor we also get a program called `torsocks`; this program will be used to redirect traffic of common programs through the Tor network. For example, it can be run as follows: + +``` bash +# SSH through Tor. +torsocks ssh user@example.com + +# CUrl through Tor. +torsocks curl -L http://httpbin.org/ip + +# Etc... +``` + +### Required Python Modules + +``` bash +pip install sklearn dpkt +``` + +## Data Collection + +For the data collection process two terminal windows in a side-by-side orientation are required, as this process is fairly manual. Also, it's advised to collect the fingerprints in a VM, in order to avoid caputring any unintended traffic. To listen on traffic there exists a script, namely [capture.sh](pcaps/capture.sh), which should be run in one of the terminals: + +``` bash +./pcaps/capture.sh duckduckgo.com +``` + +Once the listener is capturing traffic, on the next terminal run: + +``` bash +torsocks lynx https://duckduckgo.com +``` + +Once the website has finished loading, the capture process needs to be killed, along with the browser session (by hitting the `q` key twice). The process should be repeated several times for each web page so that there is enough data. + +## Machine Learning + +[Scikit Learn](http://scikit-learn.org/stable/) was used to write a [k Nearest Neighbors](http://scikit-learn.org/stable/modules/neighbors.html#nearest-neighbors-classification) classifier, that would read the pcap files, as specified in the [config.json](config.json) file. `config.json` can be changed according to which webpages were targeted for training. The training script is [gather_and_train.py](gather_and_train.py). + +

+ Scikit Learn kNN +

+ +## Classifying Unknown Traffic + +Once the training is done, and the `classifier-nb.dmp` is created, the [predict.py](predict.py) script can be run with the pcap file as the sole argument. The script will load the classifier and attempt to identify which web page the traffic originated from. + +It is worth noting that from each sample only the first 40 packets will be used to train a usable model and to run through the resulting classifier. + +

+ Visualizing the patterns +

+ +As it can be seen in the screenshot above, the patterns of the packets of each website can be seen clearly on a 3D scale. The classifier visualizes the data in a similar way and gives us the most accurate result. + +An interactive version of this graph can be found in the [graphs](graphs) folder. + +## Limitations and Disclaimers + +This setup was created in order to research the topic of website fingerprinting and how easy it is to attempt to deanonymize users over Tor or VPNs. Traffic was captured and identified in a private setting and for purely academic purposes; use of this source code is intended for those reasons only. + +Traffic is never "clean", as the assumption was - for simplicity - in this reasearch. However, if an entity has enough resources, the desired anonymized traffic can be isolated and fed into this simple classifier. This means that it is entirely possible to use a method like this to compromise anonymized users. + +## References + +1. Wang, T. and Goldberg, I. (2017). Website Fingerprinting. [online] Cse.ust.hk. Available at: https://www.cse.ust.hk/~taow/wf/. +2. Wang, T. and Goldberg, I. (2017). Improved Website Fingerprinting on Tor. Cheriton School of Computer Science. Available at: http://www.cypherpunks.ca/~iang/pubs/webfingerprint-wpes.pdf +3. Wang, T. (2015). Website Fingerprinting: Attacks and Defenses. University of Waterloo. Available at: https://uwspace.uwaterloo.ca/bitstream/handle/10012/10123/Wang_Tao.pdf + diff --git a/classifier-nb.dmp b/classifier-nb.dmp new file mode 100644 index 0000000000000000000000000000000000000000..c3241f03fcf73890253593fac77fa2ac7c384278 GIT binary patch literal 5456 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 literal 0 HcmV?d00001 diff --git a/config.json b/config.json new file mode 100644 index 0000000..a445ea9 --- /dev/null +++ b/config.json @@ -0,0 +1,11 @@ +{ + "pcaps": [ + "duckduckgo.com", + "github.com", + "jjay.cuny.edu", + "telegram.org", + "reddit.com", + "torproject.org", + "perdu.com" + ] +} diff --git a/defense.js b/defense.js new file mode 100644 index 0000000..b8698ab --- /dev/null +++ b/defense.js @@ -0,0 +1,97 @@ +"use strict"; + +const TorAgent = require("toragent"); +const request = require("request"); +const mysources = require("./mysources.json"); + +let websites = mysources.sources; +let agent = null; + +/** + * Gets some random URLs from articles. + * @param {function} callback This is called when this is done. + */ +function getNews(callback) { + let newsUrl = "https://newsapi.org/v2/everything?q=snowden&sortBy=publishedAt&apiKey="; + newsUrl += mysources.newsapi_key; + + // Get the articles. + get(newsUrl, (error, results) => { + if (!error) { + // Parse the results. + results = JSON.parse(results); + + // Add the articles to the list. + for (let i = 0; i < results.articles.length; i++) { + websites.push(results.articles[i].url); + } + } else { + throw(error); + } + + callback(); + }); +} + +/** + * Connects to the Tor network. + * @param {function} callback The callback function that's called once we're + * connected to the network. + */ +function connect(callback) { + console.log("Getting new identity"); + + TorAgent.create(false, function(error, newAgent) { + if (error) { + // Unable to connect to the Tor network + throw(err); + } + + agent = newAgent; + callback(); + }); +} + +/** + * Creates a simple HTTP GET request. + * @param {string} url The URL to get. + * @param {function} callback The function called once the request is done. + */ +function get(url, callback) { + request({ + url: url, + agent: agent, + rejectUnauthorized: false, + }, function(err, res, body) { + if(err) { + websites.splice(websites.indexOf(url), 1); + callback(err, false); + } else { + callback(null, body); + } + }); +} + +/** + * Gets a random website from the list. + * @returns {string} A URL of a page to load. + */ +function getRandomPage() { + let len = websites.length; + return websites[Math.round(Math.random() * len) % len]; +} + +/** + * Generates random traffic. + */ +function loadRandomUrl() { + let page = getRandomPage(); + get(page, (err) => console.error(err ? err : `GET: ${page}`)); + + setTimeout(loadRandomUrl, Math.round(Math.random() * 800) % 800); +} + +// Connect to Tor and begin jamming the session. +connect(() => { + getNews(loadRandomUrl); +}); \ No newline at end of file diff --git a/example-fingerprints/fingerprints.csv b/example-fingerprints/fingerprints.csv new file mode 100644 index 0000000..97af98d --- /dev/null +++ b/example-fingerprints/fingerprints.csv @@ -0,0 +1,121 @@ +domain,total_incoming_sizes,total_number_packets,no_outgoing_packets,no_incoming_packets,ratio_incoming_to_outgoing,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39 +duckduckgo.com,27427,96,41,55,1.34146341463,609,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609,609,-66 +duckduckgo.com,26971,98,42,56,1.33333333333,597,-60,-597,54,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-1514,-165,54,597,-60,-597,597,-60,-597 +duckduckgo.com,26911,96,41,55,1.34146341463,597,-60,-597,54,597,-60,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-1514,-165,54,597,-597,597,-597,597,-60 +duckduckgo.com,27241,105,45,60,1.33333333333,597,-60,-597,54,597,-60,-60,-597,597,-60,597,-60,609,-597,597,-66,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,609,609,-60,597,-66,-66,-60,-597,597,-60,-1514,-165,54 +duckduckgo.com,26971,97,41,56,1.36585365854,597,-60,-597,54,597,-60,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-1514,-165,54,597,-60,-597,597,-60,-597,597 +duckduckgo.com,26971,96,40,56,1.4,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-1514,-165,54,597,-60,-597,597,-60,-597,597,-60 +duckduckgo.com,26971,96,40,56,1.4,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-1514,-165,54,597,-60,-597,597,-60,-597,597,-60 +duckduckgo.com,27031,98,41,57,1.39024390244,597,-60,-597,54,597,-60,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-1514,-165,54,597,-60,-597,597,-60,-597 +duckduckgo.com,27508,99,43,56,1.3023255814,597,-60,-597,54,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-1514,-165,54,597,-60,-597,597,-60,-597,597 +duckduckgo.com,27151,101,42,59,1.40476190476,597,-60,-597,54,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-1514,-165,54,597,-60,-597,597,-60,-597,597 +duckduckgo.com,26851,95,41,54,1.31707317073,597,-60,-597,54,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-1514,-165,54,597,-597,597,-597,597,-60,597 +duckduckgo.com,27031,98,41,57,1.39024390244,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-1514,-165,54,597,-60,597,-60,-597,597,-60,-597 +duckduckgo.com,27568,100,43,57,1.32558139535,597,-60,-597,54,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-1514,-165,54,597,-60,-597,597,-60,-597,597 +duckduckgo.com,27091,99,41,58,1.41463414634,597,-60,-597,54,597,-60,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-1514,-165,54,597,-60,-597,597,-60,-597,597 +duckduckgo.com,27295,104,43,61,1.41860465116,597,-60,-597,54,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-1514,-165,54,-66,66,-66,-66,66,-66,597 +duckduckgo.com,28073,98,41,57,1.39024390244,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609,609 +duckduckgo.com,26971,96,40,56,1.4,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-597,597,-60,597,-60,-597,597,-60,-1514,-165,54,597,-60,-597,597,-60,-597,597,-60 +github.com,39829,98,42,56,1.33333333333,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609 +github.com,39829,97,41,56,1.36585365854,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +github.com,39668,93,39,54,1.38461538462,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-609,609 +github.com,39183,94,40,54,1.35,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609 +github.com,39212,88,34,54,1.58823529412,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609,609 +github.com,40248,94,39,55,1.41025641026,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-609,609 +github.com,39697,96,42,54,1.28571428571,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-609,609 +github.com,40372,91,35,56,1.6,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-609,66,-1123,66,609,-66,-609,66,609,-66 +github.com,39829,97,41,56,1.36585365854,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +github.com,40182,90,36,54,1.5,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609 +github.com,39602,87,34,53,1.55882352941,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609,-66 +github.com,39183,93,39,54,1.38461538462,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609,609 +github.com,40429,97,38,59,1.55263157895,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609,609 +github.com,39220,95,40,55,1.375,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +github.com,39763,89,34,55,1.61764705882,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +github.com,39088,93,40,53,1.325,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,609,-66,-609,66,609,-66,-609,609 +github.com,39220,91,36,55,1.52777777778,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609 +github.com,39734,92,37,55,1.48648648649,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +jjay.cuny.edu,63096,115,49,66,1.34693877551,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,74,-74,66,532,-609,609,-66,-1514,66,-1514,66,-166,66,-66 +jjay.cuny.edu,35647,64,22,42,1.90909090909,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,609,-1514,-1514,66,-797,-66,-1514 +jjay.cuny.edu,36227,70,27,43,1.59259259259,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,-1514,-1514,66,-797,-1514,66,-1514 +jjay.cuny.edu,35610,72,31,41,1.32258064516,609,-66,-609,66,609,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,-1514,-1514,66,-797,609,-1514,66 +jjay.cuny.edu,36256,65,22,43,1.95454545455,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,-1514,-1514,66,-797,-1514 +jjay.cuny.edu,35742,74,31,43,1.38709677419,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,66,-283,66,-1514,66,-1514,66 +jjay.cuny.edu,35742,67,24,43,1.79166666667,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,-1514,-1514,66,-797,-1514,66 +jjay.cuny.edu,52344,89,32,57,1.78125,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,705,-66,-117,66,274,-609,609,-66,-66,609,-66,-609,609,-66,-609,609,-1514,-1514,66,-1514,-1514,66,-1514,-1514,66,-1514,-1514,66 +jjay.cuny.edu,35742,71,28,43,1.53571428571,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,-1514,-1514,66,-797,-1514,66,-1514 +jjay.cuny.edu,35581,63,22,41,1.86363636364,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,-1514,-1514,66,-797,-1514,66,-1514 +jjay.cuny.edu,35713,71,28,43,1.53571428571,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,-1514,-1514,66,-797,-1514,66 +jjay.cuny.edu,36256,75,32,43,1.34375,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,66,-1514,66,-1514,66 +jjay.cuny.edu,35713,70,27,43,1.59259259259,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,-1514,-1514,66,-797,-1514,66 +jjay.cuny.edu,36322,75,31,44,1.41935483871,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,-1514,-1514,66,-797,-1514,66,-703 +jjay.cuny.edu,7110,46,20,26,1.3,609,-66,-609,66,609,-66,597,-60,-609,609,-597,54,-66,609,-66,-609,609,-66,-609,609,597,-66,609,-60,-66,-609,609,-66,-609,609,-66,609,-66,1123,597,-66,-60,-609,609,-609 +jjay.cuny.edu,62516,106,41,65,1.58536585366,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,74,-66,-74,66,534,-609,609,-66,-1514,66,-1514,66,-215,66,257,-66,609,-324,66,279,-66,-609,609,-66,-66,-609,609,-66 +jjay.cuny.edu,35742,74,31,43,1.38709677419,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-1514,-283,66,66,-1514,66,-1514,66 +telegram.org,20580,69,29,40,1.37931034483,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609 +telegram.org,20514,69,30,39,1.3,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609 +telegram.org,20580,70,30,40,1.33333333333,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +telegram.org,20514,69,30,39,1.3,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609 +telegram.org,20580,70,30,40,1.33333333333,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +telegram.org,21123,73,33,40,1.21212121212,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609 +telegram.org,53575,125,53,72,1.35849056604,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609 +telegram.org,33207,85,35,50,1.42857142857,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +telegram.org,41458,114,49,65,1.32653061224,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-609,609 +telegram.org,20580,70,30,40,1.33333333333,1123,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +telegram.org,20646,72,31,41,1.32258064516,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +telegram.org,20646,71,30,41,1.36666666667,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66 +telegram.org,40514,101,42,59,1.40476190476,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,74,-609,609,-74,66,341,-66,609,-66,-219,66,397,-66,-609,-66,609,-66,-609,609,-1514,-1514,66,-1514,-1514,66 +telegram.org,21341,80,35,45,1.28571428571,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,74,-74,66,312,-66,-489,66 +telegram.org,20514,69,30,39,1.3,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609 +telegram.org,41153,106,46,60,1.30434782609,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,74,-74,66,341,-609,609,-66,-1514,66,-1514,66,-1514,-245 +telegram.org,20580,70,30,40,1.33333333333,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-609,609 +reddit.com,111578,170,65,105,1.61538461538,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +reddit.com,109361,161,58,103,1.77586206897,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609,609 +reddit.com,111931,164,61,103,1.68852459016,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609,-66 +reddit.com,110015,161,55,106,1.92727272727,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66 +reddit.com,109862,162,57,105,1.84210526316,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66 +reddit.com,109974,163,60,103,1.71666666667,609,609,609,609,609,609,-66,-609,609,-66,-609,609,609,-609,78,-78,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66 +reddit.com,109574,161,55,106,1.92727272727,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609,-66 +reddit.com,109332,159,56,103,1.83928571429,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +reddit.com,109237,163,61,102,1.67213114754,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609 +reddit.com,108230,159,58,101,1.74137931034,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609 +reddit.com,109171,153,52,101,1.94230769231,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-609,66,609,-609,609,-66 +reddit.com,108913,165,61,104,1.70491803279,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66 +reddit.com,111557,174,68,106,1.55882352941,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +reddit.com,110447,155,52,103,1.98076923077,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609 +reddit.com,110607,164,56,108,1.92857142857,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +reddit.com,108657,162,61,101,1.65573770492,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-66,-609 +reddit.com,109398,165,61,104,1.70491803279,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,609,-66,-609,66,609,-66,-609,609,-66 +torproject.org,20580,68,28,40,1.42857142857,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609,609 +torproject.org,20646,70,29,41,1.41379310345,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609 +torproject.org,20675,70,29,41,1.41379310345,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609,609 +torproject.org,20646,69,28,41,1.46428571429,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609 +torproject.org,20712,71,29,42,1.44827586207,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609 +torproject.org,20712,70,28,42,1.5,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609 +torproject.org,20646,69,28,41,1.46428571429,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609 +torproject.org,20807,72,29,43,1.48275862069,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609 +torproject.org,21189,71,30,41,1.36666666667,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,66,-609,66,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609 +torproject.org,21255,72,30,42,1.4,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609 +torproject.org,20646,69,28,41,1.46428571429,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609 +torproject.org,20646,69,28,41,1.46428571429,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609 +torproject.org,20646,70,29,41,1.41379310345,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,609,-66,-609,609,-66 +torproject.org,20580,68,28,40,1.42857142857,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609,609 +torproject.org,20580,67,27,40,1.48148148148,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609,609,-66 +torproject.org,20646,69,28,41,1.46428571429,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609 +torproject.org,20646,73,32,41,1.28125,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1514,-189,66,609,-66,-609,609,-66,-609,609 +perdu.com,6178,33,13,20,1.53846153846,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0 +perdu.com,6178,33,13,20,1.53846153846,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0 +perdu.com,6178,33,13,20,1.53846153846,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0 +perdu.com,6112,32,13,19,1.46153846154,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0,0 +perdu.com,6112,32,13,19,1.46153846154,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0,0 +perdu.com,6112,32,13,19,1.46153846154,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0,0 +perdu.com,6450,34,13,21,1.61538461538,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-272,-1123,66,0,0,0,0,0,0 +perdu.com,6178,33,13,20,1.53846153846,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0 +perdu.com,6112,32,13,19,1.46153846154,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0,0 +perdu.com,6178,33,13,20,1.53846153846,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0 +perdu.com,6457,42,18,24,1.33333333333,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,74,-1123,66,-74,66,313,-66,-73,66,-66 +perdu.com,6112,32,13,19,1.46153846154,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0,0 +perdu.com,6112,32,13,19,1.46153846154,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,1152,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0,0 +perdu.com,6178,33,13,20,1.53846153846,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0 +perdu.com,6178,33,13,20,1.53846153846,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0 +perdu.com,6112,32,13,19,1.46153846154,609,-66,-609,66,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0,0 +perdu.com,6178,33,13,20,1.53846153846,609,-66,-609,66,609,-66,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-609,609,-66,609,-66,-609,609,-66,-1123,66,0,0,0,0,0,0,0 diff --git a/gather_and_train.py b/gather_and_train.py new file mode 100755 index 0000000..00501fc --- /dev/null +++ b/gather_and_train.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python + +import os +import re +import sys +import json +import utils +from sklearn.externals import joblib + + +# Read the configuration and start training. +with open('config.json') as fp: + print("* Parsing configuration") + + # Load the configuration from the file. + config = json.load(fp) + + # This is where all the streams are going to live. + streams = [] + + # This is where all the labels are going to live. + labels = [] + labels_str = [] + base_labels = [None] * len(config['pcaps']) + + # The base label starts from 1 and increments after that. + current_label = 1 + pat = re.compile(".*-curl\.pcap$") + + for domain in config['pcaps']: + # Set the base label. + base_labels[current_label - 1] = domain + + # Increment the label + current_label += 1 + + utils.empty_csv() + current_label = 1 + + for domain in config['pcaps']: + print(" - {}".format(domain)) + i = 0 + + # Traverse the directory for all the pcaps. + for file in os.listdir('./pcaps/{}'.format(domain)): + if file.endswith(".pcap") and (pat.match(file) is None): + # if i > 20: + # break + + # This is the pcap file we'll be reading at this point. + file = os.path.join("./pcaps/{}".format(domain), file) + + # Read the pcap file. + data = utils.read_pcap_file(file) + + # Append the data to the streams array. + streams.append(data) + + # Append everything to the log. + utils.append_to_csv(domain, data) + + # Add a label for the new file. + labels.append(current_label) + labels_str.append(domain) + + i += 1 + + print " {} pcap files".format(i) + + # Increment the label + current_label += 1 + + # Finally train the classifier. + utils.train(streams, labels) diff --git a/graph.py b/graph.py new file mode 100644 index 0000000..8828cbd --- /dev/null +++ b/graph.py @@ -0,0 +1,40 @@ +from plotly import offline +import plotly.plotly as py +import plotly.graph_objs as go +import numpy as np +import pandas as pd + +# Read the data. +data = pd.read_csv('./example-fingerprints/fingerprints.csv') + +d = data['domain'] +#x = data['total_number_packets'] +#y = data['no_incoming_packets'] +#z = data['no_outgoing_packets'] +x = data['total_incoming_sizes'] +y = data['ratio_incoming_to_outgoing'] +z = data['total_number_packets'] + +xt = [] +yt = [] +zt = [] +data = [] + +for i in range(0, len(x)): + if i == len(x) - 1 or d[i] != d[i + 1]: + data.append(go.Scatter3d(x=xt, y=yt, z=zt, mode='markers', \ + marker=dict(), name=d[i])) + + xt = [] + yt = [] + zt = [] + else: + xt.append(x[i]) + yt.append(y[i]) + zt.append(z[i]) + +layout = go.Layout(margin=dict(l=0, r=0, b=0, t=0)) + +fig = go.Figure(data=data, layout=layout) +offline.plot(fig, filename='graphs/graph.html', auto_open=False) + diff --git a/graphs/.RData b/graphs/.RData new file mode 100644 index 0000000000000000000000000000000000000000..31dcd1938e7aeceb050e4e61f865ca3cebf995d9 GIT binary patch literal 41680 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 MLdMNknB>;~0e!2g6#xJL literal 0 HcmV?d00001 diff --git a/graphs/graph-screenshot.png b/graphs/graph-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..65d579ac82ee30f75d1dcf0fcca8de35e285a457 GIT binary patch literal 36927 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

QvPzHDK z028dlU}SWGWW=uE^dax%1P1M2)n zih4`bP|xybA2=&|k_!ax53sPk6)#M0(q0>#1bM6LQx@6=JDOl$gp!Fo{yH+nwPs=L z4$|7hm%wd~STD8}3np9V32E~lTSf0Hy$|^>JQbk;VrWt;d~%oFn=ZR6wW6b|es{j1Di-7) z`;DHi@%m5S8N$TGgHMk)d<;z)vES^YXUlQpGs}Ku=4kYs_NsROVB_3z$oAhs992_j z$XU-R_St(X493K#6OPwj^qD(CAQ0iQ&?zTJs*1n-FpHYbWe9J#;mFmFKfh^VV~yB* zzTDRQ7Q2UR6MlYviiAK}my?D(?+Is~Dv#wwH9RRecnFu+$;>aegF=nPH)0S&e+spe z>YkZt@Yxb2F5$DItgHyvOuqgRWeNxnm$myY zYWeQj=l5(d%0bO>?+cubJ*Kj?k?5gr*E5gfpKan&Yvy)OeZw>SiO-tYg(wKZ&dR|( zmCeP)&ig+e>CMC*vy26maSRx-4D#8`(5HKF%SK5o`m%(>ZEf4C`)@lxdSx~5Ilir6 zTN|-HRqTa|CaiUiz=Kwlox&&ic9s)q)=YA$Wxen#9+15&ZK6!|iQuJTs->e87k62V zlnbukaS3-~S>3{0;t}gL8~-hfx7Ws znLyD$45F>wk4m?iX+&*|_MMV~jN7q^i4O>;drV#DgC(sK`NffCFD*1PA%Xr$(mela z$fjUjMo7*s&kEe$<7;Je(9a2K6LgQ>NzzH=R7)?teXT;%-{ZJ~@I7odhJ>dH2P|6E z`faAJNYGqOO-&gne42tIY3HnjbGvWr2~$bo)N5jA2m^e4a#i0zN5sE%KRvTO0H8g9%m3O@i*2}7@zuO+ zak{yA7rTNLO9qlDh21aw;d^W2F_b2n(Dr6-En}p_J1v*O!K=4gwQG9Cp&N<;vwUP? zQ|ajC(Mztb9u?OUOpIW82jM*?2Y`$dNYMhE1z_ST@z){u0EQZnM#I>{Kb>*-m~s?% zDe2@s7S#@6Kyyr9rNlP(F0I91TMM2EOxYut2#UgHRrC~hSUu~nK$5BG+BUYU5gJN# zjY<-9WWZAap6}bdXJY6~oF@GcG%C>p8x-pHWChA;e^GW_T9Lld$zwyNtzsjv2}Pux zYPZplJq_XPWthtNzOibZd(wQAv2Q8*3JRG$SY}KP=JXGFtHJlC*M88c`i*XZgtD^R zkrxnqip;Cv&z?)D{O)*AVd8UCU!U)Ora$_N{@C}(Vihc^zsEtN@h_6lIRWz0a1Ihc zl>ql8hE{`m!e@3s-H}#MzrCM$J1)XS#`(xgSM?ft$dR1jrSOa?2I-3P%2-gK#sJ`` zVm)!+#w(H6Rin{-rUrvqHcK0oCAO93apW^#fX@Pc@>i!_rP=qsJ_uI=B(>+j69)ao z06-pR47fvQ&_P-*Z0$^?cv%hrBdov8TmCzBRu_DnGi+r0RK6nDx~tDQx-@x3{5>A! zgS*4IabVWr>n+**M$>btNt7W=l>V3LN*P=52~FNYQogH)?h9ltCk}1i1K5BSovFZ+ z4+RUuV#yk>>C4l#DH>31;&h*f9KoNQzC=Xh*XHGLkSXgR9p|qweSk3)jiWX(|cP4#*iH$%| zijFs3`+@#{x*tW@;~%r;FULAcsW+ER-uxD7h50V*UW{Kh*g;X2 znwLV7HSX*Gm#i%7WA#ue=T)wNM!vxnYjtTAPJhM60<3TP7cQ)b=~}>G>iGss+pAv; zZvWZ}05349*l2?YF%7tSx7Rc1b^3P}PT*r~?LA`Pd$o2;_-f}d(pquD;z-B@_aWX0 zWOcRAZR##xmi@x}L4mH32ULprBP{r+U=cBtMU+?INjDH zx(lJ4V(i(9yOEvRlmwTX%ZI<|buXUO5p{rzEWL~wx-Tp!${r7zVA(pk4~+x^4n`Z2 zrR#^R2lf4GI0_O#armEy3)?@|)zw1i)(K*9ch@b;{(yrKWyS8##`k;XC8c#}gCUw@ASTeh6$vKdmuI~$ zLk{Dm75ANxWBlE7xI^!Z2cl5?zXxRXPK*Gc~bOp*;-lg8E4!IzXk6iItUji+FU{HGFzWf?Ma7%~PewBZf^qg>_ zWoK>^OZHN_f|!zRX8knq{^DZA*mpd_C6*bSe)IMlxN@%>10pX=uk^~FPHnuVZF)C> zrmgdOariq36>a5FET`K zyWOvx{VUXp1Z6b|MysC3AFXf=)$4|E2n3x{7rNNLRhUVBy6&FPfvUZEfiSPX1eKP`&E>r(IkMw zuV2P}{(#LgAhe^hOeis-``3#}ZRk7DV)u?oP|y6|_8PHmF<+VodompaV^rxy9-C)? zIXfC?V-F@!VfIGdEG86tOI0x*K&znlTc7q>BJe^yImpB=kQf^qpF<GjmDLQ=D#|=xkb}u34NyMbKc$u1 zm!scWrCeD}pLN1N@wsuWhZ?B)2DL3MLd<5>LBEn%ht)lnT+i30wA$b}2M2 zPE_XjN93^xu*bs#0xpw)BI<86?q;M4k|Msd4T&53V7kg2RspG@f};gG=_?3Cb` zp-@|HWwaBJpWbzOo1@}7evX~p`X}KQBD;4fAr-Fy!WT@@DloSwGQ1?LA;cb^<$Dfq zilR7U!YxG?0;~N7P;l6X&j8N>aRTKgmbo90E9El_@>uTr%(Ke4xlx1^k+jzH{&3px zu~m)5Jm;=ET;UD}a@yva5ZfevsMJvKda?#DxB%j3$8272dvB0T2KiI$NjQQEL<0%c z)pr1CQizNLHxKCIP`Lu2{Hx-%46S@QHWvNOo$ilTZH>&^HO-;>r(#X(PHeJ;5y95&CqPgZcquKA?gU9*{64eVbln=z6;sV*462e$ z$wpxQm;mpjysg$@`{D(Cht1~w6caiRj%z}KH(<;si7>;UHl^?uVW!0-YlStfG5Q88 zIOC=v?}~MgFD3z$qS+3b?pkvMX5o=UxXKliZ0k)v5Cf{nvd4ci7)L|mbKL$R$Q#KT zWety@H6WCJnWjIkQzc5W7%)Xi68+#pm)#G%*Tu%7U0qcpzsDJ0e;)pX##oIX`IK_8 z2KUTYtp0OX@*6Kf_*&Os-hoCpF8{W8Hu3Sj(B_sXbFBCVbFv6X1~Rv>ST^(`SJRg> zVz|zev?u)dQN96yLl1=6M@WF1Lw`%gYBnt*x>t_kTLs ztCb&d4uaPKQ2cuk{1I-#I07ri9jhI+em3zbZB%|%`g+)$Ch26R{1Y1iIAdKSlPEDv z(lCMjcc_(6_q-$sC)I1@=(cA2D1TH*Oes!shP7UJY?QL)7yC_y0@ekPP~RNpw8P%! zHwvULg3g!sZks~{)9gbJ;*+wr-G6=NuMa4Q1<4HyoFfgq=2Q_40crn*5cMxumtNjcamidxDO@M1sXM3i8X|Chh+HF*&))xwAf{yr2$QVGnuCi~* z$$iwc8w64dUPT+flkH&#r>Sj2IH5TwrI(U07wR8i3DZuMUq0O=FSBmpVGVvZX87}W zx$GtwE?1lm6#C=oOiJdMu2hQFRnu?m#-J)E(2l+Y1+{%g>)b109?`6gK-00g;OYiZ z*IgC<>;%rN($Qg{()1vehu@d$53EGyb|XrL;zVficFo}R<*m0VnwQ`pdo2GlwSCM;EGgkjzBR|jnt3Eu!%nI( z*`#R%LV${{kuO@aa5pA|)~^j}e-2B>rjr@yA) z&t#7=Bvw*H+Y34F!ZY@#&cbx!&eTtzGTc8dBJ~{y0s(&S!B3_jQzRCS)@FEu#xqO> zYd^t>&giiPEkESW-d$v7Vj>e8XH4o0I*dzAO-=4!unN06UW~Q*(ZXjU*U|fG(VG5= zTLsIU%zy4fujH@!v-=apPA0at_#rf86tD_ymk?pTcU^sJZm#dDCxnnWLl0gjzgu0N ziRLwzX)OE;{Acni9TbY|XnyqNKdqarG|_#(Ibxxt<1XwZjPV@`L{{5@xgFl95cmh9 z+-Ma`x61L%#ZxOL-;+}%XF_oQPV@QvhhQnd0+iVJq0xZylWBTv#1@x(A1nZ?8IV?^ zSiIr8%wQeLg1+XxxZ6_*LMz+vcI@6^e|MzZFzmj>qg^pF%q0lq@_7Tmz5s4?>v{PW zcNr1GouCfF`6Q6H0OC^+@~h{~F5Meh_5rfFo^>9vN}-SA`}T62zNh3G-*ck@xJh08 z{(B*KYAN_8ET_NYXFJJ&rz+-t@{xt7q%T4EH17#KZgx(p^~m(c;%=3)K&;JcGgCLJ zscFUDB0uY*yEK?oF&NDuGXn9st@+W_2GordEnt8AkPRI+Oq>44&7HvX>N-d66IC{V zXVt9q>2>E?Ypb)(E|Kq8%2=NT>sg1A0D^;d@OhLW6JS-_%-ke78X5l=S|f~$&y8Bj z#M+q%a0>=S7oXy)XTcrpn+2?iop z1NY>}b7C`gXL3q00pUPL0V5>=8j+o3dUzNN7))Vf7C`^=SNdg*0d%6k?>q5DoMig7 zDT`Fxvlm`ewi#N0uG-&8@sp=K@{UD(w>^I`+s+1laYVF3z2&7CxHo%o3Rnj5YS!w> zS z8@c!&$PvM}U3>;bhEEkS_GZ8nv?V&895>kyI$yO5a|8T&1G>_vKrcsKf#)F~^HO@> z11PI6Xe!UVbhks;yEUvc*(%Lj7tji(htX)8*H@2LNW#|QEB{?6)K_A|ASqah zShPsW5Oxqf{?Q3dWnHnG7N`~@l6fDynyHm3>Zoc;tgm zFF}UPN4+)^$vpwTBndAJX-}DRR{9?lY8k9_B=WGLi;gLo8!R^`#Gf_k)ok|nod-6% zDk?wBrv7CZ+%|W1k-jvopnaywTu$%K3F5 zD-%3i@HeB^o++s_@-E?${^}0$Lmj9HSbfs)Ql482WYZ;z(cWtlFRQBZo>^#_nBW4! z9;uuVgocFzMl%Ke4sQ1XOl9B~Q3SaY0bpvqZz<25pNJu`LsKA(#{_+-lc1iAfo#87 zTv}%bd092ew;)_G;i;qrNT=thf-&s}$IKR{ruQY&SAt!t%@qg!@Y2>Iu{N6{RZ4Mt zo_ke*`$?3bEjs0%ajFh{im`>{!a4nKy90j!4DW|8zy(Ha5X#pItznRr!x zl)5tamC3Ou2tqzh5V~}${U(llUiFUc&~&Cn>j|bj0HSS_wX!-B^Pt_+nVYvi8x)Zx z@k^!C0sfFw?uK7l>8@@N4n>650zD8UaeOtzox#EQ{F6WhnPZ^?1**{NU%}%$TyE<+$0-#6SVllc8v{tnP65k(sqLIb^Jr}K z>x;O^J?wf2L%O!TP0lG}axK`*q%tBFMBP?WY#_Ez!X65}-roF(FI*E1%m=BW>l1A# zDswP(0A*IVn3$63z$3z7Sp&f&OPM<+ydXQUdkbHRU;eSGA)}3jEkuYy&Qrq0 zlF2`OQPKaePj~>3*8U1>JEJ8yLybn7_R27ILZ4(DcpaAWMgq#4a z=yov{?tlRFM4ulH9zqA`BLVUJ@D~f!ft=U2{|!^0^99If@Kvmb~Q_hpt0DXwWrEzlC!? zW+eyfodoP$&=#qZ(AhtbFnmx6Ha-;cZ{w?i&p(25QUJALU6xG6D2U&2uj->wu@Oki zwa#H?WYPhfmg~_)4EQW?`N&7TP7@^3x3#IPv5`(qpX8g-=JeRu#tXR!D$Ki@AoIt} zu@^zeAE`tS$&Ee7fuKiVvX|glh5-El%P#oh+$!ELwE&yq;_QP@1CCx)AFg=?)qje@ zG`M|KcdRxqAz@(}2W!K2sUgupdZOsBZiPWn6lldOtH|(AvrR5Y&OGv_5CTan{O1Gf zhu|j#VLMksA~rcQC+DFsd)qrbrF%vqY9IswF1sAO(~l+Zg6dCaOlN#dwqO5w0`jtJ zTEGs0s6?Kv##>G#WWyaZQS8XohI#}dHlW`C`~e0|J=6ts>UdMDV8|tm7gB);PgQ45 zvN*c7*)vf2hrB#FifYg1X9S!RY&Bp^5gj(4klq;m)%i8YH83pz{em3N0qGZuo&UV; z#DN#^bO%!ZGyMP#=9A6VmWp8r(zKEZsS9u`TH79DSx}v7G%Ejrc|j)@jJ4Yf5xa!ze%v`juuiXZWydt-ffg zh>;T*S)8HKs_;u;_ITh5*Mrx=iU!xYZolrj0fBg(ds)PL^1%i$5rmeGTbCGtN@{hU+2!Y}AhYFEgNFFPBb)%q;v(7T^5|Cp7u3*z8 zfq^^OFwF@F1O-5Zf262aY3=W1^k&oZ9jDDb`VB5FKTlaeB7r~?yOzZd`O8cuHuxV4 z8v$sYp7q}eLwvTJ6oM(;?YipMA%Drp#F%_)Xny;)K%vsHpxZ(gPqpe)+iwVj!&?yE z4_-LIVxdqd98iT&GM~L&5adK(1`j2)cep_RK|!cAdolPGR(mi=c3l5{R6qZb`rnT- z=RfuUityjxKr9DkDKseB|0@TwRjSPsMqt2FaFL1We{=j016J#SSMkUL1)jZ~E2gVA z|Ai^c(V5_^0XU`z_I?C)BguI?d}6>BQhz+((E>of5Z<8K3C#M}6fipaRA5~j3X&Tc z=?k-8IHx&4Dv_lq0KGsL0_4-j#{%GF^+90h|57!dRi}dR0hk$9NwCNPm;fj33IRtci~;=b`oP^>Y6ztGrLGi", + "sources": [ + "https://duckduckgo.com", + "https://duckduckgo.com/about", + "https://stackoverflow.com/questions/47745378/float-pointer-malloc-array-receiving-into-array", + "https://stackoverflow.com/questions/15445285/how-can-i-connect-to-a-tor-hidden-service-using-curl-in-php", + "https://github.com", + "https://github.com/bitcoin/bitcoin", + "https://github.com/torproject/tor", + "https://ny.gov", + "http://www.jjay.cuny.edu", + "http://jjay.cuny.edu/webapps", + "https://mail.jjay.cuny.edu/lm_auth_proxy", + "http://perdu.com", + "https://reddit.com", + "https://reddit.com/r/privacy", + "https://reddit.com/r/tor", + "https://reddit.com/r/news", + "https://torproject.org", + "http://pwnable.kr/play.php", + "https://www.sfml-dev.org/", + "https://www.sfml-dev.org/download.php", + "https://github.com/zhaopuming/awesome-d", + "http://www.cnn.com/", + "http://www.cnn.com/2017/12/10/politics/schiff-gop-discredit-mueller-sotu-cnntv/index.html", + "http://www.cnn.com/2017/12/10/politics/susan-collins-tax-reform-vote/index.html" + ] +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..361c3e8 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "website-fingerprinting", + "version": "1.0.0", + "description": "The defense for website fingerprinting attacks", + "main": "index.js", + "repository": "git@github.com:conmarap/website-fingerprinting", + "author": "Constantine Apostolou ", + "license": "MIT", + "dependencies": { + "toragent": "^0.1.1" + } +} diff --git a/packet.py b/packet.py new file mode 100644 index 0000000..798aee8 --- /dev/null +++ b/packet.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +import sys +import dpkt +import datetime + +if len(sys.argv) == 1: + print("An argument is required") + exit(1) + +f = open(sys.argv[1]) +# f = open('data/jjay-w-tor-2nd.pcap') + +pcap = dpkt.pcap.Reader(f) +open_time = 0; + +for ts, buf in pcap: + if open_time is 0: + open_time = ts + print("# The start time was on %s (%s)" % ( + datetime.datetime.fromtimestamp( + open_time + ).strftime('%Y-%m-%d %H:%M:%S'), + open_time, + )) + print("timing,bytes") + + print("%s,%s" % (round(ts - open_time, 5), len(buf),)) diff --git a/pcaps/capture.sh b/pcaps/capture.sh new file mode 100755 index 0000000..a148dbc --- /dev/null +++ b/pcaps/capture.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +if [[ $# -eq 0 ]]; then + echo "Usage: script.sh " + echo "Example: script.sh jjay.cuny.edu lynx" + exit 1 +fi + +# Create the directory if it does not already exist. +[ -d ./pcaps/$1 ] || mkdir -pv ./pcaps/$1 + +# Create the file name. +fname="$1-$(date +'%m-%d-%y_%T')" + +if [ ! -z "$2" ]; then + fname="$fname-$2" + echo "PCAPs in ./pcaps/$1: " $(ls -ltr ./pcaps/$1/ | grep "$2.pcap$" | wc -l) +else + echo "PCAPs in ./pcaps/$1: " $(ls -ltr ./pcaps/$1/ | grep ".pcap$" | wc -l) +fi + +sudo tcpdump -vv -x -X -i eth0 -A tcp and port not 22 -w ./pcaps/$1/$fname.pcap diff --git a/pcaps/mass.sh b/pcaps/mass.sh new file mode 100755 index 0000000..45995e2 --- /dev/null +++ b/pcaps/mass.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +for i in `seq 1 2`; do + echo "[$i][$(date)] Capturing..." + + # Start capturing. + ./capture.sh eff.org lynx & + + # Start a lynx session over torsocks. + torsocks timeout 20 lynx https://eff.org/ & + + sleep 21 + + # Kill the tcpdump session. + tcpdump_pid=$(ps axf | grep tcpdump | grep -v grep | awk '{ print $1 }') + + if [[ ! -z $tcpdump_pid ]]; then + echo "Killing $tcpdump_pid" + sudo kill -15 $tcpdump_pid + fi + + # If lynx is still running it needs to be terminated. + lynx_pid=$(pidof lynx) + + if [[ ! -z $lynx_pid ]]; then + kill -9 $lynx_pid + fi +done + diff --git a/predict.py b/predict.py new file mode 100755 index 0000000..8e4e926 --- /dev/null +++ b/predict.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +import os.path +import sys +import json +import utils +from sklearn.externals import joblib + + +if len(sys.argv) == 1: + print("A pcap file is needed") + sys.exit(1) + +elif os.path.exists('config.json') == False: + print "No configuration found" + sys.exit(1) + +elif os.path.exists('./classifier-nb.dmp') == False: + print "No classifier dump found; train first" + sys.exit(1) + +elif os.path.exists(sys.argv[1]) == False: + print "The input file was not found" + sys.exit(1) + +# Read the configuration and start training. +with open('config.json') as fp: + print("* Parsing configuration") + + # Load the configuration from the file. + config = json.load(fp) + + # This is where all the labels are going to live. + base_labels = [None] * len(config['pcaps']) + + # The base label starts from 1 and increments after that. + current_label = 1 + + for domain in config['pcaps']: + # Set the base label. + base_labels[current_label - 1] = domain + + # Increment the label + current_label += 1 + +print("Loading the classifier...") + +# Try to read the classifier. +classifier = joblib.load("./classifier-nb.dmp") +i = 0 +right = 0 +wrong = 0 + +# Read the pcap file. +stream = utils.read_pcap_file(sys.argv[1]) + +# Run the prediction. +prediction = classifier.predict([stream]) + +print classifier.predict_proba([stream]) + +# Print the results. +print("[{}] Prediction: {}".format(prediction[0], base_labels[prediction[0] - 1])) diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..e7338a4 --- /dev/null +++ b/utils.py @@ -0,0 +1,182 @@ +import dpkt +import socket +import random +from sklearn.neighbors import KNeighborsClassifier +from sklearn.naive_bayes import GaussianNB, BernoulliNB, MultinomialNB +from sklearn.neural_network import MLPClassifier +from sklearn.metrics import accuracy_score +from sklearn.externals import joblib + + +def empty_csv(): + """ Empties the CSV file. """ + + with open("./fingerprints.csv", 'w') as f: + f.write("") + + +def append_to_csv(domain, data): + """ Append the information to the log file. """ + + with open("./fingerprints.csv", 'a') as f: + f.write("{},{}\n".format(domain, ','.join(str(num) for num in data))) + + +def inet_to_str(inet): + """ Convert inet object to a string """ + + return socket.inet_ntop(socket.AF_INET, inet) + + +def shuffle(x, y): + """ Shuffle the datasets. """ + + for n in range(len(x) - 1): + rnd = random.randint(0, (len(x) - 1)) + x1 = x[rnd] + x2 = x[rnd - 1] + + y1 = y[rnd] + y2 = y[rnd - 1] + + x[rnd - 1] = x1 + x[rnd] = x2 + + y[rnd - 1] = y1 + y[rnd] = y2 + + return x, y + + +def read_pcap_file(file): + """ Read the pcap file and return the sizes of the packets. """ + + # Read the file. + fp = open(file) + + # Create the pcap object + pcap = dpkt.pcap.Reader(fp) + + # This is the array that will contain all the packet sizes. + sizes = [0] * 40 + i = 0 + + # Hold the addresses of the outgoing agent. + outgoing_addr = None + + outgoing_packets = 0 + incoming_packets = 0 + total_number_of_packets = 0 + + # This will contain the total size of the incoming packets. + incoming_size = 0 + + # Loop through all the packets and save the sizes. + for ts, buf in pcap: + packet_size = len(buf) + is_outgoing = True + + # Parse the Ethernet packet. + eth = dpkt.ethernet.Ethernet(buf) + + # Parse the IP packet. + ip = eth.data + + # Get the source addresses. + src = inet_to_str(ip.src) + + if total_number_of_packets == 0: + # Get the address of the outgoing agents. The target user is the + # outgoing agent, and the incoming packets are the server/website. + outgoing_addr = src + outgoing_packets += 1 + + elif src == outgoing_addr: + # Increment the outgoing packets. + outgoing_packets += 1 + + else: + # Increment the incoming packets. + incoming_packets += 1 + + # Increment the size of the incoming packets. + incoming_size += packet_size + + # This is an incoming packet. + is_outgoing = False + + if i < 40: + # Add the size to the array. + sizes[i] = packet_size if is_outgoing else -packet_size + + # Increment the index. + i += 1 + + # Increment the total amount of packets. + total_number_of_packets += 1 + + # Get the ratio. + ratio = float(incoming_packets) / (outgoing_packets if outgoing_packets != 0 else 1) + + # Print some details. + print "OUT: {}, IN: {}, TOTAL: {}, SIZE: {}, RATIO: {}".format(\ + outgoing_packets, incoming_packets, total_number_of_packets, incoming_size, ratio) + + # Reverse the array to append the other information. + sizes.reverse() + + # Add the ratio of incoming to outgoing packets. + sizes.append(ratio) + + # Add the number of incoming packets. + sizes.append(incoming_packets) + + # Add the number of outgoing packets. + sizes.append(outgoing_packets) + + # Add the number of total packets. + sizes.append(total_number_of_packets) + + # Add the total size of the incoming packets. + sizes.append(incoming_size) + + # Reverse the array again so that the sizes are in order. + sizes.reverse() + + # Finally return the sizes. + return sizes + + +def train(streams, labels): + """ This function trains the classifier with the data. """ + + # Shuffle the arrays. + streams, labels = shuffle(streams, labels) + + stream_amount = len(streams) + training_size = int(stream_amount * 0.9) + + # Get 70% of the streams for training purposes. + training_x = streams[:training_size] + training_y = labels[:training_size] + + # Get 30% of the streams for testing purposes + testing_x = streams[training_size:] + testing_y = labels[training_size:] + + print("Training size: {}".format(training_size)) + print("Testing size: {}".format(stream_amount - training_size)) + + # Initialize the classifier. + clf = KNeighborsClassifier() + + # Now lets train our KNN classifier. + clf = clf.fit(training_x, training_y) + + # Save a snapshot of this classifier. + joblib.dump(clf, "./classifier-nb.dmp", compress=9) + + # Get the prediction. + predictions = clf.predict(testing_x) + + print("Accuracy: %s%%" % (accuracy_score(testing_y, predictions) * 100,))