something about the lulz

Hello_Everyone: an open mailing alias misadventure

lol email aliases

One day it had occurred to me that there are a handful of email aliases that are common among both large and small companies. Some of these email aliases are created automatically by the various email vendors.

I got to thinking that it would be interesting to see how many companies expose email aliases like [email protected] or [email protected], and how many hits an attacker would get to mass-mailing these aliases. This is particularly interesting because anyone in the world could email every employee within your company with this alias open. A perfect launch point for phishing or malware distribution campaigns.

For the purpose of our experiment I will be sending a test email with a link in the message to unsubscribe from further communications (which I strictly adhere to). Again, this is all for the purpose of security research and education.

In order to test this I needed:

  • Sample list of company domains to email. Ideally we would need startup-like companies because they often subscribe to a lot of business tools that may produce these aliases.
    • I scraped a small list of 378 companies from a site that indexes startups and looked for startups in seed and series A stage funding to add to my test list because younger companies tend to use business automation tooling that may automatically create default email aliases (I’m guessing).
  • Service to distribute email to the domains
    • Here I decided to go with MailGun because their free tier was all that I needed, and the logs were great (minus the 2 day retention unless you cough up some cash). Oh and don’t forget that you can get booted from this service if you have lots of invalid recipients.
  • Service to intercept mail receipt via a web beacon
    • I fancy me some good ol’ Python Flask for stuff like this.

Beacon Service

Beacon Service

The purpose of the beacon service is to tell us how many people from each domain opened our Mr. Roboto message, and how many of them also hit the unsubscribe link.

In this script the token is the unique hash of the domain name of the company that the request came from. Nginx will proxy requests to this code.

#!/usr/bin/env python3
from flask import Flask, send_file, request
import qrcode
    from BytesIO import BytesIO
except ImportError:
    from io import BytesIO

application = Flask(__name__)

@application.route('/', methods=['GET', 'POST'])
def index():
    if request.args.get('unsubscribe'):
        return 'unsubscribed OK!', 200

    return '', 200

@application.route('/<token>.png', methods=['GET'])
def tokenizer(token):
	img = qrcode.make(str(token))
	img_io = BytesIO(), 'png')
	return send_file(img_io, mimetype='image/png'), 200

if __name__ == '__main__':'', port=8080, debug=False, threaded=True)

Script to send email to target domains

Note that the message that will be received are the lyrics to Mr. Roboto. Here I took input from domains.txt and in a for-loop sent my beacon email to “everyone” and “all” aliases for each domain.

Each message contains these data points:

  • unique 1px by 1px QR code beacon image that is a hash of the company domain name
  • unique unsubscribe email

The idea here is that when employees receive our test email it will hit the beacon service that we created to log the receipt of our message. We also can see how many people clicked the unsubscribe link. All of these events will be logged within the beacon services’ nginx log.

#!/usr/bin/env python3

import os
import requests
from jinja2 import Environment
import hashlib


class Mailer():

    def send_msg(self, recipients, subject, message):
        url = '{}/messages'.format(MAILGUN_DOMAIN)
        auth = ('api', MAILGUN_SECRET)
        for recipient in recipients:
                headers = {'user-agent': ''}
                data = {
                    'from': 'domodomo gato <[email protected]{}>'.format(MAILGUN_DOMAIN),
                    'to': '{}'.format(recipient),
                    'subject': '{}'.format(subject),
                    'html': '{}'.format(message),
      , auth=auth, data=data, headers=headers).raise_for_status()

if __name__ == '__main__':
    mailer = Mailer()
    with open('./domains.txt') as f:
        domains =
    for domain in domains:
        key = hashlib.md5()
        key = key.hexdigest()
        print('sending to {}:{}'.format(key, domain))
        html_template = '''
            <img src="{}.png" style="width: 1px; height: 1px;">
            <p>Domo arigato, Mr. Roboto,</p>
            <p>Mata au hi made</p>
            <p>Domo arigato, Mr. Roboto,</p>
            <p>Himitsu wo shiri tai</p>
            <p>You're wondering who I am (secret secret I've got a secret)</p>
            <p>Machine or mannequin (secret secret I've got a secret)</p>
            <p>With parts made in Japan (secret secret I've got a secret)</p>
            <p>I am the modren man</p>
            <p>I've got a secret I've been hiding under my skin</p>
            <p>My heart is human, my blood is boiling, my brain I.B.M.</p>
            <p>So if you see me acting strangely, don't be surprised</p>
            <p>I'm just a man who needed someone, and somewhere to hide</p>
            <p>To keep me alive, just keep me alive</p>
            <p>Somewhere to hide, to keep me alive</p>
            <p>I'm not a robot without emotions. I'm not what you see</p>
            <p>I've come to help you with your problems, so we can be free</p>
            <p>I'm not a hero, I'm not the saviour, forget what you know</p>
            <p>I'm just a man whose circumstances went beyond his control</p>
            <p>Beyond my control. We all need control</p>
            <p>I need control. We all need control</p>
            <p>I am the modren man (secret secret I've got a secret)</p>
            <p>Who hides behind a mask (secret secret I've got a secret)</p>
            <p>So no one else can see (secret secret I've got a secret)</p>
            <p>My true identity</p>
            <p>Domo arigato, Mr. Roboto, domo...domo</p>
            <p>Domo arigato, Mr. Roboto, domo...domo</p>
            <p>Domo arigato, Mr. Roboto,</p>
            <p>Domo arigato, Mr. Roboto,</p>
            <p>Domo arigato, Mr. Roboto,</p>
            <p>Domo arigato, Mr. Roboto,</p>
            <p>Thank you very much, Mr. Roboto</p>
            <p>For doing the jobs tvhat nobody wants to</p>
            <p>And thank you very much, Mr. Roboto</p>
            <p>For helping me escape just when I needed to</p>
            <p>Thank you, thank you, thank you</p>
            <p>I want to thank you, please, thank you</p>
            <p>The problem's plain to see:</p>
            <p>Too much technology</p>
            <p>Machines to save our lives.</p>
            <p>Machines dehumanize.</p>
            <p>The time has come at last (secret secret I've got a secret)</p>
            <p>To throw away this mask (secret secret I've got a secret)</p>
            <p>Now everyone can see (secret secret I've got a secret)</p>
            <p>My true identity...</p>
            <p>I'm Kilroy! Kilroy! Kilroy! Kilroy!</p>
            <i><a href="{}">unsubscribe</a></i>
        '''.format(key, key)

    mailer.send_msg(['[email protected]{}'.format(domain), '[email protected]{}'.format(domain)], 'Mr Roboto!', html_template)

After blasting off my test emails I started to watch my nginx access logs on the beacon service to make sure I was getting requests. I began to see requests pour in almost immediately. - - [02/Apr/2018:16:23:35 +0000] "GET /d66f4357048adb9f12a7a5d3d5a3c82f.png HTTP/1.1" 200 711 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" - - [02/Apr/2018:16:25:11 +0000] "GET /9f81433411200281be45ba8d4b586499.png HTTP/1.1" 200 700 "-" "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via GoogleImageProxy)" - - [02/Apr/2018:16:25:14 +0000] "GET /9f81433411200281be45ba8d4b586499.png HTTP/1.1" 200 700 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko)" - - [02/Apr/2018:16:25:23 +0000] "GET /a864e1efa8b0e59578bf288915a5411a.png HTTP/1.1" 200 708 "-" "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via GoogleImageProxy)" - - [02/Apr/2018:16:25:23 +0000] "GET /9f81433411200281be45ba8d4b586499.png HTTP/1.1" 200 700 "-" "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via GoogleImageProxy)" - - [02/Apr/2018:16:25:24 +0000] "GET /9f81433411200281be45ba8d4b586499.png HTTP/1.1" 200 700 "-" "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via GoogleImageProxy)" - - [02/Apr/2018:16:25:27 +0000] "GET /a864e1efa8b0e59578bf288915a5411a.png HTTP/1.1" 200 708 "-" "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via GoogleImageProxy)" - - [02/Apr/2018:16:25:34 +0000] "GET /a864e1efa8b0e59578bf288915a5411a.png HTTP/1.1" 200 708 "-" "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via GoogleImageProxy)" - - [02/Apr/2018:16:25:35 +0000] "GET /?unsubscribe=9f81433411200281be45ba8d4b586499 HTTP/1.1" 200 16 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_1_2 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) CriOS/65.0.3325.152 Mobile/15B202 Safari/604.1"

Results of the experiment

Out of 378 companies there there were 50 companies that accepted external email to their [email protected]/[email protected] email aliases, 547 people received the lyrics to Mr. Roboto by opening our message which triggered the web beacon. Out of those 547 requests there only 89 unsubscribe requests.

Here we are able to see number of hits on the tokens per company. Again, the token is the hash for the domain name of the company that we sent the message with the beacon to.

Hits per company

company hits token 103 c413e0de9a877a84f56bb9b0d79f1d71 43 4f0ce4818de26495d77af62a5c540c3a 42 43322ab14bf50cb7e56de6ba79027b74 41 a864e1efa8b0e59578bf288915a5411a 37 5d33571281fb9a59a92900c2b3614931 30 da73388373876dc7c3b7dd725eb2087f 23 510cdbb82737ea3b9c9af89e815f4996 20 fb9155729c939dbf2cafa747dd5ac454 19 2ce8c0a53436a25c2800a2d008da3a39 15 f90e0eb6eaff25a15a0b36ce0bc2dc23 15 9f81433411200281be45ba8d4b586499 15 026caddc7860684d00beec422f21e1b4 13 37070396b502e6365214f872e7589376 12 3dcda3390107250aed6da92b87324c56 10 c97fbad1c01039e4f440b25ffe799bed 9 a1bad8d308ec01955634abb9e119f389 8 5a014c50748cd5485f69f4bcac8e46e1 8 215de6fc60407290183bb4361222402f 7 ce89915657b087f5a4591590ec2a4370 7 5d600c13b7dab00709a5f77faad07160 7 37bf796720647d8657eba014db252d57 5 dee872c35fd9497c00ef637c1fb4adb2 5 a88cd9709653d30d20fd049be6365748 4 e8274d9a6904c9af5037d248734d3f0b 4 6348d794d9b23e3af3ac34ebd88dc300 3 aeacacbbb94efa20ca8a584c52e8e378 3 a1332a3301f5206fa772625d4345ff20 3 1a2f6d2a861b86d7c9a1d0e618d399e3 2 c18798f23cafad39906c768dfbfac697 2 a97941336c05d3d63f7c0e8aae6af102 2 929275e742b3c13775bc4363407cea8a 1 e76a6b7c0b7d11395636dd7a14047979 1 e27f2323d0819cffe50d2107a7c58d73 1 dbddd778f9257f7181a7b0afd44867ae 1 d84435b5b2ef59a4f675ef13cf7b6b82 1 d66f4357048adb9f12a7a5d3d5a3c82f 1 d63c7f27241936ffe008a56163de1502
INVALID_TOKEN 1 c687100b1b811b6edb38e38e4a147849 1 8bc610db94787c7ff422f69092933538 1 860444762db7f136048ada653ada862e 1 70203d8ce884bc853b4f591953330785 1 6b1b4293ba9a74bbff3fe78cd5fd5efb 1 50c488db16f87f84282d04aecd737fbb 1 470acc8324c7955550b2a81b2f746546 1 3f14fcc448499972a81a70dc35de7e46 1 3c4fb54332b43ceca08bd21c276c4aa5 1 336b08ea336cf0f7a17459a9c096a9b8 1 31b558e4cb866609cc2ecda1a955dae0 1 1d35ccce7afea168f2be8dd11f791414

unsubscribe requests

company unsubscribe requests token 12 f90e0eb6eaff25a15a0b36ce0bc2dc23 11 43322ab14bf50cb7e56de6ba79027b74 9 c97fbad1c01039e4f440b25ffe799bed 8 c413e0de9a877a84f56bb9b0d79f1d71 5 a864e1efa8b0e59578bf288915a5411a 5 9f81433411200281be45ba8d4b586499 3 4f0ce4818de26495d77af62a5c540c3a 2 fb9155729c939dbf2cafa747dd5ac454 2 da73388373876dc7c3b7dd725eb2087f 2 a88cd9709653d30d20fd049be6365748 2 5d33571281fb9a59a92900c2b3614931 2 3dcda3390107250aed6da92b87324c56 2 026caddc7860684d00beec422f21e1b4 1 e76a6b7c0b7d11395636dd7a14047979 1 ce89915657b087f5a4591590ec2a4370 1 c18798f23cafad39906c768dfbfac697 1 a6815b77f56df9c5af975c15f2fe9864 1 a1bad8d308ec01955634abb9e119f389 1 5d600c13b7dab00709a5f77faad07160 1 3f14fcc448499972a81a70dc35de7e46

Data art

Who doesn’t like data?


full size


full size


full size

Don’t let strangers talk to you

It might be a good idea to monitor your email aliases to ensure some service that your company subscribes to does not create default aliases that allow strangers to email everyone in your company. You could end up having a bad time.