├── lib ├── __init__.py ├── when_things_go_south.py └── email_modules.py ├── sample_conf ├── body.txt ├── bjm.jpg ├── url.jpg ├── facebook.png ├── addresses.csv └── body.html ├── confs └── example.conf ├── .gitignore ├── README.md └── hemingway.py /lib/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'tisf' 2 | -------------------------------------------------------------------------------- /sample_conf/body.txt: -------------------------------------------------------------------------------- 1 | This is just a text body. 2 | -------------------------------------------------------------------------------- /sample_conf/bjm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ytisf/hemingway/HEAD/sample_conf/bjm.jpg -------------------------------------------------------------------------------- /sample_conf/url.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ytisf/hemingway/HEAD/sample_conf/url.jpg -------------------------------------------------------------------------------- /sample_conf/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ytisf/hemingway/HEAD/sample_conf/facebook.png -------------------------------------------------------------------------------- /sample_conf/addresses.csv: -------------------------------------------------------------------------------- 1 | Bill Gates ;tisf@mailinator.com 2 | Roger Waters ;tisf@mailinator.com 3 | John Cleese ;tisf@mailinator.com 4 | Douglas Adams ;tisf@mailinator.com 5 | Karl Marx ;tisf@mailinator.com 6 | -------------------------------------------------------------------------------- /confs/example.conf: -------------------------------------------------------------------------------- 1 | [server] 2 | address: 127.0.0.1 3 | port: 25 4 | max_connections: 3 5 | 6 | [phish] 7 | addresses_csv: sample_conf/addresses.csv 8 | html_body: sample_conf/body.html 9 | txt_body: sample_conf/body.txt 10 | subject: What are you doing here? 11 | attachments: sample_conf/body.html, sample_conf/body.txt 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Python template 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | env/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | 47 | # Translations 48 | *.mo 49 | *.pot 50 | 51 | # Django stuff: 52 | *.log 53 | 54 | # Sphinx documentation 55 | docs/_build/ 56 | 57 | # PyBuilder 58 | target/ 59 | 60 | # Created by .ignore support plugin (hsz.mobi) 61 | -------------------------------------------------------------------------------- /lib/when_things_go_south.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | class Error_Handler(): 5 | """ 6 | This is just a simple and simple error handler 7 | """ 8 | def __init__(self): 9 | pass 10 | 11 | class bcolors: 12 | HEADER = '\033[95m' 13 | OKBLUE = '\033[94m' 14 | OKGREEN = '\033[92m' 15 | WARNING = '\033[93m' 16 | FAIL = '\033[91m' 17 | ENDC = '\033[0m' 18 | 19 | def log_error(self, id, error): 20 | """ 21 | :param id: Identifier of error type 22 | :param error: Error message 23 | :return: nothing 24 | """ 25 | 26 | # 0 = info, 1=warning, 2=error, 3=critical 27 | 28 | if id == 0: 29 | sys.stdout.write(self.bcolors.OKGREEN + "[+] " + self.bcolors.ENDC + error + "\n") 30 | 31 | elif id == 1: 32 | sys.stderr.write(self.bcolors.WARNING + "[-] " + self.bcolors.ENDC + error + "\n") 33 | 34 | elif id == 2: 35 | sys.stderr.write(self.bcolors.FAIL + "[!] " + self.bcolors.ENDC + error + "\n") 36 | 37 | elif id == 3: 38 | sys.stderr.write(self.bcolors.FAIL + "[!] " + self.bcolors.ENDC + error + "\n") 39 | sys.exit(1) 40 | 41 | else: 42 | print("Go learn your error handler!!!!") 43 | sys.exit(1) 44 | -------------------------------------------------------------------------------- /sample_conf/body.html: -------------------------------------------------------------------------------- 1 | 2 | Get outta my head!

3 | 4 |

5 |

6 |

John Malkovich 7 | / Being John Malkovich
8 | (305) 999-9999/

9 |

10 | BGM Corp 11 | Office: +314-159-2657 12 | 13 |
14 | 15 |

16 |

17 |

18 | Lots of things. That jewel thief movie, for example. He's very well respected. Anyway, the point is... this is a very odd thing. It's supernatural, for lack of a better word. I mean, it raises all sorts of philosophical-type questions, you know... about the nature of self, about the existence of a soul. You know, am I me? Is Malkovich Malkovich? I had a piece of wood in my hand Maxine. I don't have it any more. Where is it? Did it disappear? How could that be? Is it still in Malkovich's head? I don't know! Do you see what a metaphysical can of worms this portal is? I don't see how I could go on living my life the way I've lived it before. 19 |

-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Hemingway 2 | 3 | ##Introduction 4 | This tool was built to allow simpler campaigns of phishing. It does not try to resolve issues with SMTP relaying or reputation but rather to allow a penetration tester or red team member to create a phishing campaign with a ready made server for the phishing. We also assume that if you are dealing with anti-phishing components you have already mapped their rules. 5 | Original repository and updates will be available at 6 | 7 | ##Usage 8 | For now, Hemingway will not get a configuration file from the user but will rather work with a template. 9 | The ***example.conf*** file in the ***confs*** is currently available for example. The configuration file, however, is not the only files required but also the ***sample_conf*** folder which we'll cover in a minute. 10 | ``` 11 | [server] 12 | address: 192.168.10.80 13 | port: 25 14 | max_connections: 3 15 | 16 | [phish] 17 | addresses_csv: sample_conf/addresses.csv 18 | html_body: sample_conf/body.html 19 | txt_body: sample_conf/body.txt 20 | subject: What are you doing here? 21 | attachments: sample_conf/body.html, sample_conf/body.txt 22 | ``` 23 | 24 | This file is pretty straight and forward. It will give Hemingway the information it needs for the phishing campaign. Which files to attach (separated by a ',' which means as much files as you want), subject of the email and HTML and TXT body. 25 | Now let's have a look at the addresses file ***sample_conf/addresses.csv***: 26 | 27 | Bill Gates ;tisf@mailinator.com 28 | Roger Waters ;tisf@mailinator.com 29 | John Cleese ;tisf@mailinator.com 30 | Douglas Adams ;tisf@mailinator.com 31 | Karl Marx ;tisf@mailinator.com 32 | 33 | As you can see, not much to say here as well. On the left will be the addresses for the spoofed sender and on the right the addresses of the victims. 34 | 35 | **HTML** 36 | When you are creating you HTML body please remember that each image you embed will later be attached to the body and chagned to a CID so the recipients' email clients' will be able to interpret those images. Keep the images in the body of the email for the regex to find and store the images at the same folder as the HTML body is at, aka ***sample_conf***. 37 | 38 | ##File Structure 39 | 40 | ###confs 41 | This folder holds the configuration files and in future will hold a few templates. Currently only holding ***example.conf*** 42 | 43 | ###includes 44 | This folders holds the core of Hemingway 45 | 46 | * email_modules.py - ***As it says. This module will manage, build and send the emails.*** 47 | * when_things_go_south.py - ***Error handler. A big pile of mess. *** 48 | ###sample_conf 49 | 50 | * addresses.csv - ***the address list as described earlier. *** 51 | * body.html - ***the mail HTML body. this one will be parsed for the images attached. *** 52 | * body.txt - ***the alternative text body *** 53 | * url.jpg - ***an in-body image just for an example *** 54 | 55 | ##Future Change Log 56 | - [X] Add support for mail server authentication. 57 | - [X] Add threading capabilities. 58 | - [X] Change settings to support max parallel connections to the server. 59 | - [ ] Add simpler HTML interface. 60 | - [ ] Comprehensive support for logging and summery. 61 | 62 | ##License (GPLv3) 63 | Hemingway - A Phishing Campaign Helper 64 | Copyright (C) 2014 Yuval tisf Nativ 65 | 66 | This program is free software: you can redistribute it and/or modify 67 | it under the terms of the GNU General Public License as published by 68 | the Free Software Foundation, either version 3 of the License, or 69 | (at your option) any later version. 70 | 71 | This program is distributed in the hope that it will be useful, 72 | but WITHOUT ANY WARRANTY; without even the implied warranty of 73 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 74 | GNU General Public License for more details. 75 | 76 | You should have received a copy of the GNU General Public License 77 | along with this program. If not, see . 78 | -------------------------------------------------------------------------------- /lib/email_modules.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import re 3 | import csv 4 | import smtplib 5 | from email.mime.text import MIMEText 6 | from email.mime.multipart import MIMEMultipart 7 | from email.mime.image import MIMEImage 8 | 9 | import lib.when_things_go_south 10 | 11 | 12 | class MailModule(): 13 | def __init__(self, server, port, auth, username, password): 14 | """ 15 | Tיhis is the main module that is responsible for all the email handeling 16 | It parses the CSV and goes even to the sending of the email and the attaching 17 | of the images to the HTML body. 18 | :param server: The server address, IP or DNS 19 | :param port: Port for connection 20 | :param auth: Boolean of using authentication 21 | :param username: SMTP username 22 | :param password: SMTP password 23 | :return: returns nothing 24 | """ 25 | class Object(object): 26 | """ 27 | General object class to be used later 28 | """ 29 | def __init__(self): 30 | pass 31 | 32 | self._error_handler = lib.when_things_go_south.Error_Handler() # Error event handler 33 | 34 | # Build mail server options 35 | self._mailserver = Object() 36 | self._mailserver_server = server 37 | self._mailserver_port = port 38 | if auth == 1: 39 | self._mailserver_username = username 40 | self._mailserver_password = password 41 | self._mailserver_auth = auth 42 | else: 43 | self._mailserver_auth = 0 44 | 45 | self._folder = "sample_conf/" 46 | self._i = 0 # counter for retrying 47 | self._j = 2 # how many times to try 48 | 49 | def parse_csv(self, filename): 50 | """ 51 | :param filename: Location of CSV file with emails 52 | :return: Array of addresses 53 | """ 54 | try: 55 | listi = [] 56 | f = open(filename, 'rb') 57 | list = csv.reader(f, delimiter=";") 58 | self._error_handler.log_error(0, "Parsed CSV file successfully") 59 | for data in list: 60 | listi.append(data) 61 | return listi 62 | except: 63 | self._error_handler.log_error(3, "Could not read address file. Please verify location entered.") 64 | 65 | 66 | def send_email(self, from_email, rcpt_email, subject, html_body, text_body, attachments, counter, total_len): 67 | """ 68 | :param from_email: The email to send from 69 | :param rcpt_email: Email address to send to 70 | :param subject: Subject of the mail 71 | :param html_body: HTML Body as string 72 | :param text_body: Text body as string 73 | :return: 74 | """ 75 | 76 | # Checking for retry counter 77 | if self._i == self._j: 78 | self._i = 1 79 | return 0 80 | 81 | # self._error_handler.log_error(0, "Building mail") 82 | msg = MIMEMultipart('related') 83 | msg['Subject'] = subject 84 | msg['From'] = from_email 85 | msg['To'] = rcpt_email 86 | msg.preamble = 'This is a multi-part message in MIME format.' 87 | 88 | msgAlternative = MIMEMultipart('alternative') 89 | msg.attach(msgAlternative) 90 | 91 | msgText = MIMEText(text_body) 92 | msgAlternative.attach(msgText) 93 | 94 | # Starting to handle images in file: 95 | html_body = html_body.replace('= max_connections: 172 | time.sleep(5) 173 | 174 | error_handler.log_error(0, "Sending email %s-->%s." % (from_mail, to_mail)) 175 | th = threading.Thread(target=mail_handler.send_email, args=(from_mail, to_mail, subject, html_body, txt_body, attachment_list, i, amount_to_send)) 176 | th.start() 177 | all_threads.append(th) 178 | time.sleep(0.2) 179 | i += 1 180 | 181 | while True: 182 | 183 | try: 184 | count_threads = _countActiveThreads(all_threads) 185 | if len(all_threads) == count_threads: 186 | error_handler.log_error(0, "All threads finished.") 187 | sys.exit(1) 188 | 189 | except KeyboardInterrupt: 190 | error_handler.log_error(3, "Got Keyboard Interrupt.") 191 | sys.exit(1) 192 | 193 | 194 | if __name__ == "__main__": 195 | main(sys.argv[1:]) 196 | --------------------------------------------------------------------------------