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)