├── .github └── dependabot.yml ├── LICENSE ├── README.md ├── logo.jpg ├── requirements.txt └── ya_seeker.py /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" # See documentation for possible values 4 | directory: "/" # Location of package manifests 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Soxoj 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YaSeeker 2 | 3 |

4 | 5 |

6 | 7 | ## Description 8 | 9 | YaSeeker - an OSINT tool to get info about any Yandex account using email or login. 10 | 11 | It can find: 12 | - Fullname 13 | - Photo 14 | - Gender 15 | - Yandex UID 16 | - Yandex Public ID 17 | - Linked social accounts 18 | - Activity (count of reviews, comments; subscribers and subscriptions) 19 | - Account features (is it verified, banned, deleted, etc.) 20 | 21 | Checked Yandex services: Music, Collections, Bugbounty, Reviews, Q (Znatoki), O (Classified), Zen, Market, Messenger. 22 | 23 | ## Installation 24 | 25 | Python 3.6+ and pip are required. 26 | 27 | pip3 install -r requirements.txt 28 | 29 | ## Usage 30 | 31 | ```bash 32 | $ python3 ya_seeker.py login 33 | [*] Get info by username `login`... 34 | 35 | [+] Yandex.Collections 36 | URL: https://yandex.ru/collections/user/login/ 37 | Yandex_public_id: c48fhxw0qppa50289r5c9ku4k4 38 | Fullname: haxxor elite 39 | Image: https://avatars.mds.yandex.net/get-yapic/24700/enc-0f504b0d68d5f6fb0d336e2157b44e88ef2225aff6a621016f4dccad990b5d3e/islands-200 40 | Likes: 0 41 | Cards: 0 42 | Boards: 0 43 | Is_passport: True 44 | Is_restricted: False 45 | Is_forbid: False 46 | Is_km: False 47 | Is_business: False 48 | 49 | [+] Yandex.Music 50 | URL: https://music.yandex.ru/users/login/playlists 51 | Yandex_uid: 266797119 52 | Username: login 53 | ... 54 | 55 | $ python3 ya_seeker.py c48fhxw0qppa50289r5c9ku4k4 yandex_public_id 56 | [*] Get info by yandex_public_id `c48fhxw0qppa50289r5c9ku4k4`... 57 | 58 | [+] Yandex.Collections API 59 | URL: https://yandex.ru/collections/user/c48fhxw0qppa50289r5c9ku4k4/ 60 | Yandex_public_id: c48fhxw0qppa50289r5c9ku4k4 61 | Fullname: haxxor elite 62 | Image: https://avatars.mds.yandex.net/get-yapic/24700/enc-0f504b0d68d5f6fb0d336e2157b44e88ef2225aff6a621016f4dccad990b5d3e/islands-200 63 | Likes: 0 64 | Cards: 0 65 | Boards: 0 66 | Is_passport: True 67 | Is_restricted: False 68 | Is_forbid: False 69 | Is_km: False 70 | Is_business: False 71 | 72 | [+] Yandex.Reviews 73 | URL: https://reviews.yandex.ru/user/c48fhxw0qppa50289r5c9ku4k4 74 | Yandex_public_id: c48fhxw0qppa50289r5c9ku4k4 75 | ... 76 | ``` 77 | 78 | ## Cookies 79 | 80 | Some services are required cookies for API requests. Follow next steps to use your cookies for YaSeeker: 81 | 1. Login into Yandex through your browser. 82 | 1. Install any extension to download all the Ya cookies in Netscape format aka cookies.txt ([Chrome](https://chrome.google.com/webstore/detail/get-cookiestxt/bgaddhkoddajcdgocldbbfleckgcbcid), [Firefox](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt/)). 83 | 1. Save it to the directory of YaSeeker in file `cookies.txt`. 84 | 1. Run script and enjoy! -------------------------------------------------------------------------------- /logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HowToFind-bot/YaSeeker/fd2ff602288cfedfe0706922c0811bba5f630918/logo.jpg -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | socid-extractor>=0.0.8 2 | -------------------------------------------------------------------------------- /ya_seeker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | import os 4 | import sys 5 | from http.cookiejar import MozillaCookieJar 6 | 7 | import requests 8 | from socid_extractor import extract 9 | 10 | HEADERS = { 11 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36', 12 | } 13 | 14 | COOKIES_FILENAME = 'cookies.txt' 15 | 16 | 17 | def load_cookies(filename): 18 | cookies = {} 19 | if os.path.exists(filename): 20 | cookies_obj = MozillaCookieJar(filename) 21 | cookies_obj.load(ignore_discard=False, ignore_expires=False) 22 | 23 | for domain in cookies_obj._cookies.values(): 24 | for cookie_dict in list(domain.values()): 25 | for _, cookie in cookie_dict.items(): 26 | cookies[cookie.name] = cookie.value 27 | 28 | return cookies 29 | 30 | 31 | class IdTypeInfoAggregator: 32 | acceptable_fields = () 33 | 34 | def __init__(self, identifier: str, cookies: dict): 35 | self.identifier = identifier 36 | self.cookies = cookies 37 | self.info = {} 38 | self.sites_results = {} 39 | 40 | @classmethod 41 | def validate_id(cls, name, identifier): 42 | return name in cls.acceptable_fields 43 | 44 | def aggregate(self, info: dict): 45 | for k, v in info.items(): 46 | if k in self.info: 47 | if isinstance(self.info[k], set): 48 | self.info[k].add(v) 49 | else: 50 | self.info[k] = {self.info[k], v} 51 | else: 52 | self.info[k] = v 53 | 54 | def simple_get_info_request(self, url: str, headers_updates: dict = None, orig_url: str = None) -> dict: 55 | headers = dict(HEADERS) 56 | headers.update(headers_updates if headers_updates else {}) 57 | r = requests.get(url, headers=headers, cookies=self.cookies) 58 | 59 | if 'enter_captcha_value' in r.text: 60 | info = {'Error': 'Captcha detected'} 61 | else: 62 | try: 63 | info = extract(r.text) 64 | except Exception as e: 65 | print(f'Error for URL {url}: {e}\n') 66 | info = {} 67 | 68 | if info: 69 | info['URL'] = orig_url or url 70 | return info 71 | 72 | def collect(self): 73 | for f in self.__dir__(): 74 | if f.startswith('get_'): 75 | info = getattr(self, f)() 76 | name = ' '.join(f.split('_')[1:-1]) 77 | self.sites_results[name] = info 78 | self.aggregate(info) 79 | 80 | def print(self): 81 | for sitename, data in self.sites_results.items(): 82 | print('[+] Yandex.' + sitename[0].upper() + sitename[1:]) 83 | if not data: 84 | print('\tNot found.\n') 85 | continue 86 | 87 | if 'URL' in data: 88 | print(f'\tURL: {data.get("URL")}') 89 | for k, v in data.items(): 90 | if k != 'URL': 91 | print('\t' + k.capitalize() + ': ' + v) 92 | print() 93 | 94 | 95 | class YaUsername(IdTypeInfoAggregator): 96 | acceptable_fields = ('username',) 97 | 98 | def get_collections_API_info(self) -> dict: 99 | return self.simple_get_info_request( 100 | url=f'https://yandex.ru/collections/api/users/{self.identifier}', 101 | orig_url=f'https://yandex.ru/collections/user/{self.identifier}/' 102 | ) 103 | 104 | def get_music_info(self) -> dict: 105 | orig_url = f'https://music.yandex.ru/users/{self.identifier}/playlists' 106 | referer = {'referer': orig_url} 107 | return self.simple_get_info_request( 108 | url=f'https://music.yandex.ru/handlers/library.jsx?owner={self.identifier}', 109 | orig_url=orig_url, 110 | headers_updates=referer, 111 | ) 112 | 113 | def get_bugbounty_info(self) -> dict: 114 | return self.simple_get_info_request(f'https://yandex.ru/bugbounty/researchers/{self.identifier}/') 115 | 116 | def get_messenger_search_info(self) -> dict: 117 | url = 'https://yandex.ru/messenger/api/registry/api/' 118 | data = {"method": "search", 119 | "params": {"query": self.identifier, "limit": 10, "entities": ["messages", "users_and_chats"]}} 120 | r = requests.post(url, headers=HEADERS, cookies=self.cookies, files={'request': (None, json.dumps(data))}) 121 | info = extract(r.text) 122 | if info and info.get('yandex_messenger_guid'): 123 | info['URL'] = f'https://yandex.ru/chat#/user/{info["yandex_messenger_guid"]}' 124 | return info 125 | 126 | def get_music_API_info(self) -> dict: 127 | return self.simple_get_info_request(f'https://api.music.yandex.net/users/{self.identifier}') 128 | 129 | 130 | class YaPublicUserId(IdTypeInfoAggregator): 131 | acceptable_fields = ('yandex_public_id', 'id',) 132 | 133 | @classmethod 134 | def validate_id(cls, name, identifier): 135 | return len(identifier) == 26 and name in cls.acceptable_fields 136 | 137 | def get_collections_API_info(self) -> dict: 138 | return self.simple_get_info_request( 139 | url=f'https://yandex.ru/collections/api/users/{self.identifier}', 140 | orig_url=f'https://yandex.ru/collections/user/{self.identifier}/' 141 | ) 142 | 143 | def get_reviews_info(self) -> dict: 144 | return self.simple_get_info_request(f'https://reviews.yandex.ru/user/{self.identifier}') 145 | 146 | def get_znatoki_info(self) -> dict: 147 | return self.simple_get_info_request(f'https://yandex.ru/q/profile/{self.identifier}/') 148 | 149 | def get_zen_info(self) -> dict: 150 | return self.simple_get_info_request(f'https://zen.yandex.ru/user/{self.identifier}') 151 | 152 | def get_market_info(self) -> dict: 153 | return self.simple_get_info_request(f'https://market.yandex.ru/user/{self.identifier}/reviews') 154 | 155 | def get_o_info(self) -> dict: 156 | return self.simple_get_info_request(f'http://o.yandex.ru/profile/{self.identifier}/') 157 | 158 | 159 | class YaMessengerGuid(IdTypeInfoAggregator): 160 | acceptable_fields = ('yandex_messenger_guid',) 161 | 162 | @classmethod 163 | def validate_id(cls, name, identifier): 164 | return len(identifier) == 36 and '-' in identifier and name in cls.acceptable_fields 165 | 166 | def get_messenger_info(self) -> dict: 167 | url = 'https://yandex.ru/messenger/api/registry/api/' 168 | data = {"method": "get_users_data", "params": {"guids": [self.identifier]}} 169 | r = requests.post(url, headers=HEADERS, cookies=self.cookies, files={'request': (None, json.dumps(data))}) 170 | info = extract(r.text) 171 | if info: 172 | info['URL'] = f'https://yandex.ru/chat#/user/{self.identifier}' 173 | return info 174 | 175 | 176 | def crawl(user_data: dict, cookies: dict = None, checked_values: list = None): 177 | entities = (YaUsername, YaPublicUserId, YaMessengerGuid) 178 | if cookies is None: 179 | cookies = {} 180 | if checked_values is None: 181 | checked_values = [] 182 | for k, v in user_data.items(): 183 | values = list(v) if isinstance(v, set) else [v] 184 | for value in values: 185 | if value in checked_values: 186 | continue 187 | 188 | for e in entities: 189 | if not e.validate_id(k, value): 190 | continue 191 | 192 | checked_values.append(value) 193 | 194 | print(f'[*] Get info by {k} `{value}`...\n') 195 | entity_obj = e(value, cookies) 196 | entity_obj.collect() 197 | entity_obj.print() 198 | 199 | crawl(entity_obj.info, cookies, checked_values) 200 | 201 | 202 | def main(): 203 | identifier_type = 'username' 204 | 205 | if len(sys.argv) > 1: 206 | identifier = sys.argv[1] 207 | if len(sys.argv) > 2: 208 | identifier_type = sys.argv[2] 209 | else: 210 | identifier = input('Enter Yandex username / login / email: ') 211 | 212 | cookies = load_cookies(COOKIES_FILENAME) 213 | if not cookies: 214 | print(f'Cookies not found, but are required for some sites. See README to learn how to use cookies.') 215 | 216 | user_data = {identifier_type: identifier.split('@')[0]} 217 | 218 | crawl(user_data, cookies) 219 | 220 | 221 | if __name__ == '__main__': 222 | main() 223 | --------------------------------------------------------------------------------