diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4bce00c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+__pycache__
+config.py
+downloads
+vectors
+autotest_*.txt
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..376610c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+1. `sudo pip3 install -r requirements.txt`
+2. `echo "APP_KEY = '...'" > config.py`
+3. `python3 main.py`
+4. `help`
diff --git a/exploit.py b/exploit.py
new file mode 100644
index 0000000..e69de29
diff --git a/help/main b/help/main
new file mode 100644
index 0000000..7c38f69
--- /dev/null
+++ b/help/main
@@ -0,0 +1,30 @@
+Программа для сбора информации о цели из vk.com с использованием всех доступных
+возможностей.
+
+Первый запуск:
+1. Создать standalone приложение
+2. Прописать его ключ в config.py
+
+Этапы работы с программой:
+1. Добавление доступных векторов
+ 1. Получчение ссылки: vector add
+ 2. Переход по ссылке с аккаунта-вектора (со всех доступных аккаунтов)
+ 3. Ввод результирующей ссылки в программу: vector add
+2. Добавление целей: target add
+3. Просмотр списка целей: target list
+4. Эксплуатация цели с целью получения вектора (попытка взлома)
+ 1. Список эксплоитов: exploit list
+ 2. Информация об эксплоите: exploit info
+ 3. Выбор эксплоита: exploit use
+ 4. Установка требуемых параметров: exploit set
+ 5. Запуск: exploit start
+5. Подбор векторов для цели: vector get
+6. Просмотр векторов: vector list
+7. Применение полезной нагрузки
+ 1. Список нагрузок: payload list
+ 2. Информация о нагрузке: payload info
+ 3. Выбор нагрузки: payload use
+ 4. Установка требуемых параметров: payload set
+ 5. Запуск: payload start
+8. Сохранение результатов: save
+9. Выход: exit
diff --git a/help/payload b/help/payload
new file mode 100644
index 0000000..18c3edc
--- /dev/null
+++ b/help/payload
@@ -0,0 +1,13 @@
+payload list
+ Выводит список доступных нагрузок
+payload info
+payload info
+ Выводит информацию о выбранной нагрузке.
+payload use
+ Выбирает нагрузку для использования в дальнейшей атаке.
+ Можно и нужно выбрать только одну нагрузку.
+payload set
+payload set ...
+ Устанавливает значение переменной, используемой в нагрузке
+payload start
+ Запускает нагрузку.
diff --git a/help/payload info b/help/payload info
new file mode 100644
index 0000000..3bf77e0
--- /dev/null
+++ b/help/payload info
@@ -0,0 +1,4 @@
+payload info
+payload info
+
+Выводит информацию о выбранной нагрузке.
diff --git a/help/payload list b/help/payload list
new file mode 100644
index 0000000..0e306d4
--- /dev/null
+++ b/help/payload list
@@ -0,0 +1,3 @@
+payload list
+
+Выводит список доступных нагрузок
diff --git a/help/payload set b/help/payload set
new file mode 100644
index 0000000..18e501b
--- /dev/null
+++ b/help/payload set
@@ -0,0 +1,4 @@
+payload set
+payload set ...
+
+Устанавливает значение переменной, используемой в нагрузке
diff --git a/help/payload start b/help/payload start
new file mode 100644
index 0000000..d0956fe
--- /dev/null
+++ b/help/payload start
@@ -0,0 +1,3 @@
+payload start
+
+Запускает нагрузку.
diff --git a/help/payload use b/help/payload use
new file mode 100644
index 0000000..4dd5e4c
--- /dev/null
+++ b/help/payload use
@@ -0,0 +1,4 @@
+payload use
+
+Выбирает нагрузку для использования в дальнейшей атаке.
+Можно и нужно выбрать только одну нагрузку.
diff --git a/help/target add b/help/target add
new file mode 100644
index 0000000..be697d5
--- /dev/null
+++ b/help/target add
@@ -0,0 +1,4 @@
+target add
+target add ...
+
+Добавляет пользователя в список целей
diff --git a/help/target delete b/help/target delete
new file mode 100644
index 0000000..dbfd22c
--- /dev/null
+++ b/help/target delete
@@ -0,0 +1,4 @@
+target add
+target add ...
+
+удаляет пользователя из списка целей
diff --git a/help/target list b/help/target list
new file mode 100644
index 0000000..a1ac5fc
--- /dev/null
+++ b/help/target list
@@ -0,0 +1,3 @@
+target list
+
+Выводит список целей
diff --git a/help/vector add b/help/vector add
new file mode 100644
index 0000000..431629f
--- /dev/null
+++ b/help/vector add
@@ -0,0 +1,14 @@
+vector add
+vector add
+vector add ...
+
+При вводе команды без параметров программа выдаст ссылку, по которой необходимо
+перейти. На данной странице нужно нажать "разрешить", скопировать ссылку
+итоговой страницы и ввести команду на добавление вектора уже с данной ссылкой:
+vector add
+
+Можно через пробел указывать несколько ссылок сразу:
+vector add ...
+
+Все векторы при выходе из программы сохраняются в файле "vectors" и заново
+инициализируются при каждом запуске программы.
diff --git a/help/vector delete b/help/vector delete
new file mode 100644
index 0000000..2f975ff
--- /dev/null
+++ b/help/vector delete
@@ -0,0 +1,4 @@
+vector delete
+vector delete ...
+
+Удаляет источник из списка доступных.
diff --git a/help/vector get b/help/vector get
new file mode 100644
index 0000000..0167bda
--- /dev/null
+++ b/help/vector get
@@ -0,0 +1,12 @@
+vector get
+vector get
+vector get ...
+
+Используется для получения векторов атаки для заданных целей. Для этого из
+списка доступных векторов для каждой цели выбирается наиболее близкий вектор.
+
+Возможные уровни векторов:
+1. Источник и цель совпадают
+2. Цель находится в списке друзей источника
+3. У источника и цели есть общие друзья
+4. Выбран случайный источник из списка доступных
diff --git a/help/vector list b/help/vector list
new file mode 100644
index 0000000..0b19017
--- /dev/null
+++ b/help/vector list
@@ -0,0 +1,3 @@
+vector list
+
+Выводит список источников и исписок векторов
diff --git a/inputer.py b/inputer.py
new file mode 100644
index 0000000..2496973
--- /dev/null
+++ b/inputer.py
@@ -0,0 +1,49 @@
+import readline
+
+class MyCompleter(object): # Custom completer
+
+ def __init__(self, options):
+ self.options = sorted(options)
+
+ def complete(self, text, state):
+ if state == 0: # on first trigger, build possible matches
+ if text: # cache matches (entries that start with entered text)
+ self.matches = [s for s in self.options
+ if s and s.startswith(text)]
+ else: # no text entered, all matches possible
+ self.matches = self.options[:]
+
+ # return match indexed by state
+ try:
+ return self.matches[state]
+ except IndexError:
+ return None
+
+keywords = [
+ 'vector ',
+ 'payload ',
+ 'target ',
+ 'add ',
+ 'get ',
+ 'list ',
+ 'delete ',
+ 'info ',
+ 'use ',
+ 'set ',
+ 'start ',
+ 'help '
+ ]
+from os import listdir
+pll = listdir('payloads')
+pll = [i[:-3] for i in pll if i.endswith('.py')]
+keywords.extend(pll)
+
+completer = MyCompleter(keywords)
+readline.set_completer(completer.complete)
+readline.parse_and_bind('tab: complete')
+
+if __name__ == '__main__':
+ while 1:
+ i = input("Input: ")
+ print("You entered", i)
+ readline.add_history(i)
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..cb34fed
--- /dev/null
+++ b/main.py
@@ -0,0 +1,158 @@
+#!/usr/bin/python3
+
+result = []
+def myprint(*argv, sep=' ', end='\n', error=False):
+ if error:
+ print('\x1B[31m[!]', end=' ')
+ else:
+ text = sep.join([str(i) for i in argv])+end
+ result.append(text)
+ print(*argv, sep=sep, end='\x1B[0m'+end)
+
+
+from time import sleep
+def vk_request(vk, method, params):
+ for i in (1,2,3,0):
+ try:
+ rez = vk(method, **params)
+ except Exception as e:
+ exc = e
+ sleep(i)
+ else:
+ return rez
+ if not str(exc).startswith('15.'): #if not "user deactivated"
+ myprint(exc, error=True)
+ return False
+
+
+import readline
+import inputer
+
+import vkehelp
+import target
+import vector
+import exploit
+import payload
+
+from sys import argv
+if len(argv)>1:
+ fname = ' '.join(argv[1:])
+ try:
+ f = open(fname)
+ except:
+ myprint('Файл', fname, 'не найден!', error=True)
+ queue = []
+ else:
+ queue = f.readlines()
+else:
+ queue = []
+
+
+
+def main(query):
+ if query[0] == 'help':
+ if len(query) == 1:
+ query.append('main')
+ vkehelp.fmain(query[1:])
+ elif query[0] == 'exit':
+ print('Exit...')
+ exit()
+ elif len(query) == 1:
+ vkehelp.fmain(query)
+
+ elif query[0] == 'auto':
+ try:
+ f = open(' '.join(query[1:]))
+ except:
+ myprint('Файл не найден!', error=True)
+ else:
+ queue.extend(f.readlines())
+
+ elif query[0] == 'vector':
+ if query[1] == 'add':
+ if len(query) == 2:
+ vector.fadd(False)
+ else:
+ vector.fadd(query[2:])
+ elif query[1] == 'list':
+ vector.flist()
+ elif query[1] == 'get':
+ if len(query) == 2:
+ vector.fget(list(target.targets))
+ else:
+ vector.fget(query[2:])
+ elif query[1] == 'delete':
+ if len(query) == 2:
+ vector.fdelete(list(vector.vectors))
+ else:
+ vector.fdelete(query[2:])
+ else:
+ vkehelp.fmain(query)
+
+ elif query[0] == 'target':
+ if query[1] == 'list':
+ target.flist()
+ elif query[1] == 'delete':
+ if len(query) == 2:
+ target.fdelete(list(target.targets))
+ else:
+ target.fdelete(query[2:])
+ elif len(query) == 2:
+ vkehelp.fmain(query)
+ elif query[1] == 'add':
+ target.fadd(query[2:])
+ else:
+ vkehelp.fmain([query[0]])
+
+ elif query[0] == 'payload':
+ if query[1] == 'list':
+ payload.flist()
+ elif query[1] == 'start':
+ payload.fstart()
+ elif len(query) == 2:
+ vkehelp.fmain(query)
+ elif query[1] == 'info':
+ payload.finfo(query[2:])
+ elif query[1] == 'use':
+ payload.fuse(query[2:])
+ elif query[1] == 'set':
+ payload.fset(*query[2:])
+ else:
+ vkehelp.fmain([query[0]])
+
+ elif query[0] == 'save':
+ fname = ' '.join(query[1:])
+ try:
+ f = open(fname, 'w')
+ except Exception as e:
+ myprint(e, error=True)
+ else:
+ f.write(''.join(result))
+ f.close()
+ print('Данные успешно сохранены!')
+ else:
+ myprint('Команда не найдена!', error=True)
+
+if __name__ == '__main__':
+ try:
+ while 1:
+ if queue:
+ query = queue.pop(0).replace('\n', '')
+ print('\x1B[32m>', query, '\x1B[0m')
+ else:
+ query = input('\x1B[32m> ')
+ print('\x1B[0m', end='')
+ if not query:
+ continue
+ readline.add_history(query)
+ query = query.split()
+ main(query)
+ except (EOFError, KeyboardInterrupt):
+ print('\x1B[0m\nExit...')
+ #except Exception as e:
+ # myprint(e, error=True)
+ finally:
+ if vector.utokens:
+ from pickle import dump
+ with open('vectors', 'wb') as f:
+ dump(vector.utokens, f)
diff --git a/methods.py b/methods.py
new file mode 100644
index 0000000..708dfd9
--- /dev/null
+++ b/methods.py
@@ -0,0 +1,47 @@
+from __main__ import vk_request, myprint
+import functools
+from random import choice
+
+from target import targets, vectors
+from vector import vectors as vectors_info
+def get_vk(uid=False):
+ if uid:
+ if uid in vectors_info:
+ return vectors_info[uid]
+ if uid in vectors:
+ vector_id, lvl = vectors[uid]
+ return vectors_info[vector_id]
+ return choice(list(vectors_info.values()))
+
+@functools.lru_cache(maxsize=300)
+def friends(uid, vk=False):
+ if not vk:
+ vk = get_vk(uid)
+ rez = vk_request(vk, 'friends.get', {'user_id': uid})
+ if rez:
+ return set(rez['items'])
+ else:
+ return set()
+
+
+@functools.lru_cache(maxsize=100)
+def names(uid, vk=False):
+ if not vk:
+ try:
+ vk = get_vk(uid)
+ except IndexError:
+ myprint('Прежде всего необходимо добавить векторы!')
+ return ''
+ if int(uid) > 0:
+ rez = vk_request(vk, 'users.get', {'user_ids': uid})
+ if rez:
+ return rez[0]['first_name']+' '+rez[0]['last_name']
+ else:
+ return ''
+ else:
+ rez = vk_request(vk, 'groups.getById', {'group_ids': str(uid)[1:]})
+ if rez:
+ return rez[0]['name']
+ else:
+ return ''
+
diff --git a/payload.py b/payload.py
new file mode 100644
index 0000000..4f8c576
--- /dev/null
+++ b/payload.py
@@ -0,0 +1,80 @@
+from __main__ import myprint
+import importlib
+
+from inputer import pll as payloadlist
+payload = False
+
+def flist():
+ for pld in payloadlist:
+ print(pld)
+
+def finfo(query=False):
+ if query:
+ query = query[0]
+ if query not in payloadlist:
+ myprint('Нагрузка не найдена!', error=True)
+ return
+ module = importlib.import_module('payloads.'+query)
+ print('-'*80)
+ print(module.__doc__)
+ print('-'*80)
+ else:
+ print('-'*80)
+ print(payload.__doc__)
+ print('-'*80)
+ fshow()
+
+def fshow():
+ if not payload:
+ myprint('Не выбрана нагрузка!', error=True)
+ return
+ if 'varlist' not in payload.__dir__():
+ print('Нагрузка не содержит переменных!')
+ return
+
+ kw = max([len(str(i)) for i in payload.varlist.keys()])
+ vw = max([len(str(i)) for i in payload.varlist.values()])
+ print('┌', '─'*kw, '┬', '─'*vw, '┐', sep='')
+ for k, v in payload.varlist.items():
+ print(('│{:'+str(kw)+'}│{:'+str(vw)+'}│{}').format(k, v, payload.descr[k]))
+ print('└', '─'*kw, '┴', '─'*vw, '┘', sep='')
+
+def fuse(query):
+ global payload
+ query = query[0]
+ if query not in payloadlist:
+ myprint('Нагрузка не найдена!', error=True)
+ return
+ payload = importlib.import_module('payloads.'+query)
+
+ print('Нагрузка успешно подключена')
+ print(payload.__doc__)
+ fshow()
+
+def fset(var, *vals):
+ if not payload:
+ myprint('Не выбрана нагрузка!', error=True)
+ return
+ if var not in payload.varlist:
+ myprint('Переменная не найдена!', error=True)
+ return
+
+ if len(vals) == 1:
+ if vals[0].isdigit():
+ payload.varlist[var] = int(vals[0])
+ else:
+ payload.varlist[var] = vals[0]
+ else:
+ payload.varlist[var] = vals
+ print('Переменная', var, 'успешно установлена.')
+
+def fstart():
+ if not payload:
+ myprint('Не выбрана нагрузка!', error=True)
+ return
+ try:
+ payload.start()
+ except KeyboardInterrupt:
+ myprint('Payload has stoped!', error=True)
+ #except Exception as e:
+ # myprint(e, error=True)
diff --git a/payloads/clearmessages.py b/payloads/clearmessages.py
new file mode 100644
index 0000000..3b5538d
--- /dev/null
+++ b/payloads/clearmessages.py
@@ -0,0 +1,50 @@
+"""Удаляет те сообщения, которые содержат хотя бы одно слово из списка"""
+
+varlist = {
+ 'words': ['оружие', 'наркотики', 'героин', 'суицид'],
+ 'only_targets': 0,
+ 'first_form': 0
+ }
+descr = {
+ 'var1': 'descr1',
+ 'var2': 'descr2'
+ }
+
+def start():
+ from __main__ import myprint, vk_request
+ from target import targets, vectors
+ from vector import vectors as vectors_info
+ import methods
+
+ if varlist['first_form']:
+ import pymorphy2
+
+
+ if type(varlist['words']) is str:
+ varlist['words'] = {varlist['words']}
+ else:
+ varlist['words'] = set(varlist['words'])
+
+ for target_id in targets:
+ vector_id, lvl = vectors[target_id]
+ vector_obj = vectors_info[vector_id]
+
+ msgs = #!
+ if not msgs:
+ continue
+ for msg in msgs:
+ if varlist['first_form']:
+ words = []
+ for word in msg.split():
+ words.extend(morph.normal_forms(word))
+ else:
+ words = msg.lower().split()
+ words = set(words)
+
+ if words & varlist['words']:
+ if len(msg) > 80:
+ print(msg[:79]+'…')
+ else:
+ print(msg)
+
+ #del
diff --git a/payloads/comments.py b/payloads/comments.py
new file mode 100644
index 0000000..2b02b26
--- /dev/null
+++ b/payloads/comments.py
@@ -0,0 +1,81 @@
+"""Модуль для поиска комментариев пользователя в группах из списка"""
+
+varlist = {
+ 'links': ' '
+ }
+descr = {
+ 'links': 'Если не указано, ищет в группах пользователя'
+ }
+
+
+def start():
+ from __main__ import myprint, vk_request
+ from target import targets, vectors
+ from vector import vectors as vectors_info
+ import methods
+
+ junk = ('http://', 'https://', 'vk.com/', 'group', 'id', '/')
+ if type(varlist['links']) is str:
+ varlist['links'] = varlist['links'].strip()
+ elif type(varlist['links']) is tuple:
+ varlist['links'] = list(varlist['links'])
+ if varlist['links']:
+ if not type(varlist['links']) is list:
+ varlist['links'] = [varlist['links']]
+ for i, link in enumerate(varlist['links']):
+ for j in junk:
+ link = link.replace(j, '')
+ if link.replace('-', '').isdigit():
+ varlist['links'][i] = link
+ else:
+ myprint('Неверный формат:', varlist['links'][i], error=True)
+ varlist['links'][i] = False
+
+ groups = False
+ if varlist['links']:
+ groups = varlist['links']
+ else:
+ #сообщества юзера
+ groups = set()
+ for target_id in targets:
+ vector_id, lvl = vectors[target_id]
+ vector_obj = vectors_info[vector_id]
+ this_groups = vk_request(vector_obj, 'groups.get',
+ {'user_id': target_id, 'count': 1000})
+ if this_groups:
+ this_groups = [-1*int(group) for group in this_groups['items']]
+ groups.update(set(this_groups))
+ if not groups:
+ myprint(' Невозможно получить список групп!', error=True)
+ return
+
+ for group in groups:
+ myprint('\n\n{} ({})'.format(methods.names(group), group))
+ posts = vk_request(methods.get_vk(), 'wall.get',
+ {'owner_id': group, 'count': 100})
+ if not posts:
+ continue
+
+ for post in posts['items']:
+ if post['from_id'] in targets:
+ if len(post['text']) > 78:
+ post['text'] = post['text'][:77]+'…'
+ myprint('\n {} ({})'.format(methods.names(post['from_id']), post['from_id']))
+ myprint(' ', post['text'])
+ myprint(' https://vk.com/wall-', group,'_', post['id'], sep='')
+
+ comments = vk_request(methods.get_vk(), 'wall.getComments', {
+ 'owner_id': group,
+ 'post_id': post['id'],
+ 'count': 100
+ })
+ if not comments:
+ continue
+
+ for comment in comments['items']:
+ if comment['from_id'] in targets:
+ if len(comment['text']) > 78:
+ comment['text'] = comment['text'][:77]+'…'
+ myprint('\n {} ({})'.format(methods.names(comment['from_id']), comment['from_id']))
+ myprint(' ', comment['text'])
+ myprint(' https://vk.com/wall', group,'_', post['id'], '?reply=', comment['id'], sep='')
diff --git a/payloads/downloader.py b/payloads/downloader.py
new file mode 100644
index 0000000..27ec2b3
--- /dev/null
+++ b/payloads/downloader.py
@@ -0,0 +1,197 @@
+"""Модуль для загрузки прикреплений из постов."""
+
+varlist = {
+ 'links': '',
+ 'dir': 'downloads'
+ }
+descr = {
+ 'links': 'ссылки на записи',
+ 'dir': 'директория, в которую будут сохранены скачанные файлы'
+ }
+
+def start():
+ from __main__ import myprint, vk_request
+ from target import targets, vectors
+ from vector import vectors as vectors_info
+ import methods
+
+ from time import sleep
+ import re
+ from grab import Grab
+ g = Grab()
+
+
+ def download(name, link):
+ myprint('Download', name+'...')
+ g.setup(log_file=varlist['dir']+name, timeout=False)
+ g.go(link)
+ g.setup(log_file=False, timeout=14997)
+
+
+ def get_photo(attach):
+ size = False
+ for allowed_size in photo_sizes:
+ if 'photo_'+allowed_size in attach:
+ size = allowed_size
+ break
+ if size:
+ download(str(attach['owner_id'])+'_'+str(attach['id'])+'.jpg', attach['photo_'+size])
+
+
+ from urllib.parse import quote
+ def get_video(name, link):
+ for i in (1, 2, 3):
+ try:
+ g.go(link)
+ except Exception as e:
+ myprint(e, error=True)
+ sleep(i)
+ else:
+ break
+ else:
+ myprint('Не удалось получить видео!', error=True)
+ return
+
+ if link.startswith('https://vk.com/'):
+ flink = False
+ page = g.response.body.decode('utf-8')
+ vk_rex = r'https\:\/\/[a-z0-9\-]+\.vk[a-z0-9\/\-\.]+\.{}'
+ for i in ('720\.mp4', '480\.mp4', '360\.mp4', 'vk.flv'):
+ try:
+ flink = re.search(vk_rex.format(i), page).group()
+ except Exception as e:
+ myprint(e, error=True)
+ else:
+ break
+ else:
+ myprint('Не удалось найти ссылку для загрузки видео с vk!', error=True)
+ return
+ download(name, flink)
+ elif link.startswith('https://coub.com/'):
+ page = g.response.body.decode('utf-8')
+ try:
+ page = page[page.find('"html5":{"video":'):page.find(',"iphone":{"url"')]
+ page = page[page.find('"url":"')+7:]
+ video = page[:page.find('"')]
+ page = page[page.find('"audio"'):]
+ page = page[page.find('"url":"')+7:]
+ audio = page[:page.find('"')]
+ except Exception as e:
+ myprint('Ошибка при парсинге страницы coub!', error=True)
+ myprint(e, error=True)
+ return
+ download(name+'.mp4', video)
+ download(name+'.mp3', audio)
+ elif link.startswith('https://www.youtube.com/'):
+ try:
+ g.go('http://keepvid.com/?url='+quote(link))
+ page = g.response.body.decode('utf-8')
+ except Exception as e:
+ myprint('Ошибка при переходе на keepvid.com!', error=True)
+ myprint(e, error=True)
+ return
+ page = page[page.find('id="info"'):]
+ for size in ('720p', '480p', '360p'):
+ if size in page:
+ page = page[:page.find(size)]
+ page = page[page.rfind('http'):]
+ link = page[:page.find('"')]
+ break
+ else:
+ myprint('Не удалось найти ссылку для загрузки видео с youtube!', error=True)
+ return
+ download(name, link)
+ else:
+ myprint('Невозможно скачать видео! Неподдерживаемый тип.', error=True)
+ myprint(link)
+
+
+ from boilerpipe.extract import Extractor
+ def get_link(name, link):
+ try:
+ g.go(link)
+ except Exception as e:
+ myprint('Ошибка при переходе по ссылке!', error=True)
+ myprint(e, error=True)
+ return
+ try:
+ g.response.detect_charset()
+ rez = g.response.body.decode(g.response.charset)
+ except Exception as e:
+ myprint('Ошибка при декодировании страницы!', error=True)
+ myprint(e, error=True)
+ return
+ try:
+ extractor = Extractor(extractor='ArticleExtractor', html=rez)
+ text = extractor.getText()
+ except Exception as e:
+ myprint('Ошибка при извлечении текста!', error=True)
+ myprint(e, error=True)
+ return
+ open(varlist['dir']+name+'.html', 'w').write(rez)
+ open(varlist['dir']+name+'.txt', 'w').write(text)
+
+
+ photo_sizes = ('1280', '807', '604')
+
+ if not varlist['links']:
+ myprint('Не заданы ссылки для скачивания', error=True)
+ return
+
+ if varlist['dir'][-1] != '/':
+ varlist['dir'] = varlist['dir'] + '/'
+ if type(varlist['links']) is str:
+ varlist['links'] = [varlist['links']]
+
+ links = []
+ for link in varlist['links']:
+ if '/wall' not in link or '_' not in link:
+ myprint('Неверный формат ссылки:', link, error=True)
+ continue
+ link = link[link.find('wall')+4:]
+ links.append(link)
+
+ posts = vk_request(methods.get_vk(), 'wall.getById', {'posts': ','.join(links)})
+ if posts:
+ #for post in posts['items']:
+ for post in posts:
+ if len(post['text']) > 5:
+ myprint('\n'+(post['text'].replace('\n', ''))+'\n')
+ open('{}description.{}_{}.txt'.format(varlist['dir'], post['owner_id'], post['id']), 'w').write(post['text'])
+ if 'attachments' not in post:
+ myprint('Нет прикреплений!', error=True)
+ continue
+ for attach in post['attachments']:
+ #if attach['type'] in attach and len(attach.keys()) == 2:
+ attach[attach['type']]['type'] = attach['type']
+ attach = attach[attach['type']]
+
+ if attach['type'] == 'photo':
+ get_photo(attach)
+ elif attach['type'] == 'posted_photo':
+ download(str(attach['owner_id'])+'_'+str(attach['id'])+'.jpg', attach['photo_604'])
+ elif attach['type'] == 'video':
+ video = vk_request(methods.get_vk(), 'video.get', {
+ 'videos': str(attach['owner_id'])+'_'+str(attach['id'])})
+ if video and 'player' in video['items'][0]:
+ get_video(attach['title'], video['items'][0]['player'])
+ else:
+ myprint('Видео', attach['title'], 'недоступно для скачивания...', error=True)
+ elif attach['type'] == 'audio':
+ download(attach['artist']+' - '+attach['title']+'.mp3', attach['url'])
+ elif attach['type'] == 'doc':
+ download(attach['title']+'.'+attach['ext'], attach['url'])
+ elif attach['type'] == 'link':
+ myprint('Сохранение', attach['title']+'...')
+ get_link(attach['title'], attach['url'])
+ elif attach['type'] == 'note':
+ open(varlist['dir']+attach['title']+'.txt', 'w').write(attach['text'])
+ elif attach['type'] == 'page':
+ get_link(attach['view_url'], attach['url'])
+ elif attach['type'] == 'album':
+ photos = vk_request(methods.get_vk(), 'photos.get', {'album_id': attach['id']})
+ if photos:
+ for photo in photos['items']:
+ get_photo(photo)
+ else:
+ myprint('Неподдерживаемый тип:', attach['type'], error=True)
diff --git a/payloads/hiddenfriends.py b/payloads/hiddenfriends.py
new file mode 100644
index 0000000..27e641c
--- /dev/null
+++ b/payloads/hiddenfriends.py
@@ -0,0 +1,63 @@
+"""Ищет всех друзей пользователя, включая скрытых"""
+
+varlist = {
+ 'depth': 2,
+ 'min_users': 20,
+ 'max_users': 60
+ }
+descr = {
+ 'depth': 'Глубина обхода списка друзей',
+ 'min_users': 'Мин. число людей, рассматриваемых в каждом списке друзей',
+ 'max_users': 'Макс. число людей, рассматриваемых в каждом списке друзей'
+ }
+
+def start():
+ from __main__ import myprint, vk_request
+ from target import targets, vectors
+ from vector import vectors as vectors_info
+ import methods
+
+ def get_friends(uid, target, lvl=1):
+ global finded_friends
+ lfriends = methods.friends(uid)
+ if not lfriends:
+ return False
+
+ founded_in_this_list = False
+ #если нашли нового друга
+ if target in lfriends and uid not in get_friends.founded:
+ founded_in_this_list = True
+ get_friends.founded.append(uid)
+ myprint('{} ({})'.format(methods.names(uid), uid))
+
+ #если в данном списке найдена цель, можно нырнуть на два уровня глубже
+ if lvl <= varlist['depth'] \
+ or (founded_in_this_list and lvl <= varlist['depth']+2):
+ #если цель была найдена, рассматриваем по максимуму людей из этого списка
+ limit = varlist['max_users'] if founded_in_this_list else varlist['min_users']
+ for i, friend in enumerate(lfriends):
+ #снижает число зацикливаний
+ if friend not in get_friends.founded:
+ if i >= limit:
+ break
+ rez = get_friends(friend, target, lvl+1)
+ #если было попадание в подсписке, рассматриваем по максимуму людей из этого списка
+ if rez:
+ limit = varlist['max_users']
+ return founded_in_this_list
+
+ for target_id in targets:
+ vector_id, lvl = vectors[target_id]
+ lfriends = methods.friends(target_id)
+ get_friends.founded = []
+ if lfriends:
+ get_friends.founded = list(lfriends)
+ print('Visible:')
+ for uid in lfriends:
+ myprint('{} ({})'.format(methods.names(uid), uid))
+ print('\nHidden:')
+ if lfriends and len(lfriends) > 5:
+ for uid in lfriends:
+ get_friends(uid, target_id)
+ else:
+ get_friends(vector_id, target_id)
diff --git a/payloads/likes.py b/payloads/likes.py
new file mode 100644
index 0000000..60aa74c
--- /dev/null
+++ b/payloads/likes.py
@@ -0,0 +1,74 @@
+"""Модуль для поиска лайкнутых постов в группах из списка групп пользователя"""
+
+varlist = {
+ 'links': ''
+ }
+descr = {
+ 'links': 'Если не указано, ищет в группах пользователя'
+ }
+
+from __main__ import myprint, vk_request
+def print_post(post):
+ post['text'] = post['text'].replace('\n', ' ')
+ if len(post['text']) > 78:
+ post['text'] = post['text'][:77]+'…'
+ myprint(' ', post['text'])
+ myprint(' https://vk.com/wall', post['owner_id'],'_', post['id'], sep='')
+
+def my_iter(vector_obj, target_id):
+ if not varlist['links']:
+ #сообщества юзера
+ groups = vk_request(vector_obj, 'groups.get',
+ {'user_id': target_id, 'count': 1000})
+ if not groups:
+ myprint(' Невозможно получить список групп!', error=True)
+ return
+ for group in groups['items']:
+ yield '-'+(group.replace('-', ''))
+ else:
+ #список ссылок
+ for group in varlist['links']:
+ if group:
+ yield group
+
+def start():
+ from target import targets, vectors
+ from vector import vectors as vectors_info
+ import methods
+
+ junk = ('http://', 'https://', 'vk.com/', 'group', 'id', '/')
+ if varlist['links']:
+ for i, link in enumerate(varlist['links']):
+ for j in junk:
+ link = link.replace(j, '')
+ if link.replace('-', '').isdigit():
+ varlist['links'][i] = link
+ else:
+ myprint('Неверный формат:', varlist['links'][i], error=True)
+ varlist['links'][i] = False
+
+ for target_id in targets:
+ vector_id, lvl = vectors[target_id]
+ vector_obj = vectors_info[vector_id]
+
+ myprint('{} ({})'.format(methods.names(target_id), target_id))
+ if lvl == 1:
+ rez = vk_request(vector_obj, 'fave.getPosts', {'count': 100})
+ if rez:
+ for post in rez['items']:
+ print_post(post)
+ else:
+ for group in my_iter(vector_obj, target_id);
+ print(' Анализ', group)
+ posts = vk_request(vector_obj, 'wall.get',
+ {'owner_id': group, 'count': 100})
+ if not posts:
+ continue
+ for post in posts['items']:
+ like = vk_request(vector_obj, 'likes.isLiked', {
+ 'user_id': target_id,
+ 'owner_id': -1*int(group),
+ 'item_id': post['id'],
+ 'type': 'post'})
+ if like and like['liked']:
+ print_post(post)
diff --git a/payloads/mutualfriends.py b/payloads/mutualfriends.py
new file mode 100644
index 0000000..9407e9e
--- /dev/null
+++ b/payloads/mutualfriends.py
@@ -0,0 +1,68 @@
+"""Модуль для поиска общих друзей между заданными целями."""
+
+varlist = {
+ 'depth': 3,
+ 'names': 1,
+ }
+descr = {
+ 'depth': 'Число рукопожатий (от 1 до 3)',
+ 'names': 'Выводить имена (1 - да, 0 - нет)',
+ }
+
+def start():
+ from __main__ import myprint
+ from target import targets
+ import methods
+
+ def print_rez(data, i):
+ if len(data):
+ myprint(i, 'рукопожатие(я):')
+ for ids in data:
+ if varlist['names']:
+ d = ['{} ({})'.format(methods.names(uid), uid) for uid in ids]
+ else:
+ d = [str(uid) for uid in ids]
+ myprint(' -> '.join(d))
+
+ ltargets = list(targets)
+
+ #1 рукожопатие
+ rez = []
+ for target_id in ltargets:
+ fr1 = methods.friends(target_id)
+ mut = fr1 & set(targets)
+ if mut:
+ for uid in mut:
+ rez.append((target_id, uid))
+ print_rez(rez, 1)
+
+ #2 рукожопатия
+ if varlist['depth'] > 1:
+ rez = []
+ for i in range(len(ltargets)-1):
+ for j in range(i+1, len(ltargets)):
+ fr1 = methods.friends(ltargets[i])
+ fr2 = methods.friends(ltargets[j])
+ mut = fr1 & fr2
+ if mut:
+ for uid in mut:
+ if uid != ltargets[i] and uid != ltargets[j]:
+ rez.append((ltargets[i], uid, ltargets[j]))
+ print_rez(rez, 2)
+
+ #3 рукожопатия
+ if varlist['depth'] > 2:
+ rez = []
+ for i in range(len(ltargets)-1):
+ for j in range(i+1, len(ltargets)):
+ fr1 = methods.friends(ltargets[i])
+ fr2 = methods.friends(ltargets[j])
+ for fr in fr1:
+ fr3 = methods.friends(fr)
+ mut = fr2 & fr3
+ if mut:
+ for uid in mut:
+ if uid != ltargets[i] and uid != ltargets[j] \
+ and fr != ltargets[i] and fr != ltargets[j]:
+ rez.append((ltargets[i], fr, uid, ltargets[j]))
+ print_rez(rez, 3)
diff --git a/payloads/searchmessages.py b/payloads/searchmessages.py
new file mode 100644
index 0000000..435f57c
--- /dev/null
+++ b/payloads/searchmessages.py
@@ -0,0 +1,35 @@
+"""Модуль для поиска сообщений по заданному шаблону"""
+
+varlist = {
+ 'query': 'люблю',
+ 'count': 100
+ }
+descr = {
+ 'query': 'Поисковый запрос',
+ 'count': 'Максимальное число результатов (от 1 до 100)'
+ }
+
+def start():
+ from __main__ import myprint, vk_request
+ from target import targets, vectors
+ from vector import vectors as vectors_info
+ import methods
+ from time import gmtime, strftime
+
+ for target_id in targets:
+ vector_id, lvl = vectors[target_id]
+ vector_obj = vectors_info[vector_id]
+ if lvl == 1:
+ myprint('Цель', target_id, 'не может быть атакована! Необходим вектор I уровня.')
+ else:
+ rez = vk_request(vector_obj, 'messages.search',
+ {'q': varlist['query'], 'count': varlist['count']})
+ if not rez:
+ myprint('Сообщение не найдено!')
+ else:
+ rez = rez['items']
+ for info in rez:
+ myprint()
+ myprint('{} ({}):'.format(methods.names(info['user_id']), info['user_id']))
+ myprint(info['body'])
+ myprint(strftime('[%d.%m.%Y %H:%M]', gmtime(info['date'])))
diff --git a/payloads/searchsimilar.py b/payloads/searchsimilar.py
new file mode 100644
index 0000000..5962289
--- /dev/null
+++ b/payloads/searchsimilar.py
@@ -0,0 +1,117 @@
+"""Нагрузка для поиска пользователей, похожих на заданные цели."""
+
+def start():
+ from __main__ import myprint, vk_request
+ from target import targets, vectors
+ from vector import vectors as vectors_info
+ import methods
+
+ query_fields = 'verified,sex,city,country,home_town,has_photo,education,bdate,followers_count,interests,music,movies,books,games'
+ most = ['verified', 'sex', 'city', 'country', 'home_town', 'has_photo', 'education', 'first_name']
+ avg = ['bdate', 'followers_count']
+ cntr = ['interests', 'music', 'movies', 'books', 'games']
+
+ uids = ','.join([str(target_id) for target_id in targets])
+ users = vk_request(methods.get_vk(), 'users.get', {
+ 'user_ids': uids,
+ 'fields': query_fields})
+ if not users:
+ return
+
+ #раскидываем данные о пользователях по полям
+ from itertools import chain
+ stat = dict.fromkeys(query_fields.split(','))
+ stat.update(dict.fromkeys([i+'_count' for i in cntr]))
+ stat.update({'first_name': None})
+ for user in users:
+ for field in chain(most, avg, cntr):
+ if field in user:
+ data = user[field]
+ if data:
+ if field == 'bdate':
+ data = data[-4:]
+ if '.' in data:
+ continue
+ elif field in ('city', 'country'):
+ data = data['id']
+ elif field == 'hometown':
+ data = data['title']
+
+ if type(data) is str and data.isdigit():
+ data = int(data)
+ if field in user and data:
+ if stat[field] is None:
+ stat[field] = [data]
+ else:
+ stat[field].append(data)
+
+ #рассчитываем поля
+ from pprint import pprint
+ pprint(stat)
+ count_users = len(users)
+ from collections import Counter
+ for field in most:
+ if stat[field]:
+ data = Counter(stat[field])
+ data = data.most_common(1)
+ if len(data):
+ data = data[0]
+ if data[1] > count_users/2:
+ stat[field] = data[0]
+ else:
+ stat[field] = None
+ else:
+ stat[field] = None
+ for field in avg:
+ if stat[field]:
+ stat[field] = round(sum(stat[field])/len(stat[field]))
+ for field in cntr:
+ if stat[field]:
+ #stat[field+'_count'] = round(sum(stat[field])/len(stat[field]))
+ data = Counter(stat[field])
+ data = data.most_common(1)
+ if len(data):
+ data = data[0]
+ if data[1] > max(count_users/4, 2):
+ stat[field] = data[0]
+ else:
+ stat[field] = None
+ else:
+ stat[field] = None
+
+ #вывод собранной статистики
+ for field in chain(most, avg, cntr):
+ if stat[field] is not None:
+ data = stat[field]
+ if field == 'sex':
+ data = ('женский', 'мужской')[data - 1]
+ print('{:15}: {}'.format(field, data))
+
+ #формируем запрос
+ fields = ['city', 'country', ('hometown', 'home_town'),
+ ('university', 'education'), 'sex', ('birth_year', 'bdate'),
+ 'has_photo', 'interests', ('q', 'first_name')]
+ query = dict()
+ for field in fields:
+ if type(field) is tuple:
+ field1, field2 = field
+ else:
+ field1, field2 = field, field
+ if stat[field2] is not None:
+ query[field1] = stat[field2]
+
+ query['fields'] = query_fields
+ query['count'] = 5 #200
+ if stat['followers_count'] and stat['followers_count'] > 200:
+ query['sort'] = 0
+ else:
+ query['sort'] = 1
+
+ users = vk_request(methods.get_vk(), 'users.search', query)
+ print()
+ for user in users['items']:
+ print('{} {}\n https://vk.com/id{}'.format(
+ user['first_name'],
+ user['last_name'],
+ user['id']
+ ))
diff --git a/payloads/template.py b/payloads/template.py
new file mode 100644
index 0000000..86b71cd
--- /dev/null
+++ b/payloads/template.py
@@ -0,0 +1,21 @@
+"""Descr"""
+
+varlist = {
+ 'var1': 'val1',
+ 'var2': 'val2'
+ }
+descr = {
+ 'var1': 'descr1',
+ 'var2': 'descr2'
+ }
+
+def start():
+ from __main__ import myprint, vk_request
+ from target import targets, vectors
+ from vector import vectors as vectors_info
+ import methods
+
+ for target_id in targets:
+ vector_id, lvl = vectors[target_id]
+ vector_obj = vectors_info[vector_id]
+
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..7e69414
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+vk
diff --git a/target.py b/target.py
new file mode 100644
index 0000000..b70b473
--- /dev/null
+++ b/target.py
@@ -0,0 +1,35 @@
+vectors = dict()
+targets = set()
+from __main__ import myprint
+import methods
+
+def fadd(query):
+ for uid in query:
+ uid = int(uid)
+ if uid in targets:
+ myprint(uid, 'уже добавлен в список целей!', error=True)
+ else:
+ targets.add(uid)
+ print('{} ({}) успешно добавлен в список целей.'.format(
+ methods.names(uid), uid))
+
+def fdelete(query):
+ for uid in query:
+ if uid not in targets:
+ myprint(uid, 'отсутствует в списке целей!', error=True)
+ else:
+ targets.remove(uid)
+ print(uid, 'успешно удален из списка целей.')
+
+
+def flist():
+ from vector import utokens, vectors
+ vk = vectors[utokens[0][1]]
+ i = 1
+ for uid in targets:
+ name = methods.names(uid, vk)
+ if name:
+ print('{:>2}. {} ({})'.format(i, name, uid))
+ else:
+ print('{:>2}. {}'.format(i, uid))
+ i += 1
diff --git a/vector.py b/vector.py
new file mode 100644
index 0000000..c0e5c50
--- /dev/null
+++ b/vector.py
@@ -0,0 +1,132 @@
+from vk import Session, API
+from __main__ import myprint, vk_request
+import target
+
+#uid -> obj
+from pickle import load
+try:
+ utokens = load(open('vectors', 'rb'))
+except:
+ utokens = []
+vectors = dict()
+if utokens:
+ for token, uid in utokens:
+ vectors[uid] = API(Session(access_token=token))
+
+import methods
+
+def flist():
+ print('Доступные:')
+ i = 1
+ for uid, obj in vectors.items():
+ print('{:>2}. {} ({})'.format(i, methods.names(uid, obj), uid))
+ i += 1
+ print('Установленные:')
+ i = 1
+ for uid, info in target.vectors.items():
+ print('{:>2}. {} -> {} ({} ур.)'.format(i, info[0], uid, info[1]))
+ i += 1
+
+from config import APP_KEY
+def fadd(query):
+ global vectors
+ global utokens
+ if not query:
+ print('https://oauth.vk.com/authorize?client_id=' + APP_KEY + \
+ '&scope=4667422&display=page&v=5.44&response_type=token')
+ else:
+ for token in query:
+ token = token[token.find('access_token=')+13:]
+ uid = int(token[token.rfind('=')+1:])
+ token = token[:token.find('&')]
+ if uid in vectors:
+ myprint('Токен уже есть в списке!', error=True)
+ else:
+ try:
+ vk = API(access_token=token)
+ except Exception as e:
+ myprint(e, error=True)
+ else:
+ utokens.append((token, uid))
+ name = methods.names(uid, vk)
+ vectors[uid] = vk
+ myprint('Вектор добавлен: {} ({})'.format(name, uid))
+
+def fdelete(query):
+ global vectors
+ for uid in query:
+ if uid in vectors:
+ vectors.pop(uid)
+ print(uid, 'успешно удален из списка векторов.')
+ else:
+ myprint('Вектор не найден!', error=True)
+
+def fget(queries):
+ for query in queries:
+ query = int(query)
+ #Если цель есть в списке векторов
+ if query in vectors:
+ target.vectors[query] = (query, 1)
+ print('Для {0} ({1}) получен вектор I уровня: {0} ({1}).'.format(
+ methods.names(query),
+ query))
+ continue
+
+ #выбрать первый вектор из списка для выполнения запросов к api
+ uid = utokens[0][1]
+ vk = vectors[uid]
+
+ #есть ли в списке друзей выбранного вектора цель?
+ friends = methods.friends(uid, vk)
+ if not friends:
+ myprint('Не удалось получить список друзей для', uid, error=True)
+ elif query in friends:
+ target.vectors[query] = (uid, 2)
+ print('Для {} ({}) получен вектор II уровня: {} ({}).'.format(
+ methods.names(query),
+ query,
+ methods.names(uid),
+ uid
+ ))
+ continue
+
+ #есть ли в списке друзей цели какой-нибудь вектор?
+ friends = methods.friends(query, vk)
+ if not friends:
+ myprint('Не удалось получить список друзей для', query, error=True)
+ else:
+ rez = friends & set(vectors)
+ if len(rez):
+ rez = rez.pop()
+ target.vectors[query] = (rez, 2)
+ print('Для {} ({}) получен вектор II уровня: {} ({}).'.format(
+ methods.names(query),
+ query,
+ methods.names(rez),
+ rez
+ ))
+ continue
+
+ #Есть ли общие друзья у какого-нибудь вектора и цели?
+ b = False
+ if friends:
+ for vid, obj in vectors.items():
+ friends2 = methods.friends(vid, obj)
+ if friends2:
+ rez = friends & friends2
+ if len(rez):
+ target.vectors[query] = (vid, 3)
+ print('Для {} ({}) получен вектор III уровня: {} ({}).'.format(
+ methods.names(query),
+ query,
+ methods.names(vid),
+ vid
+ ))
+ b = True
+ break
+ if b:
+ continue
+
+ #Выбрать случайный вектор
+ target.vectors[query] = (uid, 4)
+ print('Для {} получен вектор IV уровня: {}.'.format(query, uid))
diff --git a/vkehelp.py b/vkehelp.py
new file mode 100644
index 0000000..6d25fad
--- /dev/null
+++ b/vkehelp.py
@@ -0,0 +1,13 @@
+from __main__ import myprint
+from os import listdir
+helplist = listdir('help')
+def fmain(query):
+ query = ' '.join(query)
+ if query in helplist:
+ f = open('help/'+query)
+ print('+', '-'*80, '+', sep='')
+ for i in f:
+ print('|{:80}|'.format(i[:-1]))
+ print('+', '-'*80, '+', sep='')
+ else:
+ myprint('help for', query, 'not found!', error=True)