What You’ll Learn

I’m going to quickly go through the process of setting up GoPhish and show you how we evade defenders to increase the success rate of our phishing campaigns.


Phishing is getting harder and harder. Landing in a user’s inbox, creating the pretext, and setting up your infrastructure in a way that doesn’t get you caught isn’t as easy as it used to be.

We want to build infrastructure that’s long-lasting, blocks security solutions, and appears legitimate to users. That’s a huge task. So, let’s start by focusing on the tool almost all of us use for phishing engagements: GoPhish.

We’ll review how to:

  • Look for GoPhish indicators that trigger a response from security controls
  • Manually modify GoPhish to evade security controls
  • Automate the process of evading security controls with GoPhish

Evading controls with GoPhish

Believe it or not, out of the box, Gophish will tip your hand to security controls and defenders by design. Several aspects of the tool reveal to security controls that emails a user received came from a Gophish server. On top of this, the phishing site your users visit further reveals your intentions. It does so using easily fingerprinted HTTP headers and 404 pages.

Hey! GoPhish sent this!

Let’s start by looking at the GoPhish source code. If you grep the source code for the value X-GoPhish, you will be greeted with the following:

Gophish Source Code

As you can see, email sending utilities within the project append the header listed below to your emails when they go out:

  • X-Gophish-Contact
  • X-Gophish-Signature

This is a big no-no, as it allows security controls to fingerprint your email as malicious easily. With that, we need to change this header to look a little more normal. The easiest way to do this on the fly is to run the following command in the root directory of a freshly cloned GoPhish repository:

find . -type f -exec sed -i.bak 's/X-Gophish-Contact/X-Contact/g' {} +
find . -type f -exec sed -i.bak 's/X-Gophish-Signature/X-Signature/g' {} +

Don't ignore your servers name

We still have a couple more changes to make before we can continue. In the file config.go there is a Server variable set to “gophish” out of the box. This is shown in the screenshot below:

Config.go Server Variable gophish

So what is the best way to change this? We don’t want to spoof any mail client or server because it might tip our hand (Trust me on this!). So instead, let’s opt to set the value to IGNORE.

This comes courtesy of the great ired.team blog article linked below:

SMTP Forwarders / Relays
SMTP Redirector + Stripping Email Headers. Set up a mail server that will be later used as an SMTP relay server. First off, a new Ubuntu droplet was created in Digital Ocean:


I did this using vim, but you can also use sed to get the job done.

SMTP Forwarders / Relays Using vim

404, FOUND.

We need to also change the 404 page displayed to users when they don’t have a valid URL sent during our campaign. We can additionally make changes to the response headers returned when visiting the phishing site itself. This is optional, as we should use a reverse proxy to shield our phishing infrastructure.

Why are we doing this? A great article on the Insomniac blog about fingerprinting GoPhish servers spells it out wonderfully. One of the best ways for catching a live GoPhish instance is the 404 page and headers sent along with it. They’re fairly unique in combination. You can read more using the link below:

Identifying Gophish Servers
Alain Homewood Senior Security Consultant - Alain shares a methodology for discovering and identifying Gophish deployments in the wild. How easy is your Gophish


Making this change is a little more difficult than you would expect. I was inspired to flesh this out after reading edermi’s article on modding GoPhish and seeing some of the challenges that exist. Edermi already did the groundwork needed to add a custom 404 page to GoPhish. With this, we can simply import their changes right into our modified version of the tool. Please see the article below for some more context.

Modding Gophish
TL;DR: I'll shine a light on Gophish and how to modify it to change behavior or introduce/remove functionality. At the end of this post, you'll know how to host custom 404 pages in


In the referenced article, edermi does all the heavy lifting for us. To make this simple, replace the phish.go file in your base GoPhish repository with the file linked below.

Open-Source Phishing Toolkit. Contribute to edermi/gophish_mods development by creating an account on GitHub.


Once you’ve copied the version of the file created by edermi to your repository, create a custom 404 page in the template directory at the root of your GoPhish repository. For example, this is my current 404.html file.

404 File

Modify this page to fit your pretext and headers.

Your headers are horrible

You may want to make some additional changes based on your use case. For example, modifying the headers returned by the server is easy by making additions to the code on line 86 of the phish.go file you just added to the repository. This is my current setup:

Modifying GoPhish Headers

Note that you should use a reverse proxy in front of your GoPhish server, regardless. Only really make this change as an extra precaution or as needed.

Getting rid of rid

Every phishing link you send includes an easily identifiable uncommon parameter in the URL. The link is used to track clicks during your campaign. An example of a URL sent to users in phishing emails is listed below:


That rid parameter screams GoPhish and is so easy to flag on. Changing this is simple. In the file, campaign.go in the GoPhish repository, the parameter is defined on line 130. Change it to something benign that’s common in marketing emails. Use the following command to make the change:

sed -i 's/const RecipientParameter = "rid"/const RecipientParameter = "keyname"/g' models/campaign.go

We opted to use the variable keyname here, but you can use whatever you want. Your links will now include the keyname variable as opposed to rid.


What we did

So what did we change to avoid security controls?

  • Modified email headers sent by default to not include the word “GoPhish.”
  • Modified the server name sent in browser and with emails to the value “IGNORE”
  • Changed our 404.html page to be a bit more complex and harder to fingerprint
  • Changed web server headers to appear real as opposed to the simple defaults included with GoPhish
  • Changed the tracking parameter included in phishing links to track user clicks

These changes aren’t going to bypass everything, but they’ll go a long way in getting your phishing email into a user’s inbox.


This is all awesome, but we pentesters want to make this process much faster. So let’s automate the process. Luckily, I have a new repository available on GitHub that builds a Docker image with all these changes built right in.

Hiding GoPhish from the boys in blue! See my blog article linked below for details on all the changes made during compilation of GoPhish before using!


Do the following to get the repository up and running:

  1. Clone the repository and build the container

    git clone https://github.com/puzzlepeaches/sneaky_gophish && \
      cd sneaky_gophish && \
      docker build -t sneaky_gophish .
  2. Run the container with the following command

    docker run -itd --name sneaky_gophish -p 3333:3333 -p 8080:8080 sneaky_gophish
  3. Get the admin password

    docker logs sneaky_gophish | grep password

So what does this Dockerfile actually do? It’s nearly identical to the upstream GoPhish repository with all the changes listed above included – before the compilation of the GoPhish binary. The core of these changes starts around line 48 in the Dockerfile.

# Stripping X-Gophish 
USER root
RUN sed -i 's/X-Gophish-Contact/X-Contact/g' models/email_request_test.go
RUN sed -i 's/X-Gophish-Contact/X-Contact/g' models/maillog.go
RUN sed -i 's/X-Gophish-Contact/X-Contact/g' models/maillog_test.go
RUN sed -i 's/X-Gophish-Contact/X-Contact/g' models/email_request.go

# Stripping X-Gophish-Signature
RUN sed -i 's/X-Gophish-Signature/X-Signature/g' webhook/webhook.go

# Changing server name
RUN sed -i 's/const ServerName = "gophish"/const ServerName = "IGNORE"/' config/config.go

# Changing rid value
RUN sed -i 's/const RecipientParameter = "rid"/const RecipientParameter = "keyname"/g' models/campaign.go

I have some additional caveats listed in the GitHub repository. They’re also listed below:

  • This container exposes port 8080 for the phishing page sent to users. This means we aren’t using SSL out of the box for the phishing page we deliver to users. Instead, I recommend using a reverse proxy and robust redirect rules to protect your GoPhish instance and thwart defenders (More on this at a later date).
  • The changes to this repository aren’t the end-all for detection capabilities. There is more here that should be done before using it in a real-world engagement.

Wrap up

The container I built isn’t the miracle cure for evasion, but it’s a good start. It’s a bad idea to use any of your tooling out of the box. You’ve heard this before, but I want to reiterate how important it is to understand how your tools work.

The GoPhish authors include indicators to weed out unsophisticated attackers only trying to steal someone’s Netflix password. That isn’t the level of value we should show our clients. Highly skilled attackers are making these changes, and they’re the ones your customers need to worry about.

You can make additional changes to evade controls and also make your phishing campaigns easier to deploy. This is an exercise for the reader, however.

Pull requests to the repository I created are welcome. The core of changes made are fairly simple and could easily be expanded upon and made a bit more dynamic to continue working after changes have been made to the upstream GitHub repository.