Creating a multiport man-in-the-middle network tap

The problem

During red teaming, once physical access has been obtained a typical next step is to connect to the internal network. While many tools (such as cobalt strike) provide excellent logging functionality, other tools are somewhat lacking. A solution to this problem is to locally log all network traffic thereby providing a complete overview of all actions performed on the network.
However, there are some potential issues with this approach:

  • Each time a new connection is established this manual log needs to be initiated
  • The virtual machine needs to be capable of performing said logging (memory, processing power, etc)
  • Each member of the testing team needs to consolidate their network logs daily
  • … it’s annoying

A solution for these issues is to create a separate man-in-the-middle network device which acts as an intermediary logger between testing clients and the network.

Finding appropriate hardware

The most appropriate device is the Banana Pi R1 (BPI-R1) which has a number of hardware features, however the most interesting for our scenario are the 4x Gigabit LAN and 1x Gigabit WAN ports on the board. Additionally, this device can run Debian and it completely configurable.

untitled

Plan of attack

All network interfaces on the BPI-R1 belong to the same physical interface (eth0), while configuration and separation is performed via VLAN tagging. During this post we will create a multiport network tap with the following functionality:

  • Constructs a transparent bridge between a maximum of 3 devices and the internal client network (rather than the hassle of NAT and firewalls)
  • Logs all traffic passed between this bridge to an external encrypted USB drive
  • Facilitates a management interface for ease of use, safer unmounts and debugging

untitled-diagram1
Preparing the operating system

The first step is to download the Bananian distribution and install the operating system to an SD card:

Once installed, insert the SD card into the BPI-R1 and initiate the configuration process. The initial login can be performed using the default root  user with the password of pi. Next update the system and install the required utilities:

Configuring the switch

Once the operating system is installed we can configure the switch. The physical sockets on the device are ordered as follows:

We will be using the following configurations for these ports:

  • Port 2 (VLAN 103); device management interface
  • Ports 1, 0, 4 (VLAN 102); testing devices connecting to the internal client network
  • Port 3 (VLAN 101); direct connection to the internal client network

With ports 1, 0 and 4 being bridged to port 3 thereby giving each device connected to our tap a direct and transparent connection to the internal client network.

This configuration can be achieved using swconfig  by modifying the /etc/network/if-pre-up.d/swconfig  configuration file:

Once the VLAN tags are configured, we can directly configure the network interfaces via /etc/network/interfaces:

After rebooting the device, we can confirm the interfaces and bridges are configured and enabled via ifconfig  and brctl show:

Configuring the management VLAN

For ease of configuration and to facilitate usage on a site without an HDMI monitor and USB keyboard, we can configure a DHCP server on the management interface. Update /etc/default/isc-dhcp-server  with INTERFACES="eth0.103"  and /etc/dhcp/dhcpd.conf with:

Also set up SSH to listen on this interface via /etc/ssh/sshd_config:

Configuring the logging device

While it is possible to store logs on the SD card itself, a more portable and reliable mechanism is to write to an external USB device. Due to the potential of storing sensitive client data, this USB device should be encrypted before writing data:

Conclusion

By following this guide, you will have configured your BPI-R1 to transparently bridge connections between the ‘external’ client network connection on port 3 and any testing devices connected to ports 0, 1 or 4. Networking traffic transferred via this bridge will be stored on an encrypted USB drive protected by a password. Additionally, the device will lease an IP address and is configurable via SSH on the management interface via port 2.

Hack in the Box 2016 – MISC400 Writeup (Part 1)

The challenge

This year the CTF prize sponsors Beyond Security contributed a 400 point challenge:

MISC400 - Above and Beyond
Even chefs need a bit of help sometimes, especially when it comes to IT related subjects.
Luckily, the guys at Beyond Security are always willing to offer a helping hand through their IT blog.
So, if you have any trouble, try the blog at http://145.111.225.63/

The basics

Visiting this blog presented us with the following website:
1

Browsing the website we identified a number of read only, static pages – nothing particularly interesting. However, by viewing the CSS source we identify the following:

So, there must be a form available somewhere, eventually one of the usual suspects gives a hit and we find the admin panel:

http://145.111.225.63/admin/

2

This admin panel requires authentication and the ‘hint’ implies brute forcing is not a good solution. Luckily, the HTML source gives our next hint, backups are stored on the server:

http://145.111.225.63/admin/backup/

Accessing this directory we identify a number of backup archives are accessible:
3

Selecting a backup archive at random, we find it is password protected.

So, let’s try them all:

wget --mirror http://145.111.225.63/admin/backup/
for a in *.tar.gz; do tar -zxvf $a; done

With access to the source code, things start to get interesting:
4

Needle in the haystack

After some precursory browsing of the source code, we find the Session class to be particularly interesting. The Session class is implemented as a singleton and can be directly initialised through the admin directory, via either the index.php or manage.php URLs.

5

This Session class contains (among others) the following functions:

So, we have an arbitrary object injection when the Session object is initialised.

The question becomes, what can we do with this?

Tracing our flows

With these kinds of challenges (i.e. too many lines of source code), I always prefer to draw the call graphs to trace the function flows and thereby gain a clearer understanding of how the application works and which functions we can call.

To prevent unnecessary confusion from the scratchings I made during the CTF, I have reproduced these graphs with the help of Dia.

Below, we can see the function flow (as seen in the source above) to reach the vulnerable unserialise call with our user supplied data:
6

Now we have a clear understanding of how to reach the vulnerable function call, we can start looking for ways to abuse this object injection.

Digging deeper

Via the User class, we identify the following function:

As we can see, an SQL query is generated utilising an escaped version of the User object’s _user variable. However, prior to being inserted into the query, the data is sanitised using PHP’s real_escape_string.

As per the documentation (and assuming ‘regular’ character sets), PHP’s real_escape_string call encodes the following characters:

Characters encoded are NUL (ASCII 0), \n, \r, \, ', ", and Control-Z.

As per the function above, the escaped user input is not enclosed within quotes, therefore this function is still vulnerable to SQL injection attacks.

As an example, we can circumvent the real_escape_string call by creating a User object with a username of ‘1 or sleep(5)‘, which will result in the following SQL query after sanitisation (and will cause the database to sleep for 5 seconds):

SELECT last_login FROM $users_table WHERE user=1 or sleep(5)

The only problem with this path of attack is the rewind function is never called by the application..

Calling uncallable functions

Taking a closer look at the User class, we see it implements the Iterator interface. This interface allows the associated object to be used as part of a foreach loop. To facilitate this, the interface permits custom implementations of the following functions:

As per the PHP documentation, rewind is used to ‘rewind the Iterator to the first element’ and is the first method called at the start of a foreach loop.

With this understanding, the SQL injection can be triggered as follows:

  • Create a User object with a customisable username
  • Utilise this object in a foreach loop to trigger the Iterator (thereby rewinding to the first element)
  • Perform the SQL injection via the insecure real_escape_string sanitisation
  • Extract the administrator’s username and password

As we identified in the code snippet above, the loadSession function is called with our user supplied data as part of a cookie. This function takes the cookie data, base64_decodes it, unserialises it, then finally performs a foreach loop to map the data as part of an array within the object.

Using this information, we can create our own dummy function, which creates a custom serialised object matching the conditions outlined in our above attack:

Setting the $session output as our session cookie and accessing the application will cause the above attack chain to be triggered.

Automating the injection

To make life easier, we can set-up a local proxy:

Then allow sqlmap to perform the heavy lifting:

python sqlmap.py -u "http://127.0.0.1/p.php?1=1" -p1 --level=5 --risk=3 --sql-shell

Once the injection point is identified, we can perform arbitrary SQL commands against the server database, such as extracting the username and password of the admin user:

7

Tracing our flows (again)

Now we have access to both the username and the MD5 password for the admin user of the application. Assuming this MD5 cannot be trivially cracked, we need to find another way to abuse this information.

Via the application there are two ways to attempt to access the administrative panel, either via index.php or manage.php which result in a slightly different authorisation check.

Via index.php we can access functions in the following paths:
8

Via manage.php we can access functions in the following paths:
9

Therefore, it is possible to instantiate our User object and influence the subsequent checkPassword authorisation flow with different boolean values for the _is_session parameter:

Since we already know the MD5 value of the password (via the SQL injection), we want the _is_session parameter to be set to true, thereby skipping the function. We can achieve this condition with a secondary object injection attack:

  • Create a User object with the known valid credentials
  • Access the function flow via manage.php (resulting in the MD5 function not being called)
  • Gain access to administrative functions without cracking the password

We can therefore gain administrative access to the application with the following object:

Setting this as the session cookie in our browser and accessing the administrative interface via manage.php permits us to successfully access the application as an administrator:
10

Back to the source

Now we are administrators, we have access to some interesting new functions:

As an attacker, the download function looks most interesting. A user supplied website can be downloaded via the file_get_contents call, then a regular expression is performed against the content to obtain the website’s title. The website data is then saved in a base64_encoded format in the files directory; all within a native system call.

The output of the website’s data is saved based on the matches array which is a result of the preg_match call:

$matches[0] will contain the text that matched the full pattern, $matches[1] will have the text that matched the first captured parenthesized subpattern, and so on.

As per the function definition and the above implementation, we can control the data stored within $matches[1], by hosting our own webpage with a custom, malicious <title> tag which we can then abuse to break out of the underlying system call.

Remote code execution

As an example, we can ‘break out’ of the system call and perform ls on the local file system via the following:

So, let’s set up a website on our local machine with these malicious <title> tags:

Then download this page via the management application:

11

Finally, we have obtained code execution on the application server.

An obvious flag was not accessible in the webroot, so the next step is to gain a shell on the server (they removed python for some reason?):

Surely we must have earned some points by now right?

Wrong:

ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=85ac919bb9c5311f8bdbcf2e6255814d227d8b76, not stripped

Stay tuned for part 2…

Synology NAS DSM 5.2 Remote Code Execution (RCE)

1

TLDR

RCE in Synology NAS DSM 5.2 due to lack of input sanitisation. RCE triggered indirectly via port forwarding mechanism in the NAS UI.

Getting started

I recently bought a Synology DS416 NAS and noticed during the set-up process you are first required to download the device firmware, which is then flashed to the device via the setup web interface.

Interested in my new devices security, I decided to take a look at the firmware while the system was installing.

Firstly, let’s download the DSM 5.2 firmware (unsure which versions are affected by this vulnerability) from the official Synology download center and identify what we are dealing with:

3

So, the archived DSM_DS416_5644.pat file contains a number of subsidiary files and packages, as well as what looks like a compressed kernel. As the device has no default storage (OS is installed to your separate HDD’s), hda1.tgz immediately looks interesting.

4

So hda1.tgz is another archive, in which we find what looks to be a Linux filesystem.

After some cursory browsing, I noticed some helper php files are in use, so let’s look for some low hanging fruit.

5

PHP 101

Let’s take a look at our first grep result:
cat ./etc/portforward/routerdb/BT/HomeHub2.0/Version8.1.H.G_TypeA/dele_rule.php

As we can see, the php script above appears to contain the following functionality:

  • Take inputs passed to the script
  • Add port forwarding rules via a 3rd party routers web interface
  • Delete port forwarding rules via a 3rd party routers web interface

Interestingly, when a port is deleted the (unsanitised) inputs passed to the script are unsafetly concatenated into a string, then passed to a php system call. If we can control these inputs, we can ‘break out’ of the string and append arbitrary commands to the system call; thereby obtaining RCE on the NAS device.

A first look

The NAS OS has installed by this point, so we can login to the device and take a look around the UI. The UI looks nice and the control panel appears to have many features. One in particular that takes my immediate interest (based on the script above) is ‘External Access’.

6

7

The ‘External Access’ option permits users to configure their router and from within the NAS UI they can perform actions on their router such as adding or deleting forwarded ports. Based on the naming convention of our vulnerable script above, the ‘BT: HomeHUB2.0’ looks promising. By using the ‘custom router account’ we can also identify what appears to be the parameters being passed to the script.

Gaining access

Assuming these parameters are passed directly to the php script with no intermediate sanitisation, we can attempt to modify the php system call by ‘breaking out’ of the unsafetly concatenated string and appending our own arbitrary commands.

In particular, the offending line:

For example, by changing our router password to a\';touch /tmp/test, we should ‘break out’ of the initial command and append touch /tmp/test, which will then also be passed to the system call. Thereby writing the file test to the /tmp directory of the NAS device.

Creating files is well and good, but to make the most of an RCE, we want a revere shell.

For example, using python we can set the following password for the HomeHub2.0 router, which will initiate a reverse shell from the NAS device to our system listening at 192.168.50.1 on TCP port 1234 when the affected call is triggered:

Once the backdoored router password has been added, we simply need to follow the information flow as per the script above to trigger our backdoor and gain a reverse shell:

  • Login to the NAS UI
  • Set up the HomeHub2.0 router with the backdoored password
  • Delete some router rule

Automating the process

Naturally, we want to automate this attack. Unfortunately, the login process to the NAS is not straight forward. When logging in, the username and password (and some additional parameters) are encrypted with both RSA and AES (assumedly to protect against MITM attacks on the network) and then the encrypted data is posted to the server.

Looking at the client side JavaScript files we can identify how this encryption is being performed.

During the login process, the client also submits a request to obtain the server’s public key. As seen in the script above, when a response from the server results in a failure, it’s possible to submit the valid login request in plain text. Therefore we don’t need to re-implement this encryption method, we can instead abuse the insecure fall back.

Firstly, we login to the device:

Secondly, we utilise the valid cookie and custom synology headers to set up the vulnerable router with our backdoored password:

Finally, we trigger the backdoor by removing a port forwarding rule:

Pulling it all together

8

It’s running as root, so that makes privilege escalation a breeze.

Note: The astute readers might notice the vulnerable php script above will only follow the aforementioned data flow when specific patterns are matched (based on the responses received from the routers web interface). Initially, I set up a faux router (based on a real web interface for HomeHub2.0 identified via a Shodan search) to give the correct dummy responses to ensure the data flow was followed as expected. However, this ultimately was not needed to trigger the RCE, so I suspect something even more sinister is going on under the hood; which I did not investigated.

PS: for those of you playing along at home who also want a shell on their NAS. I later found it’s also possible to just enable SSH via the UI 🙂

Edit: At the request of the Synology security team, and to avoid some confusion in the usage of the ‘test’ account in the POC above, this attack can only be performed with a valid administrative account. This clearly affects the likelihood of this attack, however there a few things to consider in this particular case. Firstly, this is not intended functionality by the developers. Secondly, many of these devices are placed on the Internet and only accessible via 1 port (their web interface); so being able to gain a root shell via this method and bypass corporate firewalls/routers/etc is certainly interesting.

Disclosure timeline

13th December 2015 First contact requested information on submitting security vulnerabilities
14th December 2015 Given address of PGP key and security contact email address
14th December 2015 Encrypted information about vulnerability including POST requests for a POC
16th December 2015 Similarly, given address of PGP key and security contact address (from another support address)
16th December 2015 Informed both support addresses that I have received the PGP key and submitted a POC. Requested information on when to expect a response
17th December 2015 Received response that the information was received and had been sent to the appropriate teams for investigation
23rd December 2015 Emailed to request status of the issue
24th December 2015 Received response that the issue is valid and fix will be applied to next DSM release
24th December 2015 Emailed to request an ETA for when the new DSM version will be published
24th December 2015 No schedule for release. Current estimate is ‘some time in February’. Will be notified when the fix is released.
22nd February 2016 Requested whether the fix was shadow-patched in the 5.2-5644 patch released on the 19/2/2016
22nd February 2016 Security team responded that the issue was fixed on January 22nd in version: 5.2-5644 Update 3 under the confusing nomenclature ‘Enhanced network stability when port forwarding is configured.’
22nd February 2016 Blog post published

How to add an XSS-able bot to your CTF

During CTF events it can be interesting to provide XSS challenges for players to solve. This post will discuss automating the process of executing user supplied JavaScript – aka running XSS-able bots within a CTF environment.

PhantomJS is a headless WebKit useful for automating tasks such as functional or display testing. Another use we can adapt PhantomJS for is to visit web pages known to contain user supplied JavaScript and executing these payloads.

Once installed, PhantomJS can be run with user supplied JavaScript.

The example script below will visit a known vulnerable url where CTF players are tasked with exploiting and storing their XSS payload.

The onResourceTimeout and open functions handle pages where user payloads hang and initial access of the url respectively.

You will also see the setTimeout function surrounding phantom.exit(). We found during CTFs a timeout was required to ensure all types of XSS payloads (such as complex payloads containing multiple redirects) were executed by PhantomJS – this value may require tweaking for individual circumstances.

Once the above code has been adapted as required, we can call PhantomJS to XSS itself continuously.

Where the command line options permit the following:

  • ignore-ssl-errors: ignores SSL errors, such as expired or self-signed certificate errors;
  • local-to-remote-url-access: allows local content to access remote URL;
  • web-security: enables web security and forbids cross-domain XHR;
  • ssl-protocol: sets the SSL protocol for secure connections.

As an example, once our XSS bot is executing – PhantomJS should show similar output to the following:
xss-bot

For testing purposes, we can inject the following JavaScript into the vulnerable url PhantomJS is polling:

Setting up some listener on the required port:

Once our PhantomJS XSS bot accesses the vulnerable url and executes our payload, we receive a callback to our listener:
xss-bot2

Hack in the box teaser 2015 : Forensics 1000

In preparation for the Amsterdam Hack in the box CTF this year I took a look at the Forensics 1000 challenge, the description of which you can find below.

Pyongyang
While doing forensics on the HEAVENWEB's server we found a possible ACTOR.
We scanned the interweb for possible traces left by this ACTOR and found an opendir containing HEAVENWEB_SCRAPE.tar.xz [sha256: 6188c47846d306f29315c5df85c507052d20e98e592e08bdf1b35b46c7f84564].
We believe they use a proprietary crypto application only known to this ACTOR.
Are you able to find the flag?
HINT: https://www.youtube.com/watch?v=zuxlLLeKZZ8

The HEAVENWEB_SCRAPE.tar.xz archive contained 2 files:

  • HITB_FOR1000_2015: data
  • HITB2015_FOR1000.dmp: ELF 64-bit LSB core file x86-64, version 1 (SYSV)

Running strings on the HITB2015_FOR1000.dmp file, we see it is an operating system memory dump:

  • /boot/vmlinuz-2.6.38.8-24.rs3.0.i686

Some cursory googling, coupled with the challenge name we identify the operating system as North Korea’s RedStar. Inspecting the HITB_FOR1000_2015 file we find references to a file system as well as some common encryption buzz words.

Bokem

After this quick analysis, we watched the hint video and at around the 12.00 minute mark we see a demonstration of Red Star’s custom encryption application – Bokem.

The video further explains Bokem is native to Red Star and requires root privileges to run.

So, let’s install Red Star and escalate to root:

Let’s fix networking while we are at it:

After a quick sudo –s you should be able to execute Bokem with root privileges.
Redstar

Next we can create our own Bokem container, after which we identified that the challenge is also a Bokem container which we need to access.

After creating our own container, we notice the .bokem3.conf file in our current directory, which contained:

To this configuration file, we can append the container from the challenge to attempt to load it:

Container

Unsurprisingly, the challenge container 93a0c2f4 requires a password.

Given this is a forensics challenge, let’s assume we can find what we need in the challenge. So, let’s mount our own container and dump our machine memory. Assuming you are using a virtual machine, you can do this by simply taking the .vmem file of a snapshot.

So now we have the following:

  • Our container file, to which we know the password;
  • Our memory dump, including a running and decrypted container;
  • The challenge container file, which we want to decrypt and do not know the password;
  • The challenge memory dump, hopefully including a running and decrypted container.

Let’s start by analysing our own container.

Looking at our own container with the name and password of test we notice in the header:
098f6bcd4621d373cade4e832627b4f6test

Which is the md5 of our password, followed by our container name.

Similarly, in the challenge container we notice in the header:
5135c956f0d1dbacaaaabebc7b3a659f93a0c2f4

Which is the md5 of the container password (which we couldn’t crack), followed by the container name.

So we need some more information from the challenge container, let’s take another look at our running container on Red Star.

Dmsetup is a low level logical volume management tool. Dmsetup can be used to create and remove devices, get information about devices or reload tables. Using the dmsetup tool we can gain some information about the currently mapped devices on the system. Luckily, dmsteup also supports displaying of the encryption keys used.

Let’s take a look at our mapped container and its associated encryption key:

So, our encryption key is as follows:
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

If we lazily search for our key in our memory dump we identify an interesting instance:


00000000000000000000000000000000000000000000098f6bcd4621d373
cade4e832627b4f600000000000000000000000000000000000000000000
00000000000000000000b09952080000000081d0869f657d4c88a0ea2f9a
15d05ac51b4fbfa32c820b2b156c5dd1080af0b040000000000000007465
737480000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
00209f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15
b0f00a08609b520800000000000000000000000000000000000000000000

The memory structure identified contains the md5 of our password, as well as our known encryption key some bytes above.

Doing a similar search using the password hash from the challenge, we identify a similar structure in the challenge memory:

0000000000000000000000000000000000005135c956f0d1dbacaaaabebc
7b3a659f0000000000000000000000000000000000000000000000000000
0000000000009078a4090000000030506bbe15ea870ed58408daff8147e4
280080bfad3db06db6e40ce0f40bad4c4000000000000000000000000000
000000000000000000000000000000800000000000000000000000000000
000000000000000000000000000000000000000000000000000000a8be6b
50300e87ea15da0884d5e44781ffbf8000286db03dade00ce4b64cad0bf4
407aa4090000000000000000000000000000000000000000000000000000

Based on our testing container, be6b50300e87ea15da0884d5e44781ffbf8000286db03dade00ce4b64cad0bf4 appears to be the encryption key used by the challenge container.

So, let’s try and mount the challenge container using the above identified key.

We can create a device and specify a mapping table using dmsetup, for this we need the following table parameters:

We can identify most of this information from the mapping settings in our similarly sized container, except the sector offset.

Looking at the challenge container randomness with a hex editor we can identify that the file’s encryption offset appears to start at 0x200 or 512 bytes into the file. For dmsetup a sector is always defined as 512 bytes, so we can identify our new table as follows:

Now we can mount the challenge container:

Once mounted, we identify a single file in the container flag_HITB.txt which contained:

The hash that never was

It’s a familiar situation, you’ve found some vulnerability and popped a limited shell.

You’ve enumerated services, the kernel, applications, plugins, the distribution, jobs, configs, file permissions, etc, etc – but you can’t find a feasible way to escalate your privileges.

I present the following scenario.

There is a web app on the system and you suspect the system root user (who also uses the web app) suffers from the common (and tempting) affliction of password re-use.

You’ve gained access to the database and dumped the web app root user’s password – but can’t crack it.

So, what can we do?

Intercept the password before it’s hashed.

For this demo we will be using a default WordPress install.

Our first step is to find where authentication is handled:
htnw-login

So, we are looking for loginform from assumedly wp-login.php (this is not always so trivial).

htnw-grep

Once we have identified the location of the authentication form, we want to hijack the flow of execution and intercept the password – before it is hashed and compared in the database.

We can achieve this using file_get_contents and raw post data.

The file_get_contents function can be used to include some resource from an arbitrary domain, while php://input allows us to read raw POST data directly from the request body.

By combining these components we can send authentication POST data to some arbitrary site prior to being hashed (note: this code should be placed in the execution flow where authentication is handled):

Next time some user logs in, we will receive the following plain text in our server logs:
htnw-log

The friendly phisherman

While technical resilience to security can be quantitatively tested and evaluated at some point in time. The human factor is often a weak point which is difficult to assess, even more difficult to rely upon (consistently) and can result in compromise even where technical issues have been addressed.

A simple way to test organisational resilience or the effectiveness of staff security awareness training is to perform social engineering exercises. While areas such as physical access, cold drops and phone calls all fall under this remit (among others), this post will focus on a technique with a very low barrier of entry and expertise – phishing.

So, how can we test an organisations resilience to a phishing campaign?

Launch one.

Our friendly (note step 3) phishing campaign will comprise of 3 simple steps:
1. Obtain email addresses for some company (target)
2. Send an email to each address containing a uniquely identifiable URL (phish)
3. Record which users follow the offending link (log)

To record which user has followed our phishing links, we will send URL’s with the following format:
http://yoursite.com/index.php?id={base64_encode(target email)}

Let’s start by setting up our logging script.

Using php we want to unencode the user’s email address from the $_GET['id'] parameter and log the result to a text file:

We will also add some html so as not to arouse too much suspicion:

Any user who follows our link will be served a 404 page (note a 302 would work just as well), while their details are logged in the background:

phish-not-found

Next we need a list of target email addresses for some given domain, for our purposes we will use theharvester tool, which we will call from our python script:

To make our links appear less suspicious we will utilise the free bit.ly url shortening service, (requires account registration to obtain an api key):

Once we have our list of targets we email each user with our enticing phishing email, they will then receive a custom email in their inbox:

phish-email

Each user who follows the link will then have their email address logged:

phish-log

Using this method, we can easily and automatically identify users who are more likely to succumb to a real phishing attack and update staff awareness training as appropriate.

A full python code listing can be found below: