Skip to content

Commit abec367

Browse files
authored
Merge pull request #77 from VirusTotal/jupyter-examples
Adds Jupyter examples.
2 parents 459cf49 + 514bea1 commit abec367

File tree

3 files changed

+1070
-1
lines changed

3 files changed

+1070
-1
lines changed

.github/workflows/testing.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
2828
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
2929
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
30-
codespell --ignore-words-list="nd" --skip="*.css,*.js,*.svg"
30+
codespell --ignore-words-list="nd" --skip="*.css,*.js,*.svg,*ipynb"
3131
- name: Test with pytest
3232
run: |
3333
pytest

examples/jupyter/ransomware_report_usecases1.ipynb

Lines changed: 765 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "2de615a6",
6+
"metadata": {},
7+
"source": [
8+
"# Jupyter Notebook - Ransomware report use cases 2\n",
9+
"\n",
10+
"Copyright © 2021 Google"
11+
]
12+
},
13+
{
14+
"cell_type": "code",
15+
"execution_count": 1,
16+
"id": "f2c002ed",
17+
"metadata": {},
18+
"outputs": [],
19+
"source": [
20+
"import vt\n",
21+
"import nest_asyncio\n",
22+
"import pandas as pd"
23+
]
24+
},
25+
{
26+
"cell_type": "code",
27+
"execution_count": null,
28+
"id": "a0e8fb38",
29+
"metadata": {},
30+
"outputs": [],
31+
"source": [
32+
"#@markdown Please, insert your VT API Key*:\n",
33+
"\n",
34+
"API_KEY = '' #@param {type: \"string\"}\n",
35+
"\n",
36+
"#@markdown **The API key should have Premium permissions, otherwise some of the use cases might not provide the expected results.*\n",
37+
"\n",
38+
"#@markdown "
39+
]
40+
},
41+
{
42+
"cell_type": "code",
43+
"execution_count": 2,
44+
"id": "6a43b2f8",
45+
"metadata": {},
46+
"outputs": [],
47+
"source": [
48+
"nest_asyncio.apply()"
49+
]
50+
},
51+
{
52+
"cell_type": "markdown",
53+
"id": "81e7e852",
54+
"metadata": {},
55+
"source": [
56+
"# 1. Collecting hashes"
57+
]
58+
},
59+
{
60+
"cell_type": "code",
61+
"execution_count": 23,
62+
"id": "dd8258f0",
63+
"metadata": {},
64+
"outputs": [
65+
{
66+
"name": "stdout",
67+
"output_type": "stream",
68+
"text": [
69+
"9426 hashes have been written to the file hashes.log\n",
70+
"\n"
71+
]
72+
}
73+
],
74+
"source": [
75+
"nh = 0\n",
76+
"with vt.Client(API_KEY) as client:\n",
77+
" it = client.iterator('/intelligence/search',\n",
78+
" params={'query': 'engines:ryuk fs:2021-01-01+ (type:peexe or type:pedll) p:10+'})\n",
79+
" with open('hashes.log','w') as f:\n",
80+
" for obj in it:\n",
81+
" if obj.id:\n",
82+
" f.write(f'{obj.id}\\n')\n",
83+
" nh += 1\n",
84+
" f.close()\n",
85+
"print(f'{nh} hashes have been written to the file hashes.log\\n')"
86+
]
87+
},
88+
{
89+
"cell_type": "markdown",
90+
"id": "af491db1",
91+
"metadata": {},
92+
"source": [
93+
"# 2. Malicious contacted IOCs"
94+
]
95+
},
96+
{
97+
"cell_type": "code",
98+
"execution_count": 24,
99+
"id": "91f52171",
100+
"metadata": {},
101+
"outputs": [],
102+
"source": [
103+
"def get_malicious_IPs(file_hash):\n",
104+
" contacted_IPs = set()\n",
105+
" for ip in client.iterator('/files/{}/contacted_ips', file_hash, limit=20):\n",
106+
" stats = ip.get('last_analysis_stats')\n",
107+
" if stats and stats['malicious'] >= min_positives:\n",
108+
" contacted_IPs.add(ip.id)\n",
109+
" return contacted_IPs\n",
110+
"\n",
111+
"def get_malicious_Domains(file_hash):\n",
112+
" contacted_domains = set()\n",
113+
" for domain in client.iterator('/files/{}/contacted_domains', file_hash, limit=20):\n",
114+
" stats = domain.get('last_analysis_stats')\n",
115+
" if stats and stats['malicious'] >= min_positives:\n",
116+
" contacted_domains.add(domain.id)\n",
117+
" return contacted_domains"
118+
]
119+
},
120+
{
121+
"cell_type": "code",
122+
"execution_count": 25,
123+
"id": "3fe5a2cb",
124+
"metadata": {},
125+
"outputs": [
126+
{
127+
"name": "stdout",
128+
"output_type": "stream",
129+
"text": [
130+
"29 IOCs have been written to the file iocs.log\n",
131+
"\n"
132+
]
133+
}
134+
],
135+
"source": [
136+
"malIOCs = set()\n",
137+
"min_positives = 5 # Minimun number of positives for every IOC\n",
138+
"nIOCs = 0\n",
139+
"\n",
140+
"with vt.Client(API_KEY) as client:\n",
141+
" it = client.iterator('/intelligence/search',\n",
142+
" params={'query': 'engines:babuk fs:2021-07-01+ (have:contacted_domains or have:contacted_ips)'})\n",
143+
" for obj in it:\n",
144+
" ips = get_malicious_IPs(obj.id)\n",
145+
" domains = get_malicious_Domains(obj.id)\n",
146+
" malIOCs = malIOCs | ips | domains\n",
147+
"\n",
148+
"with open('iocs.log','w') as f:\n",
149+
" for ioc in malIOCs:\n",
150+
" f.write(f'{ioc}\\n')\n",
151+
" nIOCs += 1\n",
152+
" \n",
153+
"print(f'{nIOCs} IOCs have been written to the file iocs.log\\n') \n",
154+
"f.close()"
155+
]
156+
},
157+
{
158+
"cell_type": "markdown",
159+
"id": "75eb0fbb",
160+
"metadata": {},
161+
"source": [
162+
"# 3. Searching for a text in domains and URLs"
163+
]
164+
},
165+
{
166+
"cell_type": "code",
167+
"execution_count": 3,
168+
"id": "a621ab7d",
169+
"metadata": {},
170+
"outputs": [],
171+
"source": [
172+
"def search_domains(file_hash, text):\n",
173+
" domains = set()\n",
174+
" for domain in client.iterator('/files/{}/embedded_domains', file_hash, limit=20):\n",
175+
" if text in domain.id:\n",
176+
" domains.add(domain.id)\n",
177+
" for domain in client.iterator('/files/{}/itw_domains', file_hash, limit=20):\n",
178+
" if text in domain.id:\n",
179+
" domains.add(domain.id) \n",
180+
" return domains\n",
181+
"\n",
182+
"def search_urls(file_hash, text):\n",
183+
" urls = set()\n",
184+
" for url in client.iterator('/files/{}/embedded_urls', file_hash, limit=20):\n",
185+
" if text in url.id:\n",
186+
" urls.add(url.id)\n",
187+
" for url in client.iterator('/files/{}/itw_urls', file_hash, limit=20):\n",
188+
" if text in url.id:\n",
189+
" urls.add(url.id)\n",
190+
" return urls"
191+
]
192+
},
193+
{
194+
"cell_type": "code",
195+
"execution_count": 13,
196+
"id": "627139ad",
197+
"metadata": {},
198+
"outputs": [
199+
{
200+
"name": "stdout",
201+
"output_type": "stream",
202+
"text": [
203+
"** Results found for file hash: 1a5f649438646bfe909ac1e08bfe37f969e21b7900933d51ad2fe0c5c549a79b (pedll)\n",
204+
"\n",
205+
" - www.google.fr\n",
206+
"\n",
207+
"** Results found for file hash: af48fb4200cff418d513fe0ca841a8adb8699b266266fcf46ef44e460361cff0 (peexe)\n",
208+
"\n",
209+
" - www.google-analytics.com\n",
210+
"\n",
211+
"** Results found for file hash: 062227eaca57abaf97dd2c6d5f198fdd0d11b15cfd45eef0f0f0217d5c70aa06 (android)\n",
212+
"\n",
213+
" - play.google.com\n",
214+
"\n",
215+
" - googleads.g.doubleclick.net\n",
216+
"\n",
217+
" - pagead2.googlesyndication.com\n",
218+
"\n",
219+
" - plus.google.com\n",
220+
"\n",
221+
" - www.google.com\n",
222+
"\n",
223+
" - support.google.com\n",
224+
"\n",
225+
"** Results found for file hash: 569a267a4282bc694a8b39502b4e51bd3b78d449e075f4480c51eba71433b5dd (peexe)\n",
226+
"\n",
227+
" - www.google.de\n",
228+
"\n",
229+
"** Results found for file hash: 87ceec489fbfc70c2d935dc0717dba6f7d7147d06be08c661e05f7c83c3b67f0 (android)\n",
230+
"\n",
231+
" - play.google.com\n",
232+
"\n",
233+
" - googleads.g.doubleclick.net\n",
234+
"\n",
235+
" - pagead2.googlesyndication.com\n",
236+
"\n",
237+
" - plus.google.com\n",
238+
"\n",
239+
" - www.google.com\n",
240+
"\n",
241+
" - support.google.com\n",
242+
"\n",
243+
"** Results found for file hash: d419b2e7a6e9252b1cb3b86a6f8f107206c31cc666a74af97738f46b650ed4c5 (peexe)\n",
244+
"\n",
245+
" - www.googleadservices.com\n",
246+
"\n",
247+
" - googleads.g.doubleclick.net\n",
248+
"\n",
249+
" - www.googletagmanager.com\n",
250+
"\n",
251+
"** Results found for file hash: bcd862cc4d790ff73de8f573b3719f2c857bf0d03efa311e1f9cbf5cfa05d9ed (peexe)\n",
252+
"\n",
253+
" - partner.googleadservices.com\n",
254+
"\n",
255+
"** Results found for file hash: 147e54a51effe8a0cb42691e0e967752698b4db5883532f88daed9ba4f8b69a7 (peexe)\n",
256+
"\n",
257+
" - ssl.google-analytics.com\n",
258+
"\n",
259+
"** Results found for file hash: ac8eac1c5644ea1563783e7bdccaddbfaa6146fdcd610a7acc852fe76420352a (peexe)\n",
260+
"\n",
261+
" - partner.googleadservices.com\n",
262+
"\n"
263+
]
264+
}
265+
],
266+
"source": [
267+
"stxt=\"google\" # Write here any text you want to search for\n",
268+
"query_string = 'engines:cerber fs:2021-06-01+ (embedded_domains: %s OR embedded_urls:%s OR itw: %s)' % (stxt, stxt, stxt)\n",
269+
"\n",
270+
"with vt.Client(API_KEY) as client:\n",
271+
" it = client.iterator('/intelligence/search', params={'query': query_string})\n",
272+
"\n",
273+
" for obj in it:\n",
274+
" results = search_domains(obj.id, search_text) | search_urls(obj.id, search_text)\n",
275+
" \n",
276+
" if results:\n",
277+
" print(f'** Results found for file hash: {obj.id} (%s)\\n' %(obj.type_tag) )\n",
278+
" for result in results:\n",
279+
" print(f' - {result}\\n')"
280+
]
281+
}
282+
],
283+
"metadata": {
284+
"kernelspec": {
285+
"display_name": "Python 3 (ipykernel)",
286+
"language": "python",
287+
"name": "python3"
288+
},
289+
"language_info": {
290+
"codemirror_mode": {
291+
"name": "ipython",
292+
"version": 3
293+
},
294+
"file_extension": ".py",
295+
"mimetype": "text/x-python",
296+
"name": "python",
297+
"nbconvert_exporter": "python",
298+
"pygments_lexer": "ipython3",
299+
"version": "3.8.1"
300+
}
301+
},
302+
"nbformat": 4,
303+
"nbformat_minor": 5
304+
}

0 commit comments

Comments
 (0)