├── AutomatedSpearPhisher ├── images │ ├── fish.png │ ├── python.png │ ├── scraper.png │ ├── twitter.png │ └── facebook.png ├── font │ ├── Orbitron-Black.ttf │ ├── Orbitron-Bold.ttf │ ├── Orbitron-Medium.ttf │ └── Orbitron-Regular.ttf ├── Resources │ ├── tweets │ │ └── .gitignore │ └── facebook │ │ └── .gitignore ├── Output │ ├── tweets │ │ └── .gitignore │ └── facebook │ │ └── .gitignore ├── config.py ├── helpers │ ├── __init__.py │ ├── photoImageCreator.py │ ├── fieldWarningCreator.py │ ├── subHeadingCreator.py │ ├── ButtonManager.py │ └── EntryManager.py ├── MenuPage.py ├── FacebookPage.py ├── ScrapeAppGUI.py ├── CommonFrame.py ├── LoginPage.py ├── FacebookPublicPage.py ├── TwitterPage.py └── FacebookPrivatePage.py ├── pyproject.toml ├── requirements.txt ├── setup.py ├── LICENSE ├── .gitignore └── README.md /AutomatedSpearPhisher/images/fish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aarif123456/Fb-Twitter-gui/HEAD/AutomatedSpearPhisher/images/fish.png -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools>=42", 4 | "wheel" 5 | ] 6 | build-backend = "setuptools.build_meta" -------------------------------------------------------------------------------- /AutomatedSpearPhisher/images/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aarif123456/Fb-Twitter-gui/HEAD/AutomatedSpearPhisher/images/python.png -------------------------------------------------------------------------------- /AutomatedSpearPhisher/images/scraper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aarif123456/Fb-Twitter-gui/HEAD/AutomatedSpearPhisher/images/scraper.png -------------------------------------------------------------------------------- /AutomatedSpearPhisher/images/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aarif123456/Fb-Twitter-gui/HEAD/AutomatedSpearPhisher/images/twitter.png -------------------------------------------------------------------------------- /AutomatedSpearPhisher/images/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aarif123456/Fb-Twitter-gui/HEAD/AutomatedSpearPhisher/images/facebook.png -------------------------------------------------------------------------------- /AutomatedSpearPhisher/font/Orbitron-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aarif123456/Fb-Twitter-gui/HEAD/AutomatedSpearPhisher/font/Orbitron-Black.ttf -------------------------------------------------------------------------------- /AutomatedSpearPhisher/font/Orbitron-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aarif123456/Fb-Twitter-gui/HEAD/AutomatedSpearPhisher/font/Orbitron-Bold.ttf -------------------------------------------------------------------------------- /AutomatedSpearPhisher/font/Orbitron-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aarif123456/Fb-Twitter-gui/HEAD/AutomatedSpearPhisher/font/Orbitron-Medium.ttf -------------------------------------------------------------------------------- /AutomatedSpearPhisher/font/Orbitron-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aarif123456/Fb-Twitter-gui/HEAD/AutomatedSpearPhisher/font/Orbitron-Regular.ttf -------------------------------------------------------------------------------- /AutomatedSpearPhisher/Resources/tweets/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory - The tweets will be stored here 2 | * 3 | # Keep gitignore to add empty folder 4 | !.gitignore -------------------------------------------------------------------------------- /AutomatedSpearPhisher/Output/tweets/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory - The generated tweets will be stored here 2 | * 3 | # Keep gitignore to add empty folder 4 | !.gitignore -------------------------------------------------------------------------------- /AutomatedSpearPhisher/Output/facebook/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory - The generated tweets will be stored here 2 | * 3 | # Keep gitignore to add empty folder 4 | !.gitignore -------------------------------------------------------------------------------- /AutomatedSpearPhisher/Resources/facebook/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory - The generated tweets will be stored here 2 | * 3 | # Keep gitignore to add empty folder 4 | !.gitignore -------------------------------------------------------------------------------- /AutomatedSpearPhisher/config.py: -------------------------------------------------------------------------------- 1 | tor_installation_path='Resources/tor-browser_en-US' 2 | # hashed version of password 3 | program_password='$2y$12$YI.5vchiPumzxH4mRhsnrOKS9xxjK1D56ec.IwTGRUaIXhw66XEgy' -------------------------------------------------------------------------------- /AutomatedSpearPhisher/helpers/__init__.py: -------------------------------------------------------------------------------- 1 | from .fieldWarningCreator import * 2 | from .subHeadingCreator import * 3 | from .photoImageCreator import * 4 | from .ButtonManager import * 5 | from .EntryManager import * -------------------------------------------------------------------------------- /AutomatedSpearPhisher/helpers/photoImageCreator.py: -------------------------------------------------------------------------------- 1 | from tkinter import Frame, Label, PhotoImage 2 | 3 | # creates picture in the frame 4 | def createPictureInFrame(button_frame: Frame, image_path: str): 5 | image = PhotoImage (file=image_path) 6 | image_label = Label(button_frame, image=image) 7 | image_label.place(relx=0.6, rely=0) 8 | image_label.image = image -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Aarif123456/tweetGenerator#egg=tweetGenerator 2 | git+https://github.com/AshrafTaifour/Private-Facebook-Scraper#egg=FacebookChatPhisher 3 | git+https://github.com/Aarif123456/FacebookPost#egg=FacebookPost 4 | git+https://github.com/mohamadelchami/textGenerator#egg=phishingTextGenerator 5 | git+https://github.com/Aarif123456/twint.git#egg=twint 6 | bcrypt==3.2.0 7 | -------------------------------------------------------------------------------- /AutomatedSpearPhisher/helpers/fieldWarningCreator.py: -------------------------------------------------------------------------------- 1 | from tkinter import Frame, Label 2 | 3 | # field warning create a text field that will show a user-friendly error 4 | def createFieldWarning(button_frame: Frame, row: int, col: int) -> Label: 5 | field_warning_label = Label (button_frame,text='',font=('orbitron', 13), 6 | fg='white', bg='#80c1ff', anchor='s') 7 | field_warning_label.grid(row=row,column=col,pady=5, ipady=20) 8 | return field_warning_label -------------------------------------------------------------------------------- /AutomatedSpearPhisher/helpers/subHeadingCreator.py: -------------------------------------------------------------------------------- 1 | from tkinter import Frame, Label 2 | # These helper functions create the sub headings on the screen 3 | def setSubHeading(frame: Frame, sub_heading: str): 4 | heading_label = Label(frame, text=sub_heading, font=('orbitron', 13), fg='white', bg='#0077e6' ) 5 | heading_label.pack() 6 | 7 | def createLeftSubHeading(frame: Frame, sub_heading: str): 8 | heading_label = Label(frame, text=sub_heading, font=('orbitron', 15), fg='white', bg='#0077e6', anchor='w' ) 9 | heading_label.pack(fill='x') 10 | 11 | def createRightSubHeading(frame: Frame, sub_heading: str): 12 | heading_label = Label(frame, text=sub_heading, font=('orbitron', 15), fg='white', bg='#0077e6', anchor='e' ) 13 | heading_label.place(relx=0.75, rely=0.12, relwidth=0.25, relheight=0.15) -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r", encoding="utf-8") as fh: 4 | long_description = fh.read() 5 | 6 | REQUIRED = ['FacebookChatPhisher', 'tweetGenerator', 'FacebookPoster'] 7 | setuptools.setup( 8 | name="Automated_Spear_Phisher_Tool", 9 | version="0.0.1", 10 | author="Abdullah Chattha", 11 | author_email="chatthaf@uwindsor.ca", 12 | description="This program is automated spear phishing tool that works on both Facebook and Twitter.", 13 | long_description=long_description, 14 | long_description_content_type="text/markdown", 15 | url="https://github.com/Abdullah-chattha/Fb-Twitter-gui", 16 | classifiers=[ 17 | "Programming Language :: Python :: 3", 18 | "License :: OSI Approved :: MIT License", 19 | "Operating System :: OS Independent", 20 | ], 21 | packages=setuptools.find_packages(), 22 | install_requires=REQUIRED, 23 | python_requires='>=3.8', 24 | ) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Abdullah Arif, Abdullah Chattha, Mohamad Elchami, Steve Pham, Ashraf Taifour 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 | -------------------------------------------------------------------------------- /AutomatedSpearPhisher/MenuPage.py: -------------------------------------------------------------------------------- 1 | from CommonFrame import CommonFrame 2 | from helpers import * 3 | #-------------------------------------------Selection-------------------------------------------------- 4 | class MenuPage(CommonFrame): 5 | def __init__(self, parent, controller): 6 | self.controller = controller 7 | super().__init__(parent) 8 | #Set center subheading 9 | setSubHeading(self, 'Main Menu') 10 | #selection label 11 | createLeftSubHeading(self, 'Please make a selection') 12 | #buttons/frame to select which application to Scrape 13 | self.createButtonFrame() 14 | button_frame = self.getButtonFrame() 15 | #spear fish symbol 16 | createPictureInFrame(button_frame, 'images/fish.png') 17 | # Add in buttons 18 | self.addButtons(button_frame) 19 | 20 | def addButtons(self, button_frame): 21 | button_manager = ButtonManager(button_frame, self.changePages) 22 | # create selection button to go to pages 23 | button_manager.autoCreateChangePageButton('FacebookPage', 'Scrape Facebook') 24 | button_manager.autoCreateChangePageButton('TwitterPage', 'Scrape Twitter') 25 | button_manager.autoCreateChangePageButton('LoginPage', 'Exit') -------------------------------------------------------------------------------- /AutomatedSpearPhisher/FacebookPage.py: -------------------------------------------------------------------------------- 1 | from CommonFrame import CommonFrame 2 | from helpers import * 3 | 4 | # Page for Facebook selection 5 | class FacebookPage(CommonFrame): 6 | def __init__(self, parent, controller): 7 | self.controller = controller 8 | super().__init__(parent) 9 | 10 | #subheadings 11 | setSubHeading(self, 'Facebook') 12 | #Facebook selection path 13 | createLeftSubHeading(self, 'Please make a selection') 14 | createRightSubHeading(self, 'Previous Page: Main menu') 15 | 16 | #buttons/frame to select which application to Scrape 17 | self.createButtonFrame() 18 | button_frame = self.getButtonFrame() 19 | self.addButtons(button_frame) 20 | 21 | #Facebook symbol 22 | createPictureInFrame(button_frame, 'images/facebook.png') 23 | 24 | def addButtons(self, button_frame): 25 | button_manager = ButtonManager(button_frame, self.changePages) 26 | # create selection button to go to pages 27 | button_manager.autoCreateChangePageButton('FacebookPublicPage', 'Public Facebook') 28 | button_manager.autoCreateChangePageButton('FacebookPrivatePage', 'Private Facebook') 29 | button_manager.autoCreateChangePageButton('MenuPage', 'Back') -------------------------------------------------------------------------------- /AutomatedSpearPhisher/ScrapeAppGUI.py: -------------------------------------------------------------------------------- 1 | #GUI application for spear phishing tool 2 | #Abdullah Chattha mar 22/2021 3 | #imports 4 | from tkinter import Tk, Frame 5 | from LoginPage import LoginPage 6 | from MenuPage import MenuPage 7 | from FacebookPage import FacebookPage 8 | from TwitterPage import TwitterPage 9 | from FacebookPublicPage import FacebookPublicPage 10 | from FacebookPrivatePage import FacebookPrivatePage 11 | 12 | #Parent class which handles rendering in Tkinter 13 | class AutomatedSpearPhisherApp(Tk): 14 | def __init__(self, *args, **kwargs): 15 | Tk.__init__(self, *args, **kwargs) 16 | ''' 17 | the container is where we'll stack a bunch of frames 18 | on top of each other, then the one we want visible 19 | will be raised above the others 20 | ''' 21 | container = Frame(self) 22 | container.pack(side='top', fill='both', expand=True) 23 | container.grid_rowconfigure(0, weight=1) 24 | container.grid_columnconfigure(0, weight=1) 25 | 26 | self.frames = {} 27 | for F in (LoginPage, MenuPage, FacebookPage, TwitterPage, FacebookPublicPage,FacebookPrivatePage): 28 | page_name = F.__name__ 29 | frame = F(parent=container, controller=self) 30 | self.frames[page_name] = frame 31 | ''' 32 | put all of the pages in the same location; 33 | the one on the top of the stacking order 34 | will be the one that is visible. 35 | ''' 36 | frame.grid(row=0, column=0, sticky='nsew') 37 | 38 | self.show_frame('LoginPage') 39 | 40 | def show_frame(self, page_name): 41 | # Show a frame for the given page name 42 | frame = self.frames[page_name] 43 | frame.tkraise() 44 | 45 | if __name__ == '__main__': 46 | app = AutomatedSpearPhisherApp() 47 | app.mainloop() 48 | -------------------------------------------------------------------------------- /AutomatedSpearPhisher/CommonFrame.py: -------------------------------------------------------------------------------- 1 | from tkinter import Frame, PhotoImage, Label 2 | from warnings import warn 3 | from time import strftime 4 | 5 | # Common Frame with header and footer 6 | class CommonFrame(Frame): 7 | def __init__(self, parent): 8 | Frame.__init__(self, parent, bg='#0077e6') 9 | self.createHeading() 10 | self.createFooter() 11 | self.tick () 12 | 13 | #common heading 14 | def createHeading(self): 15 | heading_label = Label(self, text='Spear Phishing Tool', font=('orbitron', 45,'bold'), fg='white', bg='#0077e6') 16 | heading_label.pack(pady=25) 17 | 18 | def createFooter(self): 19 | #bottom frame for time and python logo 20 | bottom_frame = Frame(self,relief='raised', borderwidth=3) 21 | bottom_frame.pack(fill='x',side='bottom') 22 | 23 | #python develop sentence 24 | python_dev_label = Label(bottom_frame, text='Developed with: ', font=('orbitron', 12,'bold')) 25 | python_dev_label.place(relx=0) 26 | 27 | #python symbol 28 | python_image = PhotoImage (file='images/python.png') 29 | python_label = Label(bottom_frame, image=python_image) 30 | python_label.place(relx=0.11) 31 | python_label.image = python_image 32 | 33 | self.time_label = Label(bottom_frame,font=('orbitron-Bold',12)) 34 | self.time_label.pack (side='right') 35 | 36 | #time bar at the bottom 37 | def tick(self): 38 | current_time = strftime('%I:%M %p').lstrip('0').replace(' 0',' ') 39 | self.time_label.config(text=current_time) 40 | self.time_label.after(200,self.tick) 41 | 42 | #frame for buttons 43 | def createButtonFrame(self): 44 | self.button_frame = Frame(self,bg='#80c1ff') 45 | self.button_frame.pack(fill='both', expand=True) 46 | 47 | # make sure button frame exists 48 | def getButtonFrame(self): 49 | try: 50 | self.button_frame 51 | except NameError: 52 | self.createButtonFrame() 53 | warn('WARNING: Main button frame did not exist... Manually creating button frame') 54 | return self.button_frame 55 | 56 | def changePages(self, page_name: str): 57 | self.controller.show_frame(page_name) -------------------------------------------------------------------------------- /AutomatedSpearPhisher/LoginPage.py: -------------------------------------------------------------------------------- 1 | from tkinter import PhotoImage, Label, StringVar, Button, Entry 2 | from config import program_password 3 | import bcrypt 4 | from CommonFrame import CommonFrame 5 | #------------------------------------------Login------------------------------------------------------- 6 | # This page shows the initial login screen 7 | class LoginPage(CommonFrame): 8 | def __init__(self, parent, controller): 9 | self.controller = controller 10 | super().__init__(parent) 11 | self.setWindowsAttribute() 12 | self.createPasswordEntry() 13 | self.createSubmitButton() 14 | self.createInvalidPasswordLabel() 15 | 16 | # change the title in the window and add an icon 17 | def setWindowsAttribute(self): 18 | self.controller.title ('Spear Phishing Tool') 19 | self.controller.state ('normal') 20 | self.controller.iconphoto (False, PhotoImage (file='images/scraper.png')) 21 | 22 | #password entry that stores password 23 | def createPasswordEntry(self): 24 | space_label = Label(self,height=4, bg='#0077e6') 25 | space_label.pack() 26 | 27 | password_label=Label(self,text='Enter password', font=('orbitron', 13), bg='#0077e6', fg='white') 28 | password_label.pack(pady=10) 29 | 30 | self.my_password = StringVar() 31 | password_box = Entry(self, show='*', textvariable=self.my_password,font=('orbitron', 12), width=22) 32 | password_box.focus_set() 33 | password_box.pack(ipady=7) 34 | 35 | def createSubmitButton(self): 36 | enter_button = Button(self, text='Enter', command=self.checkPassword, relief='raised', borderwidth=3, width=40, height=3 ) 37 | enter_button.pack(pady=10) 38 | 39 | def createInvalidPasswordLabel(self): 40 | self.incorrect_password_label = Label (self,text='',font=('orbitron', 13),fg='white', bg='#80c1ff', anchor='n') 41 | self.incorrect_password_label.pack(fill='both', expand=True) 42 | 43 | #password enter button and checks to see if it matches password from the configuration file 44 | def checkPassword(self): 45 | if bcrypt.checkpw(self.my_password.get().encode('utf-8'), program_password.encode('utf-8')): 46 | self.my_password.set('') 47 | self.incorrect_password_label['text']='' 48 | self.controller.show_frame('MenuPage') 49 | else: 50 | self.incorrect_password_label['text']='Incorrect Password' 51 | 52 | -------------------------------------------------------------------------------- /AutomatedSpearPhisher/helpers/ButtonManager.py: -------------------------------------------------------------------------------- 1 | from tkinter import Frame, Button 2 | from typing import Callable 3 | from functools import partial 4 | 5 | # Handles creation of button to a given - allows button to be added automatically and increment row 6 | # Also simplifies page changing 7 | class ButtonManager: 8 | def __init__(self, button_frame: Frame, changePages: Callable[[Frame, str], None]): 9 | if button_frame==None: 10 | raise ValueError 11 | self.changePages = changePages 12 | self.button_frame = button_frame 13 | # used to automatically insert buttons 14 | self.button_row = 0 15 | self.button_col = 0 16 | self.last_button_row = 0 17 | 18 | # Get back last row we created a button. This makes it easier to place objects 19 | def getLastButtonRow(self)-> int: 20 | return self.last_button_row 21 | 22 | # Make a button that runs a given function when pressed 23 | def createButton(self, button_frame: Frame, text: str, command: Callable[[], None], 24 | row: int, col: int, style='raised', borderwidth=3, width=50,height=5, sticky=''): 25 | button = Button(button_frame, text=text, command=command, 26 | relief=style,borderwidth=borderwidth, width=width,height=height) 27 | button.grid (row=row,column=col, pady=5, sticky=sticky) 28 | self.last_button_row = max(row, self.last_button_row) 29 | 30 | # add button to main button frame - and go to new row 31 | def autoAddButton(self, text: str, command : Callable[[], None], style='raised', 32 | borderwidth=3, width=50,height=5): 33 | button_frame = self.button_frame 34 | self.createButton(button_frame, text, command, self.button_row, 35 | self.button_col, style, borderwidth, width, height) 36 | self.button_row+=1 37 | 38 | # page changing functions 39 | def getPageChangeFunction(self, page_name: str) -> Callable[[], None]: 40 | return partial(self.changePages, page_name) 41 | 42 | # Convenience function to change pages 43 | def autoCreateChangePageButton(self, page_name: str, text: str): 44 | change_page_func = self.getPageChangeFunction(page_name) 45 | self.autoAddButton(text, change_page_func) 46 | 47 | # Create a button that changes pages but you can pass in rows and column 48 | def createChangePageButton(self, page_name: str, text: str, row: int, col: int): 49 | change_page_func = self.getPageChangeFunction(page_name) 50 | self.createButton(self.button_frame, text, change_page_func, row, col) -------------------------------------------------------------------------------- /AutomatedSpearPhisher/FacebookPublicPage.py: -------------------------------------------------------------------------------- 1 | from CommonFrame import CommonFrame 2 | # TODO: add face book public scraper 3 | # TODO: make sure posting works on public scraper as well 4 | from FacebookPost import post 5 | from helpers import * 6 | 7 | class FacebookPublicPage(CommonFrame): 8 | def __init__(self, parent, controller): 9 | self.controller = controller 10 | super().__init__(parent) 11 | 12 | #subheadings 13 | setSubHeading(self, 'Public Facebook') 14 | #Facebook selection path 15 | createLeftSubHeading(self, 'Please enter fields') 16 | createRightSubHeading(self, 'Previous Page: Facebook') 17 | 18 | #frame for buttons 19 | self.createButtonFrame() 20 | button_frame = self.getButtonFrame() 21 | #Facebook symbol 22 | createPictureInFrame(button_frame, 'images/facebook.png') 23 | #create entry fields and their label 24 | self.entry_manager = EntryManager(button_frame, start_row=1, label_col=0, entry_col=1) 25 | self.addEnteries(self.entry_manager) 26 | last_entry_row = self.entry_manager.getLastEntryRow() 27 | # create buttons 28 | last_button_row = self.addButtons(button_frame, last_entry_row+1) 29 | #create field that will show warnings 30 | self.field_warning_label = createFieldWarning(button_frame, row=last_button_row, col=1) 31 | 32 | #TODO: function to pass arguments to Ashraf's scripts 33 | def scrapePublicFacebook(self): 34 | entry_manager = self.entry_manager 35 | facebook_url = entry_manager.getValueOfEntry('facebook_url') 36 | facebook_visibility = entry_manager.getValueOfEntry('facebook_visibility') 37 | 38 | if not entry_manager.allFieldsFilled(): 39 | self.field_warning_label['text']='*Please fill all fields*' 40 | else: 41 | print (facebook_url) 42 | print (facebook_visibility) 43 | print('NOT SENDING ARGUMENTS TO PUBLIC scraper') 44 | self.changePages('FacebookPage') 45 | 46 | # add in buttons in the frame and get back last row that we have a button 47 | def addButtons(self, button_frame, button_row): 48 | button_manager = ButtonManager(button_frame, self.changePages) 49 | #send button 50 | button_manager.createButton(button_frame, text='Enter', command=self.scrapePublicFacebook, row=button_row, col=1) 51 | # back button 52 | button_manager.createChangePageButton(page_name='FacebookPage', text='Back', row=button_row+1,col=0) 53 | return button_manager.getLastButtonRow() 54 | 55 | def addEnteries(self, entry_manager): 56 | entry_manager.addLabelWithEntry('URL of friend to Scrape:', 'facebook_url') 57 | entry_manager.addLabelWithEntry('visible/invisible :', 'facebook_visibility') -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | cover/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Scrapy stuff: 60 | .scrapy 61 | 62 | # Sphinx documentation 63 | docs/_build/ 64 | 65 | # PyBuilder 66 | .pybuilder/ 67 | target/ 68 | 69 | # Jupyter Notebook 70 | .ipynb_checkpoints 71 | 72 | # IPython 73 | profile_default/ 74 | ipython_config.py 75 | 76 | # pyenv 77 | # For a library or package, you might want to ignore these files since the code is 78 | # intended to run in multiple environments; otherwise, check them in: 79 | .python-version 80 | /facebookEnv/ 81 | 82 | # pipenv 83 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 84 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 85 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 86 | # install all needed dependencies. 87 | #Pipfile.lock 88 | 89 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 90 | __pypackages__/ 91 | 92 | # Celery stuff 93 | celerybeat-schedule 94 | celerybeat.pid 95 | 96 | # SageMath parsed files 97 | *.sage.py 98 | 99 | # Environments 100 | .env 101 | .venv 102 | env/ 103 | venv/ 104 | ENV/ 105 | env.bak/ 106 | venv.bak/ 107 | 108 | # Spyder project settings 109 | .spyderproject 110 | .spyproject 111 | 112 | # Rope project settings 113 | .ropeproject 114 | 115 | # mkdocs documentation 116 | /site 117 | 118 | # mypy 119 | .mypy_cache/ 120 | .dmypy.json 121 | dmypy.json 122 | 123 | # Pyre type checker 124 | .pyre/ 125 | 126 | # pytype static type analyzer 127 | .pytype/ 128 | 129 | # static files generated from Django application using `collectstatic` 130 | media 131 | static 132 | 133 | # pycharm dump 134 | /.idea/ 135 | 136 | # download tor on your own: https://www.torproject.org/download/ 137 | /tor-browser_en-US/ 138 | 139 | #gecko driver files 140 | geckodriver.log 141 | -------------------------------------------------------------------------------- /AutomatedSpearPhisher/TwitterPage.py: -------------------------------------------------------------------------------- 1 | from tweetGenerator import createCorpusForUser 2 | from tweetGenerator import generateTweet 3 | from CommonFrame import CommonFrame 4 | from helpers import * 5 | 6 | #-------------------------------------------Twitter page---------------------------------------------- 7 | class TwitterPage(CommonFrame): 8 | def __init__(self, parent, controller): 9 | self.controller = controller 10 | super().__init__(parent) 11 | 12 | #subheadings 13 | setSubHeading(self, 'Twitter') 14 | #twitter selection path 15 | createLeftSubHeading(self, 'Please enter fields') 16 | createRightSubHeading(self, 'Previous Page: Main menu') 17 | 18 | #frame for buttons 19 | self.createButtonFrame() 20 | button_frame = self.getButtonFrame() 21 | #twitter symbol 22 | createPictureInFrame(button_frame, 'images/twitter.png') 23 | #entry fields 24 | self.entry_manager = EntryManager(button_frame, start_row=0, label_col=0, entry_col=1) 25 | self.addEnteries(self.entry_manager) 26 | last_entry_row = self.entry_manager.getLastEntryRow() 27 | last_button_row = self.addButtons(button_frame, last_entry_row+1) 28 | self.field_warning_label = createFieldWarning(button_frame, row=last_button_row, col=1) 29 | 30 | 31 | #function to pass to Ashraf's scripts 32 | def sendTwitterHandle (self): 33 | entry_manager = self.entry_manager 34 | twitter_handle = entry_manager.getValueOfEntry('twitter_handle') 35 | twitter_url = entry_manager.getValueOfEntry('twitter_url') 36 | num_scrape_tweets = entry_manager.getValueOfEntry('num_scrape_tweets') 37 | num_tweets = entry_manager.getValueOfEntry('num_tweets') 38 | tweets_folder = "Resources/tweets" 39 | gen_tweets_folder = "Output/tweets" 40 | 41 | if not entry_manager.allFieldsFilled(): 42 | self.field_warning_label['text']='*Please fill all fields*' 43 | else: 44 | #call tweet generator 45 | createCorpusForUser (twitter_handle, tweets_folder, int(num_scrape_tweets)) 46 | generateTweet (twitter_handle, twitter_url, gen_tweets_folder,\ 47 | tweets_folder, int(num_tweets)) 48 | 49 | #print(twitter_handle) 50 | self.changePages('MenuPage') 51 | 52 | # add in buttons in the frame and get back last row that we have a button 53 | def addButtons(self, button_frame, button_row): 54 | button_manager = ButtonManager(button_frame, self.changePages) 55 | #send button 56 | button_manager.createButton(button_frame, text='Enter', command=self.sendTwitterHandle, row=button_row, col=1) 57 | #back button 58 | button_manager.createChangePageButton(page_name='MenuPage', text='Back', row=button_row+1,col=0) 59 | return button_manager.getLastButtonRow() 60 | 61 | 62 | def addEnteries(self, entry_manager): 63 | entry_manager.addLabelWithEntry('Twitter handle of account:', 'twitter_handle') 64 | entry_manager.addLabelWithEntry('Phishing URL:', 'twitter_url') 65 | entry_manager.addNumericalEntryWithLabel('Tweets to Scrape', 'num_scrape_tweets') 66 | entry_manager.setValueOfEntry('num_scrape_tweets', str(5000)) 67 | entry_manager.addNumericalEntryWithLabel('Tweets to generate', 'num_tweets') 68 | entry_manager.setValueOfEntry('num_tweets', str(10)) 69 | 70 | -------------------------------------------------------------------------------- /AutomatedSpearPhisher/helpers/EntryManager.py: -------------------------------------------------------------------------------- 1 | from tkinter import Frame, Label, Entry, END 2 | from warnings import warn 3 | 4 | # Entry manager creates text fields with labels 5 | class EntryManager: 6 | def __init__(self, button_frame: Frame, start_row: int, label_col: int, entry_col: int): 7 | if button_frame==None: 8 | raise ValueError 9 | self.button_frame = button_frame 10 | self.label_row = start_row 11 | self.entry_row = start_row 12 | self.label_col = label_col 13 | self.entry_col = entry_col 14 | self.entry_dict = dict() 15 | 16 | # get the last row that we have an entry on 17 | def getLastEntryRow(self)-> int: 18 | return self.entry_row-1 19 | 20 | # Create a label -this meant to be used alongside the text-field(entry) 21 | def autoAddLabel(self, text: str, sticky=''): 22 | button_frame = self.button_frame 23 | label = Label(button_frame, text=text, font=('orbitron', 15), 24 | fg='white', bg='#80c1ff',anchor='w' ) 25 | label.grid (row=self.label_row,column=self.label_col,pady=5, ipady=20, sticky=sticky) 26 | self.label_row += 1 27 | 28 | # create dictionary to map entry and create text field 29 | def autoAddEntry(self, entry_label, sticky='', show='', width=59, vcmd={}, validate="none"): 30 | button_frame = self.button_frame 31 | entry = Entry(button_frame, width=width, show=show, validate=validate, validatecommand=vcmd) 32 | entry.grid (row=self.entry_row,column=self.entry_col,pady=5, ipady=20, sticky=sticky) 33 | self.entry_dict[entry_label] = entry 34 | self.entry_row += 1 35 | 36 | # Create a label with a text field 37 | def addLabelWithEntry(self, text: str, entry_label: str, sticky_label='', sticky_entry='', show='', vcmd={}, validate="none"): 38 | self.autoAddLabel(text, sticky_label) 39 | self.autoAddEntry(entry_label, sticky_entry, show, vcmd=vcmd, validate=validate) 40 | self.entry_row 41 | 42 | # Create a label with a text field that only accepts numbers 43 | def addNumericalEntryWithLabel(self, text: str, entry_label: str, sticky_label='', sticky_entry='', show=''): 44 | # '%P' is value of entry if allowed 45 | validateNumber = (self.register(self.validateNumber), "%P") 46 | self.addLabelWithEntry(text, entry_label, sticky_label, sticky_entry, show, validate="all", vcmd=validateNumber) 47 | 48 | # retrieve the value of the entry 49 | def getValueOfEntry(self, entry_label: str): 50 | if entry_label in self.entry_dict: 51 | return self.entry_dict[entry_label].get() 52 | warn(f'WARNING: value "{entry_label}" does not exist') 53 | return '' 54 | 55 | # Set the value of text field. Can be used to set default values 56 | def setValueOfEntry(self, entry_label: str, value: str): 57 | if entry_label in self.entry_dict: 58 | e=self.entry_dict[entry_label] 59 | e.delete(0,END) 60 | e.insert(0,value) 61 | else: 62 | warn(f'WARNING: value "{entry_label}" does not exist') 63 | 64 | def getEntryGridInfo(self, entry_label: str): 65 | if entry_label in self.entry_dict: 66 | return self.entry_dict[entry_label].grid_info() 67 | warn(f'WARNING: value "{entry_label}" does not exist') 68 | return {"row":0, "column": 0} 69 | 70 | # Check if all fields are filled out 71 | def allFieldsFilled(self)-> bool: 72 | for entry_label in self.entry_dict: 73 | if self.getValueOfEntry(entry_label) == '': 74 | return False 75 | return True 76 | 77 | # Set up function that will be used to control what inputs the entry accepts 78 | def register(self, callback): 79 | return (self.button_frame.register(callback)) 80 | 81 | # Helper function that only accepts numbers 82 | def validateNumber(self, val)-> bool: 83 | return str.isdigit(val) or val == "" 84 | 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## What is this? 🤔 2 | This program is automated spear phishing tool that works on both Facebook and Twitter. 3 | THIS IS ONLY INTENDED FOR RESEARCH PURPOSES 4 | 5 | ## Authors: 6 | - Abdullah Arif 7 | - Abdullah Chattha 8 | - Ashraf Taifour 9 | - Mohamad Elchami 10 | - Steve Pham 11 | 12 | ## Supervisor 13 | Dr. Sherif Saad Ahmed 14 | 15 | ## How to run 16 | Program has been tested on Linux 17 | 1. Setup 18 | * Make sure you have gecko driver installed: https://github.com/mozilla/geckodriver/releases 19 | * Also, install TOR: https://www.torproject.org/download/ 20 | * Extract TorFolder in the `AutomatedSpearPhisher/Resources` directory 21 | * If you choose to use a different folder, you need to change the setting in the config.py file 22 | 2. Recommended step: use virtual environment 23 | ``` 24 | python3 -m venv env 25 | source env/bin/activate 26 | ``` 27 | 4. Install dependencies 28 | `pip3 install -r requirements.txt` 29 | 30 | 5. Run program 31 | `python3 ScrapeAppGUI.py` 32 | 33 | ## Troubleshooting 34 | If you are running on a python version that doesn't have tkinter installed 35 | please run 36 | ```apt-get install python3-tk``` 37 | 38 | ## Features 39 | * Password protected program, so it will be easy to protect the program if we develop it further. 40 | * Support for both Twitter and Facebook 41 | * For the Facebook phisher, only the private phisher is working currently 42 | * The private Facebook supports a variety of browsers, make sure to download the appropriate selenium driver to use 43 | * The target is the user whose friends will be scraped, it can be your own username if you want to generate phishing messages for your friends 44 | * The number of friends parameter allows you to control how many friends you want to target. We recommend using a small number if you enable the posting option. 45 | * The path to the driver will the path to the Selenium driver 46 | * If you tick the check-box then the program will post to Facebook using your account 47 | * For the Twitter portion, you just type the target's Twitter handle and the url to the phishing site. The program will output the Tweets. The generated tweets are stored in the `Output/tweets` directory. 48 | 49 | ## Importance 50 | Phishing attacks accounted for 80% of security incidents. And the pandemic has increased the number of cyber attacks. So, it is imperative that we study different social attacks. There is a more potent type of phishing called “spear-phishing”, where an attacker gathers information about a user and uses that to craft a more persuasive message. This technique has a much higher click through rate than average phishing attacks. Fortunately, this method is time-consuming and so the attacker cannot target as many people. However, we believe that you can use machine learning to automate this process. If this process becomes widespread, it would have disastrous consequences. 51 | 52 | Our project will be to create this automated spear-phishing tool. We will then use our tool to analyze them to determine the effectiveness of various algorithms and the vulnerability on different platforms. We also hope to show the potency of this attack. So, we will compare it to normal phishing attacks and compare the results. We hope the results from our study will help future developers and cybersecurity researchers to create more effective safeguards against social attacks. 53 | 54 | Most malware comes from email. However, there is a rising trend for phishing attacks conducted on social media. This is because social media contains a plethora of personal information which makes it possible to launch this type of automated spear-phishing attack. 55 | 56 | Rather than creating a defensive tool like a phishing detector using machine learning, we have created an offensive tool. This is because when people are trying to break things, they look for the easiest ways to get the job done. The principle of easiest penetration states that a security system is as strong as its weakest link. So by thinking like an attacker, we can become better defenders. 57 | 58 | ## Related Repository 59 | These are other repository used in the project 60 | Private Facebook Scrape: https://github.com/AshrafTaifour/Private-Facebook-Scraper 61 | 62 | Public Facebook Scraper: https://github.com/AshrafTaifour/public-Facebook-Scraper 63 | 64 | Facebook Poster: https://github.com/Aarif123456/FacebookPost 65 | 66 | Phishing Message Generator: https://github.com/mohamadelchami/textGenerator 67 | 68 | Malicious Website: https://github.com/Steve-Pham/UserClicks (website link: https://steve-pham.github.io/UserClicks/) 69 | 70 | Twitter Phisher: https://github.com/Aarif123456/tweetGenerator 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /AutomatedSpearPhisher/FacebookPrivatePage.py: -------------------------------------------------------------------------------- 1 | from tkinter.ttk import Combobox 2 | from tkinter import filedialog, Checkbutton, IntVar 3 | from CommonFrame import CommonFrame 4 | from config import tor_installation_path 5 | from FacebookChatPhisher import * 6 | from FacebookPost import post 7 | import phishingTextGenerator 8 | from time import sleep 9 | from helpers import * 10 | 11 | class FacebookPrivatePage(CommonFrame): 12 | def __init__(self, parent, controller): 13 | self.controller = controller 14 | super().__init__(parent) 15 | #subheadings 16 | setSubHeading(self, 'Private Facebook') 17 | #Facebook selection path 18 | createLeftSubHeading(self, 'Please enter fields') 19 | createRightSubHeading(self, 'Previous Page: Facebook') 20 | #frame for buttons/entry fields 21 | self.createButtonFrame() 22 | button_frame = self.getButtonFrame() 23 | #Facebook symbol 24 | createPictureInFrame(button_frame, 'images/facebook.png') 25 | # creating typeable fields 26 | self.entry_manager = EntryManager(button_frame, start_row=0, label_col=0, entry_col=1) 27 | self.addEnteries(self.entry_manager) 28 | last_entry_row = self.entry_manager.getLastEntryRow() 29 | self.addBrowserSelector(button_frame, last_entry_row+1) 30 | self.addPostingCheckBox(button_frame, last_entry_row+1) 31 | ''' The buttons will be placed after the entries, the 32 | browser selector and posting check-box 33 | ''' 34 | button_rows = last_entry_row +2 35 | last_button_row = self.addButtons(button_frame, button_rows) 36 | # field to show warnings 37 | self.field_warning_label = createFieldWarning(button_frame, row=last_button_row, col=1) 38 | 39 | def setFile(self): 40 | ftypes = [('Executables files', '*.exe'), ('All files', '*')] 41 | filename = filedialog.askopenfilename(initialdir = "/", 42 | title = "Select a File", 43 | filetypes = ftypes) 44 | self.entry_manager.setValueOfEntry('driver_path', filename) 45 | 46 | # add in buttons in the frame and get back last row that we have a button 47 | def addButtons(self, button_frame, button_rows: int): 48 | button_manager = ButtonManager(button_frame, self.changePages) 49 | driver_path_row = self.entry_manager.getEntryGridInfo('driver_path')['row'] 50 | # This button is associated with the entry that control the browser driver path 51 | button_manager.createButton(button_frame, text='Open', command=self.setFile, row=driver_path_row, col=0, width=15, height=3) 52 | #send button 53 | button_manager.createButton(button_frame, text='Enter', command=self.scrapePrivateFacebook, row=button_rows, col=1) 54 | #back button 55 | button_manager.createChangePageButton(page_name='FacebookPage', text='Back', row=button_rows+1,col=0) 56 | return button_manager.getLastButtonRow() 57 | 58 | # drop-down select browser 59 | def addBrowserSelector(self, button_frame, browser_row: int): 60 | self.browser_selector = Combobox(button_frame, values=getSupportedBrowser(), width=35,height=15, font=('orbitron', 15)) 61 | self.browser_selector.grid(row=browser_row, column=1) 62 | self.browser_selector.current(0) 63 | 64 | def addPostingCheckBox(self, button_frame, check_box_row: int): 65 | self.shouldPost = IntVar() 66 | poster_box = Checkbutton(button_frame, text = "Post To Facebook", 67 | variable=self.shouldPost) 68 | poster_box.grid(row=check_box_row, column=0) 69 | 70 | def addEnteries(self, entry_manager): 71 | entry_manager.addLabelWithEntry('Email used for Facebook:', 'email') 72 | entry_manager.addLabelWithEntry('Facebook Password:', 'password', show='*') 73 | entry_manager.addLabelWithEntry('Your Facebook Username:', 'username') 74 | entry_manager.addNumericalEntryWithLabel('Number of Friends to Scrape:', 'num_friends') 75 | entry_manager.addLabelWithEntry('Path to driver:', 'driver_path', sticky_label='we') 76 | 77 | #function to pass arguments to Ashraf's scripts 78 | def scrapePrivateFacebook(self): 79 | entry_manager = self.entry_manager 80 | email = entry_manager.getValueOfEntry('email') 81 | password = entry_manager.getValueOfEntry('password') 82 | username = entry_manager.getValueOfEntry('username') 83 | num_friends = entry_manager.getValueOfEntry('num_friends') 84 | driver_path = entry_manager.getValueOfEntry('driver_path') 85 | browser_mode = SUPPORTED_BROWSER.get(self.browser_selector.get()) 86 | 87 | if not entry_manager.allFieldsFilled() : 88 | self.field_warning_label['text']='*Please fill all fields*' 89 | else: 90 | inputPath = "Resources/facebook" 91 | outputPath = "Output/facebook" 92 | # login to Facebook 93 | driver = getDriver(driver_path, browser_mode, tor_installation_path) 94 | loginToFacebook(driver, email , password) 95 | sleep(8) 96 | # get list of friend's pages 97 | FULLHTMLPAGE = getFriendsListHTMLPage(driver, username) 98 | # extract the URL to their page 99 | friendURLS = parseFriendsPage(FULLHTMLPAGE) 100 | # scrape and store their likes pages 101 | scrapeLikePages(driver, friendURLS, int(num_friends), inputPath) 102 | # create phishing text based on created like pages 103 | phishingTextGenerator.main(inputPath, outputPath) 104 | if self.shouldPostToFacebook(): 105 | self.postToFacebook(driver, friendURLS, outputPath) 106 | self.changePages('FacebookPage') 107 | 108 | def shouldPostToFacebook(self)-> bool: 109 | return self.shouldPost.get() == 1 110 | 111 | def postToFacebook(self, driver, friendURLS: list, outputPath : str): 112 | for i in range(len(friendURLS)): 113 | friendURL = friendURLS[i] 114 | filepath = f"{outputPath}/message{i}.txt" 115 | with open(filepath, "r", encoding='utf-8') as f: 116 | message = f.read() 117 | post(driver, friendURL, message) 118 | sleep(3) 119 | 120 | 121 | --------------------------------------------------------------------------------