├── .gitignore ├── LICENSE ├── README.md ├── blackcert.conf ├── blackcert.py ├── docs ├── blackcert_logo.png └── blackcert_slack_alert.png ├── modules └── confusables.py ├── requirements.txt └── suspicious.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](docs/blackcert_logo.png) 2 | # blackcert 📓 3 | Blackcert monitors [Certificate Transparency Logs](https://en.wikipedia.org/wiki/Certificate_Transparency) for a keyword. Blackcert collects any certificate changes for this keyword and also checks if any domain changes with that keyword look like a phishing domain. 4 | 5 | # Purpose 6 | Developed to proactively monitor for actors registering certificates for a domain for phishing purposes. Although I have found it useful/used for: 7 | 8 | * monitoring certificate changes for your company, for example, configure keyword `splunk` 9 | * monitoring/enumerating customers for companies that use SAN, for example seeing all customers registered by fastly or medium, since they add a new domain alias to their shared certificate for new customers. configure `medium, fastly` 10 | * monitoring for fraud sites that relate to topical things, for example, all domains that have registered for a certificate with the words configure `coronavirus, covid, chloroquine`. 11 | 12 | # Installation 13 | 14 | 1. clone project: `git clone https://github.com/d1vious/blackcert.git && cd blackcert` 15 | 2. install depencecies in virtualenvironment: `pip install virtualenv && virtualenv -p python3 venv && source venv/bin/activate && pip install -r requirements.txt` 16 | 3. configure keywords to monitor and slack webhook optionally by editing [blackcert.conf](https://github.com/d1vious/blackcert/blob/master/blackcert.conf) 17 | 18 | # Run 19 | 20 | `python blackert.py` 21 | 22 | all results will be printed and also written to [results.log](#results-log) by default. 23 | 24 | # Usage 25 | 26 | ``` 27 | usage: blackcert.py [-h] [-c CONFIG] [-o OUTPUT] [-v] 28 | 29 | starts listening for newly registered certificates and sends slack alerts when 30 | it matches 31 | 32 | optional arguments: 33 | -h, --help show this help message and exit 34 | -c CONFIG, --config CONFIG 35 | path to the configuration file of blackcert 36 | -o OUTPUT, --output OUTPUT 37 | path to a JSON log file of the matches 38 | -v, --version shows current blackcert version 39 | ``` 40 | 41 | # Slack Alerts 42 | I recommend creating a bot channel eg. blackcert-bot and then creating a webhook for it. Below is an example message for it. Protip inviting the SOC into a bot channel like this will help them understand how certificates are being used in the org. 😉 43 | 44 | ![](docs/blackcert_slack_alert.png) 45 | 46 | # Phishing Score Calculation 47 | The score calculation is graciously borrowed from [Phishing Catcher](phishing_catcher) which was an inspiration for this project. It calculates the score using the following workflow: 48 | 49 | 1. adds 20 points if it has a [suspicios TLPs](https://github.com/d1vious/blackcert/blob/master/suspicious.yaml#L137) 50 | 2. Add points for [higher entropy](https://github.com/d1vious/blackcert/blob/master/blackcert.py#L79) 51 | 3. Adds 10 points for [fake](https://github.com/d1vious/blackcert/blob/master/blackcert.py#L87) .com .net .org, for example `*.com-account-management.info` 52 | 4. Add points for [suspecios keywords](https://github.com/d1vious/blackcert/blob/master/suspicious.yaml#L1). 53 | 5. Adds points for [too many](https://github.com/d1vious/blackcert/blob/master/blackcert.py#L102) `-` character in the domain, for example, `www.paypal-datacenter.com-acccount-alert.com` 54 | 6. Adds points for [deeply nested](https://github.com/d1vious/blackcert/blob/master/blackcert.py#L106) domains, for example, `www.paypal.com.security.accountupdate.gq` 55 | 56 | # Results.json 57 | Below is an example of how objects are saved in results.json. Protip, indexing these in a system like Splunk or ES will allow you to create a nice histogram on certificate changes for your organization, a competitor, or even mine the data for enumeration purposes. 58 | 59 | ``` 60 | { 61 | "timestamp": "2020-03-26T03:26:58.097680", 62 | "fingerprint": "51635745d6b7da0914196e6015023bac67351e86", 63 | "domain": "woodsnap.com", 64 | "subject": "/C=US/CN=sni.cloudflaressl.com/L=San Francisco/O=Cloudflare, Inc./ST=CA", 65 | "CA": [ 66 | "CloudFlare Inc ECC CA-2", 67 | "Baltimore CyberTrust Root" 68 | ], 69 | "score": 29 70 | } 71 | ``` 72 | -------------------------------------------------------------------------------- /blackcert.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | keywords = covid, coronavirus, corona 3 | log_path = blackcert.log 4 | certstream_url = wss://certstream.calidog.io 5 | 6 | # slack config 7 | [slack] 8 | hook = 9 | alert_score_threshold = 10 10 | -------------------------------------------------------------------------------- /blackcert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import configparser 4 | import logging 5 | import os 6 | import sys 7 | import time 8 | import certstream 9 | import argparse 10 | import json 11 | import datetime 12 | import requests 13 | import math 14 | import yaml 15 | import re 16 | from Levenshtein import distance 17 | from tld import get_tld 18 | from pathlib import Path 19 | from modules.confusables import unconfuse 20 | 21 | 22 | VERSION = '1' 23 | 24 | 25 | def setup_logging(LOG_PATH,LOG_LEVEL): 26 | """Creates a shared logging object for the application""" 27 | # create logging object 28 | logger = logging.getLogger('blackcert') 29 | logger.setLevel(LOG_LEVEL) 30 | # create a file and console handler 31 | fh = logging.FileHandler(LOG_PATH) 32 | fh.setLevel(LOG_LEVEL) 33 | ch = logging.StreamHandler() 34 | ch.setLevel(LOG_LEVEL) 35 | # create a logging format 36 | formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s') 37 | fh.setFormatter(formatter) 38 | ch.setFormatter(formatter) 39 | # add the handlers to the logger 40 | logger.addHandler(fh) 41 | logger.addHandler(ch) 42 | return logger 43 | 44 | # shamelessly stolen from https://github.com/x0rz/phishing_catcher/blob/master/catch_phishing.py 45 | # credits to @x0rz 46 | 47 | def entropy(string): 48 | """Calculates the Shannon entropy of a string""" 49 | prob = [ float(string.count(c)) / len(string) for c in dict.fromkeys(list(string)) ] 50 | entropy = - sum([ p * math.log(p) / math.log(2.0) for p in prob ]) 51 | return entropy 52 | 53 | def score_domain(domain): 54 | """Score `domain`. 55 | The highest score, the most probable `domain` is a phishing site. 56 | Args: 57 | domain (str): the domain to check. 58 | Returns: 59 | int: the score of `domain`. 60 | """ 61 | 62 | score = 0 63 | for t in suspicious['tlds']: 64 | if domain.endswith(t): 65 | score += 20 66 | 67 | # Remove initial '*.' for wildcard certificates bug 68 | if domain.startswith('*.'): 69 | domain = domain[2:] 70 | 71 | # Removing TLD to catch inner TLD in subdomain (ie. paypal.com.domain.com) 72 | try: 73 | res = get_tld(domain, as_object=True, fail_silently=True, fix_protocol=True) 74 | domain = '.'.join([res.subdomain, res.domain]) 75 | except Exception: 76 | pass 77 | 78 | # Higer entropy is kind of suspicious 79 | score += int(round(entropy(domain)*10)) 80 | 81 | # Remove lookalike characters using list from http://www.unicode.org/reports/tr39 82 | domain = unconfuse(domain) 83 | 84 | words_in_domain = re.split("\W+", domain) 85 | 86 | # ie. detect fake .com (ie. *.com-account-management.info) 87 | if words_in_domain[0] in ['com', 'net', 'org']: 88 | score += 10 89 | 90 | # Testing keywords 91 | for word in suspicious['keywords']: 92 | if word in domain: 93 | score += suspicious['keywords'][word] 94 | 95 | # Testing Levenshtein distance for strong keywords (>= 70 points) (ie. paypol) 96 | for key in [k for (k,s) in suspicious['keywords'].items() if s >= 70]: 97 | # Removing too generic keywords (ie. mail.domain.com) 98 | for word in [w for w in words_in_domain if w not in ['email', 'mail', 'cloud']]: 99 | if distance(str(word), str(key)) == 1: 100 | score += 70 101 | 102 | # Lots of '-' (ie. www.paypal-datacenter.com-acccount-alert.com) 103 | if 'xn--' not in domain and domain.count('-') >= 4: 104 | score += domain.count('-') * 3 105 | 106 | # Deeply nested subdomains (ie. www.paypal.com.security.accountupdate.gq) 107 | if domain.count('.') >= 3: 108 | score += domain.count('.') * 3 109 | 110 | return score 111 | 112 | def parse_configs(CONFIG_PATH): 113 | config = configparser.ConfigParser() 114 | config.read(CONFIG_PATH) 115 | settings = {} 116 | 117 | for section in config.sections(): 118 | for key in config[section]: 119 | try: 120 | settings[key] = perform_lookup(key, config.get(section, key)) 121 | except Exception as e: 122 | print("ERROR - with configuration file at {0} failed with error {1}".format(CONFIG_PATH, e)) 123 | sys.exit(1) 124 | return settings 125 | 126 | 127 | def perform_lookup(config_key, config_value): 128 | if config_key == 'keywords': 129 | keywords = [e.strip() for e in config_value.split(',')] 130 | return keywords 131 | else: 132 | return config_value 133 | 134 | 135 | def process_message(domain, message): 136 | result = {} 137 | result['timestamp'] = str(datetime.datetime.utcnow().isoformat()) 138 | result['fingerprint'] = message['data']['leaf_cert']['fingerprint'].replace(":", "").lower() 139 | result['domain'] = domain 140 | result['subject'] = message['data']['leaf_cert']['subject']['aggregated'] 141 | result['CA'] = [c['subject']['CN'] for c in message['data']['chain']] 142 | return result 143 | 144 | 145 | def sendslack(slackhook, domain, result): 146 | """Send message to Slack""" 147 | 148 | slack_data = {"blocks": [{"type": "section", 149 | "text": {"type": "mrkdwn", "text":":lock_with_ink_pen: :oncoming_police_car: :zap: *Certificate changes have been detected for: {0}*\n see details in ** :flashlight:".format(domain, result['fingerprint'])}}, 150 | {"type": "section", "fields": [{"type": "mrkdwn","text": "*Domain:*\n{0}".format(domain)}, 151 | {"type": "mrkdwn", "text": "*Score:*\n {0}".format(result['score'])}, 152 | {"type": "mrkdwn","text": "*CA:*\n{0}".format(result['CA'])}, 153 | {"type": "mrkdwn","text":"*Subject Line:*\n{0}".format(result['subject'])}]}, 154 | {"type": "context", "elements": [{"type": "mrkdwn", "text": "*Author:* "}]}]} 155 | 156 | response = requests.post( 157 | slackhook, data=json.dumps(slack_data), 158 | headers={'Content-Type': 'application/json'} 159 | ) 160 | 161 | if response.status_code != 200: 162 | raise ValueError( 163 | 'Request to slack returned an error %s, the response is:\n%s' 164 | % (response.status_code, response.text)) 165 | 166 | def write_results(result): 167 | try: 168 | with open(OUTPUT_PATH, 'a') as outfile: 169 | json.dump(result, outfile) 170 | except Exection as e: 171 | log.error("writing result file: {0}".format(str(e))) 172 | 173 | 174 | def callback(message, context): 175 | #log.info("Message -> {}".format(message)) 176 | keywords = config['keywords'] 177 | if message['message_type'] == "heartbeat": 178 | return 179 | 180 | if message['message_type'] == "certificate_update": 181 | all_domains = message['data']['leaf_cert']['all_domains'] 182 | 183 | for domain in all_domains: 184 | for keyword in keywords: 185 | if domain.find(keyword) != -1: 186 | result = process_message(domain, message) 187 | score = score_domain(domain) 188 | log.info("matched domain: {0} for keyword: {1} score: {2}".format(domain, keyword, score)) 189 | result['score'] = score 190 | # only high scores we alert on 191 | if result['score'] >= int(config['alert_score_threshold']): 192 | log.info("slack alert score threshold reached for domain: {0} with score: {2}".format(domain, keyword, score)) 193 | sendslack(config['hook'], domain, result) 194 | write_results(result) 195 | 196 | def on_open(instance): 197 | # Instance is the CertStreamClient instance that was opened 198 | print("Connection successfully established!") 199 | 200 | def on_error(instance, exception): 201 | # Instance is the CertStreamClient instance that barfed 202 | print("Exception in CertStreamClient! -> {0}".format(exception)) 203 | 204 | 205 | if __name__ == "__main__": 206 | # grab arguments 207 | parser = argparse.ArgumentParser(description="starts listening for newly registered certificates and sends slack alerts when it matches") 208 | parser.add_argument("-c", "--config", required=False, default="blackcert.conf", 209 | help="path to the configuration file of blackcert") 210 | parser.add_argument("-o", "--output", required=False, default="results.log", 211 | help="path to a JSON log file of the matches") 212 | parser.add_argument("-v", "--version", default=False, action="store_true", required=False, 213 | help="shows current blackcert version") 214 | 215 | # parse them 216 | args = parser.parse_args() 217 | ARG_VERSION = args.version 218 | config = args.config 219 | OUTPUT_PATH = args.output 220 | 221 | print(""" 222 | _ _ _ _ 223 | | | | | | | | | 224 | | |__ | | __ _ ___| | _____ ___ _ __| |_ 225 | | '_ \| |/ _` |/ __| |/ / __/ _ \ '__| __| 226 | | |_) | | (_| | (__| < (_| __/ | | |_ 227 | |_.__/|_|\__,_|\___|_|\_\___\___|_| \__| 228 | """) 229 | 230 | # parse config 231 | blackcert_config = Path(config) 232 | if blackcert_config.is_file(): 233 | print("blackcert {1} is using config at path {0}".format(blackcert_config, str(VERSION))) 234 | configpath = str(blackcert_config) 235 | else: 236 | print("ERROR: blackcert failed to find a config file at {0} or {1}..exiting".format(blackcert_config)) 237 | sys.exit(1) 238 | 239 | # Parse config 240 | config = parse_configs(configpath) 241 | log = setup_logging(config['log_path'], 'INFO') 242 | 243 | if ARG_VERSION: 244 | log.info("version: {0}".format(VERSION)) 245 | sys.exit(0) 246 | log.info("alerting to keywords: {0}".format(config['keywords'])) 247 | 248 | #load suspicious words: 249 | suspicious_yaml = os.path.dirname(os.path.realpath(__file__)) + '/suspicious.yaml' 250 | with open(suspicious_yaml, 'r') as f: 251 | suspicious = yaml.safe_load(f) 252 | # certstream.listen_for_events(callback, on_open=on_open, on_error=on_error, url=config['certstream_url']) 253 | certstream.listen_for_events(callback, url=config['certstream_url']) 254 | -------------------------------------------------------------------------------- /docs/blackcert_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josehelps/blackcert/d4afef568a00ace2522d3b91a66253b25494e919/docs/blackcert_logo.png -------------------------------------------------------------------------------- /docs/blackcert_slack_alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josehelps/blackcert/d4afef568a00ace2522d3b91a66253b25494e919/docs/blackcert_slack_alert.png -------------------------------------------------------------------------------- /modules/confusables.py: -------------------------------------------------------------------------------- 1 | confusables = { 2 | u'\u2460': '1', 3 | u'\u2780': '1', 4 | u'\U0001D7D0': '2', 5 | u'\U0001D7DA': '2', 6 | u'\U0001D7E4': '2', 7 | u'\U0001D7EE': '2', 8 | u'\U0001D7F8': '2', 9 | u'\uA75A': '2', 10 | u'\u01A7': '2', 11 | u'\u03E8': '2', 12 | u'\uA644': '2', 13 | u'\u14BF': '2', 14 | u'\uA6EF': '2', 15 | u'\u2461': '2', 16 | u'\u2781': '2', 17 | u'\u01BB': '2', 18 | u'\U0001F103': '2.', 19 | u'\u2489': '2.', 20 | u'\U0001D206': '3', 21 | u'\U0001D7D1': '3', 22 | u'\U0001D7DB': '3', 23 | u'\U0001D7E5': '3', 24 | u'\U0001D7EF': '3', 25 | u'\U0001D7F9': '3', 26 | u'\U00016F3B': '3', 27 | u'\U000118CA': '3', 28 | u'\uA7AB': '3', 29 | u'\u021C': '3', 30 | u'\u01B7': '3', 31 | u'\uA76A': '3', 32 | u'\u2CCC': '3', 33 | u'\u0417': '3', 34 | u'\u04E0': '3', 35 | u'\u0AE9': '3', 36 | u'\u2462': '3', 37 | u'\u0498': '3', 38 | u'\U0001F104': '3.', 39 | u'\u248A': '3.', 40 | u'\U0001D7D2': '4', 41 | u'\U0001D7DC': '4', 42 | u'\U0001D7E6': '4', 43 | u'\U0001D7F0': '4', 44 | u'\U0001D7FA': '4', 45 | u'\U000118AF': '4', 46 | u'\u13CE': '4', 47 | u'\u2463': '4', 48 | u'\u2783': '4', 49 | u'\u1530': '4', 50 | u'\U0001F105': '4.', 51 | u'\u248B': '4.', 52 | u'\U0001D7D3': '5', 53 | u'\U0001D7DD': '5', 54 | u'\U0001D7E7': '5', 55 | u'\U0001D7F1': '5', 56 | u'\U0001D7FB': '5', 57 | u'\U000118BB': '5', 58 | u'\u01BC': '5', 59 | u'\u2464': '5', 60 | u'\u2784': '5', 61 | u'\U0001F106': '5.', 62 | u'\u248C': '5.', 63 | u'\U0001D7D4': '6', 64 | u'\U0001D7DE': '6', 65 | u'\U0001D7E8': '6', 66 | u'\U0001D7F2': '6', 67 | u'\U0001D7FC': '6', 68 | u'\U000118D5': '6', 69 | u'\u2CD2': '6', 70 | u'\u0431': '6', 71 | u'\u13EE': '6', 72 | u'\u2465': '6', 73 | u'\u2785': '6', 74 | u'\U0001F107': '6.', 75 | u'\u248D': '6.', 76 | u'\U0001D212': '7', 77 | u'\U0001D7D5': '7', 78 | u'\U0001D7DF': '7', 79 | u'\U0001D7E9': '7', 80 | u'\U0001D7F3': '7', 81 | u'\U0001D7FD': '7', 82 | u'\U000104D2': '7', 83 | u'\U000118C6': '7', 84 | u'\u2466': '7', 85 | u'\u2786': '7', 86 | u'\U0001F108': '7.', 87 | u'\u248E': '7.', 88 | u'\U0001E8CB': '8', 89 | u'\U0001D7D6': '8', 90 | u'\U0001D7E0': '8', 91 | u'\U0001D7EA': '8', 92 | u'\U0001D7F4': '8', 93 | u'\U0001D7FE': '8', 94 | u'\U0001031A': '8', 95 | u'\u0B03': '8', 96 | u'\u09EA': '8', 97 | u'\u0A6A': '8', 98 | u'\u0223': '8', 99 | u'\u0222': '8', 100 | u'\u2467': '8', 101 | u'\u2787': '8', 102 | u'\U0001F109': '8.', 103 | u'\u248F': '8.', 104 | u'\U0001D7D7': '9', 105 | u'\U0001D7E1': '9', 106 | u'\U0001D7E4': '9', 107 | u'\U0001D7EB': '9', 108 | u'\U0001D7F5': '9', 109 | u'\U0001D7FF': '9', 110 | u'\U000118CC': '9', 111 | u'\U000118AC': '9', 112 | u'\U000118D6': '9', 113 | u'\u0A67': '9', 114 | u'\u0B68': '9', 115 | u'\u09ED': '9', 116 | u'\u0D6D': '9', 117 | u'\uA76E': '9', 118 | u'\u2CCA': '9', 119 | u'\u0967': '9', 120 | u'\u06F9': '9', 121 | u'\u2468': '9', 122 | u'\u2788': '9', 123 | u'\U0001F10A': '9.', 124 | u'\u2490': '9.', 125 | u'\U0001D41A': 'a', 126 | u'\U0001D44E': 'a', 127 | u'\U0001D482': 'a', 128 | u'\U0001D4B6': 'a', 129 | u'\U0001D4EA': 'a', 130 | u'\U0001D51E': 'a', 131 | u'\U0001D552': 'a', 132 | u'\U0001D586': 'a', 133 | u'\U0001D5BA': 'a', 134 | u'\U0001D5EE': 'a', 135 | u'\U0001D622': 'a', 136 | u'\U0001D656': 'a', 137 | u'\U0001D68A': 'a', 138 | u'\U0001D6C2': 'a', 139 | u'\U0001D6FC': 'a', 140 | u'\U0001D736': 'a', 141 | u'\U0001D770': 'a', 142 | u'\U0001D7AA': 'a', 143 | u'\U0001D400': 'a', 144 | u'\U0001D434': 'a', 145 | u'\U0001D468': 'a', 146 | u'\U0001D49C': 'a', 147 | u'\U0001D4D0': 'a', 148 | u'\U0001D504': 'a', 149 | u'\U0001D538': 'a', 150 | u'\U0001D56C': 'a', 151 | u'\U0001D5A0': 'a', 152 | u'\U0001D5D4': 'a', 153 | u'\U0001D608': 'a', 154 | u'\U0001D63C': 'a', 155 | u'\U0001D670': 'a', 156 | u'\U0001D6A8': 'a', 157 | u'\U0001D6E2': 'a', 158 | u'\U0001D71C': 'a', 159 | u'\U0001D756': 'a', 160 | u'\U0001D790': 'a', 161 | u'\u237A': 'a', 162 | u'\uFF41': 'a', 163 | u'\u0251': 'a', 164 | u'\u03B1': 'a', 165 | u'\u0430': 'a', 166 | u'\u2DF6': 'a', 167 | u'\uFF21': 'a', 168 | u'\u0391': 'a', 169 | u'\u0410': 'a', 170 | u'\u13AA': 'a', 171 | u'\u15C5': 'a', 172 | u'\uA4EE': 'a', 173 | u'\u2376': 'a', 174 | u'\u01CE': 'a', 175 | u'\u0103': 'a', 176 | u'\u01CD': 'a', 177 | u'\u0102': 'a', 178 | u'\u0227': 'a', 179 | u'\u00E5': 'a', 180 | u'\u0226': 'a', 181 | u'\u00C5': 'a', 182 | u'\u1E9A': 'a', 183 | u'\u1EA3': 'a', 184 | u'\uAB7A': 'a', 185 | u'\u1D00': 'a', 186 | u'\uA733': 'aa', 187 | u'\uA732': 'aa', 188 | u'\u00E6': 'ae', 189 | u'\u04D5': 'ae', 190 | u'\u00C6': 'ae', 191 | u'\u04D4': 'ae', 192 | u'\uA735': 'ao', 193 | u'\uA734': 'ao', 194 | u'\U0001F707': 'ar', 195 | u'\uA737': 'au', 196 | u'\uA736': 'au', 197 | u'\uA738': 'av', 198 | u'\uA739': 'av', 199 | u'\uA73A': 'av', 200 | u'\uA73B': 'av', 201 | u'\uA73D': 'ay', 202 | u'\uA73C': 'ay', 203 | u'\U0001D41B': 'b', 204 | u'\U0001D44F': 'b', 205 | u'\U0001D483': 'b', 206 | u'\U0001D4B7': 'b', 207 | u'\U0001D4EB': 'b', 208 | u'\U0001D51F': 'b', 209 | u'\U0001D553': 'b', 210 | u'\U0001D587': 'b', 211 | u'\U0001D5BB': 'b', 212 | u'\U0001D5EF': 'b', 213 | u'\U0001D623': 'b', 214 | u'\U0001D657': 'b', 215 | u'\U0001D68B': 'b', 216 | u'\U0001D401': 'b', 217 | u'\U0001D435': 'b', 218 | u'\U0001D469': 'b', 219 | u'\U0001D4D1': 'b', 220 | u'\U0001D505': 'b', 221 | u'\U0001D539': 'b', 222 | u'\U0001D56D': 'b', 223 | u'\U0001D5A1': 'b', 224 | u'\U0001D5D5': 'b', 225 | u'\U0001D609': 'b', 226 | u'\U0001D63D': 'b', 227 | u'\U0001D671': 'b', 228 | u'\U0001D6A9': 'b', 229 | u'\U0001D6E3': 'b', 230 | u'\U0001D71D': 'b', 231 | u'\U0001D757': 'b', 232 | u'\U0001D791': 'b', 233 | u'\U00010282': 'b', 234 | u'\U000102A1': 'b', 235 | u'\U00010301': 'b', 236 | u'\U0001D6C3': 'b', 237 | u'\U0001D6FD': 'b', 238 | u'\U0001D737': 'b', 239 | u'\U0001D771': 'b', 240 | u'\U0001D7AB': 'b', 241 | u'\u0184': 'b', 242 | u'\u042C': 'b', 243 | u'\u13CF': 'b', 244 | u'\u15AF': 'b', 245 | u'\uFF22': 'b', 246 | u'\u212C': 'b', 247 | u'\uA7B4': 'b', 248 | u'\u0392': 'b', 249 | u'\u0412': 'b', 250 | u'\u13F4': 'b', 251 | u'\u15F7': 'b', 252 | u'\uA4D0': 'b', 253 | u'\u0253': 'b', 254 | u'\u0183': 'b', 255 | u'\u0182': 'b', 256 | u'\u0411': 'b', 257 | u'\u0180': 'b', 258 | u'\u048D': 'b', 259 | u'\u048C': 'b', 260 | u'\u0463': 'b', 261 | u'\u0462': 'b', 262 | u'\u0432': 'b', 263 | u'\u13FC': 'b', 264 | u'\u0299': 'b', 265 | u'\uA7B5': 'b', 266 | u'\u03B2': 'b', 267 | u'\u03D0': 'b', 268 | u'\u13F0': 'b', 269 | u'\u00DF': 'b', 270 | u'\u042B': 'bl', 271 | u'\U0001D41C': 'c', 272 | u'\U0001D450': 'c', 273 | u'\U0001D484': 'c', 274 | u'\U0001D4B8': 'c', 275 | u'\U0001D4EC': 'c', 276 | u'\U0001D520': 'c', 277 | u'\U0001D554': 'c', 278 | u'\U0001D588': 'c', 279 | u'\U0001D5BC': 'c', 280 | u'\U0001D5F0': 'c', 281 | u'\U0001D624': 'c', 282 | u'\U0001D658': 'c', 283 | u'\U0001D68C': 'c', 284 | u'\U0001043D': 'c', 285 | u'\U0001F74C': 'c', 286 | u'\U000118F2': 'c', 287 | u'\U000118E9': 'c', 288 | u'\U0001D402': 'c', 289 | u'\U0001D436': 'c', 290 | u'\U0001D46A': 'c', 291 | u'\U0001D49E': 'c', 292 | u'\U0001D4D2': 'c', 293 | u'\U0001D56E': 'c', 294 | u'\U0001D5A2': 'c', 295 | u'\U0001D5D6': 'c', 296 | u'\U0001D60A': 'c', 297 | u'\U0001D63E': 'c', 298 | u'\U0001D672': 'c', 299 | u'\U000102A2': 'c', 300 | u'\U00010302': 'c', 301 | u'\U00010415': 'c', 302 | u'\U0001051C': 'c', 303 | u'\uFF43': 'c', 304 | u'\u217D': 'c', 305 | u'\u1D04': 'c', 306 | u'\u03F2': 'c', 307 | u'\u2CA5': 'c', 308 | u'\u0441': 'c', 309 | u'\uABAF': 'c', 310 | u'\u2DED': 'c', 311 | u'\uFF23': 'c', 312 | u'\u216D': 'c', 313 | u'\u2102': 'c', 314 | u'\u212D': 'c', 315 | u'\u03F9': 'c', 316 | u'\u2CA4': 'c', 317 | u'\u0421': 'c', 318 | u'\u13DF': 'c', 319 | u'\uA4DA': 'c', 320 | u'\u00A2': 'c', 321 | u'\u023C': 'c', 322 | u'\u20A1': 'c', 323 | u'\u00E7': 'c', 324 | u'\u04AB': 'c', 325 | u'\u00C7': 'c', 326 | u'\u04AA': 'c', 327 | u'\u0187': 'c', 328 | u'\U0001D41D': 'd', 329 | u'\U0001D451': 'd', 330 | u'\U0001D485': 'd', 331 | u'\U0001D4B9': 'd', 332 | u'\U0001D4ED': 'd', 333 | u'\U0001D521': 'd', 334 | u'\U0001D555': 'd', 335 | u'\U0001D589': 'd', 336 | u'\U0001D5BD': 'd', 337 | u'\U0001D5F1': 'd', 338 | u'\U0001D625': 'd', 339 | u'\U0001D659': 'd', 340 | u'\U0001D68D': 'd', 341 | u'\U0001D403': 'd', 342 | u'\U0001D437': 'd', 343 | u'\U0001D46B': 'd', 344 | u'\U0001D49F': 'd', 345 | u'\U0001D4D3': 'd', 346 | u'\U0001D507': 'd', 347 | u'\U0001D53B': 'd', 348 | u'\U0001D56F': 'd', 349 | u'\U0001D5A3': 'd', 350 | u'\U0001D5D7': 'd', 351 | u'\U0001D60B': 'd', 352 | u'\U0001D63F': 'd', 353 | u'\U0001D673': 'd', 354 | u'\u217E': 'd', 355 | u'\u2146': 'd', 356 | u'\u0501': 'd', 357 | u'\u13E7': 'd', 358 | u'\u146F': 'd', 359 | u'\uA4D2': 'd', 360 | u'\u216E': 'd', 361 | u'\u2145': 'd', 362 | u'\u13A0': 'd', 363 | u'\u15DE': 'd', 364 | u'\u15EA': 'd', 365 | u'\uA4D3': 'd', 366 | u'\u0257': 'd', 367 | u'\u0256': 'd', 368 | u'\u018C': 'd', 369 | u'\u0111': 'd', 370 | u'\u0110': 'd', 371 | u'\u00D0': 'd', 372 | u'\u0189': 'd', 373 | u'\u20AB': 'd', 374 | u'\u147B': 'd', 375 | u'\u1487': 'd', 376 | u'\u0257': 'd', 377 | u'\u0256': 'd', 378 | u'\u018C': 'd', 379 | u'\u0111': 'd', 380 | u'\u0110': 'd', 381 | u'\u00D0': 'd', 382 | u'\u0189': 'd', 383 | u'\u20AB': 'd', 384 | u'\u147B': 'd', 385 | u'\u1487': 'd', 386 | u'\uAB70': 'd', 387 | u'\U0001D41E': 'e', 388 | u'\U0001D452': 'e', 389 | u'\U0001D486': 'e', 390 | u'\U0001D4EE': 'e', 391 | u'\U0001D522': 'e', 392 | u'\U0001D556': 'e', 393 | u'\U0001D58A': 'e', 394 | u'\U0001D5BE': 'e', 395 | u'\U0001D5F2': 'e', 396 | u'\U0001D626': 'e', 397 | u'\U0001D65A': 'e', 398 | u'\U0001D68E': 'e', 399 | u'\U0001D404': 'e', 400 | u'\U0001D438': 'e', 401 | u'\U0001D46C': 'e', 402 | u'\U0001D4D4': 'e', 403 | u'\U0001D508': 'e', 404 | u'\U0001D53C': 'e', 405 | u'\U0001D570': 'e', 406 | u'\U0001D5A4': 'e', 407 | u'\U0001D5D8': 'e', 408 | u'\U0001D60C': 'e', 409 | u'\U0001D640': 'e', 410 | u'\U0001D674': 'e', 411 | u'\U0001D6AC': 'e', 412 | u'\U0001D6E6': 'e', 413 | u'\U0001D720': 'e', 414 | u'\U0001D75A': 'e', 415 | u'\U0001D794': 'e', 416 | u'\U000118A6': 'e', 417 | u'\U000118AE': 'e', 418 | u'\U00010286': 'e', 419 | u'\U0001D221': 'e', 420 | u'\u212E': 'e', 421 | u'\uFF45': 'e', 422 | u'\u212F': 'e', 423 | u'\u2147': 'e', 424 | u'\uAB32': 'e', 425 | u'\u0435': 'e', 426 | u'\u04BD': 'e', 427 | u'\u2DF7': 'e', 428 | u'\u22FF': 'e', 429 | u'\uFF25': 'e', 430 | u'\u2130': 'e', 431 | u'\u0395': 'e', 432 | u'\u0415': 'e', 433 | u'\u2D39': 'e', 434 | u'\u13AC': 'e', 435 | u'\uA4F0': 'e', 436 | u'\u011B': 'e', 437 | u'\u011A': 'e', 438 | u'\u0247': 'e', 439 | u'\u0246': 'e', 440 | u'\u04BF': 'e', 441 | u'\uAB7C': 'e', 442 | u'\u1D07': 'e', 443 | u'\u0259': 'e', 444 | u'\u01DD': 'e', 445 | u'\u04D9': 'e', 446 | u'\u2107': 'e', 447 | u'\u0510': 'e', 448 | u'\u13CB': 'e', 449 | u'\U0001D41F': 'f', 450 | u'\U0001D453': 'f', 451 | u'\U0001D487': 'f', 452 | u'\U0001D4BB': 'f', 453 | u'\U0001D4EF': 'f', 454 | u'\U0001D523': 'f', 455 | u'\U0001D557': 'f', 456 | u'\U0001D58B': 'f', 457 | u'\U0001D5BF': 'f', 458 | u'\U0001D5F3': 'f', 459 | u'\U0001D627': 'f', 460 | u'\U0001D65B': 'f', 461 | u'\U0001D68F': 'f', 462 | u'\U0001D213': 'f', 463 | u'\U0001D405': 'f', 464 | u'\U0001D439': 'f', 465 | u'\U0001D46D': 'f', 466 | u'\U0001D4D5': 'f', 467 | u'\U0001D509': 'f', 468 | u'\U0001D53D': 'f', 469 | u'\U0001D571': 'f', 470 | u'\U0001D5A5': 'f', 471 | u'\U0001D5D9': 'f', 472 | u'\U0001D60D': 'f', 473 | u'\U0001D641': 'f', 474 | u'\U0001D675': 'f', 475 | u'\U0001D7CA': 'f', 476 | u'\U000118C2': 'f', 477 | u'\U000118A2': 'f', 478 | u'\U00010287': 'f', 479 | u'\U000102A5': 'f', 480 | u'\U00010525': 'f', 481 | u'\uAB35': 'f', 482 | u'\uA799': 'f', 483 | u'\u017F': 'f', 484 | u'\u1E9D': 'f', 485 | u'\u0584': 'f', 486 | u'\u2131': 'f', 487 | u'\uA798': 'f', 488 | u'\u03DC': 'f', 489 | u'\u15B4': 'f', 490 | u'\uA4DD': 'f', 491 | u'\u0192': 'f', 492 | u'\u0191': 'f', 493 | u'\u1D6E': 'f', 494 | u'\uFB00': 'ff', 495 | u'\uFB03': 'ffi', 496 | u'\uFB04': 'ffl', 497 | u'\uFB01': 'fi', 498 | u'\uFB02': 'fl', 499 | u'\u02A9': 'fn', 500 | u'\U0001D420': 'g', 501 | u'\U0001D454': 'g', 502 | u'\U0001D488': 'g', 503 | u'\U0001D4F0': 'g', 504 | u'\U0001D524': 'g', 505 | u'\U0001D558': 'g', 506 | u'\U0001D58C': 'g', 507 | u'\U0001D5C0': 'g', 508 | u'\U0001D5F4': 'g', 509 | u'\U0001D628': 'g', 510 | u'\U0001D65C': 'g', 511 | u'\U0001D690': 'g', 512 | u'\U0001D406': 'g', 513 | u'\U0001D43A': 'g', 514 | u'\U0001D46E': 'g', 515 | u'\U0001D4A2': 'g', 516 | u'\U0001D4D6': 'g', 517 | u'\U0001D50A': 'g', 518 | u'\U0001D53E': 'g', 519 | u'\U0001D572': 'g', 520 | u'\U0001D5A6': 'g', 521 | u'\U0001D5DA': 'g', 522 | u'\U0001D60E': 'g', 523 | u'\U0001D642': 'g', 524 | u'\U0001D676': 'g', 525 | u'\uFF47': 'g', 526 | u'\u210A': 'g', 527 | u'\u0261': 'g', 528 | u'\u1D83': 'g', 529 | u'\u018D': 'g', 530 | u'\u0581': 'g', 531 | u'\u050C': 'g', 532 | u'\u13C0': 'g', 533 | u'\u13F3': 'g', 534 | u'\uA4D6': 'g', 535 | u'\u1DA2': 'g', 536 | u'\u1D4D': 'g', 537 | u'\u0260': 'g', 538 | u'\u01E7': 'g', 539 | u'\u011F': 'g', 540 | u'\u01E6': 'g', 541 | u'\u011E': 'g', 542 | u'\u01F5': 'g', 543 | u'\u0123': 'g', 544 | u'\u01E5': 'g', 545 | u'\u01E4': 'g', 546 | u'\u0193': 'g', 547 | u'\u050D': 'g', 548 | u'\uAB90': 'g', 549 | u'\u13FB': 'g', 550 | u'\U0001D421': 'h', 551 | u'\U0001D489': 'h', 552 | u'\U0001D4BD': 'h', 553 | u'\U0001D4F1': 'h', 554 | u'\U0001D525': 'h', 555 | u'\U0001D559': 'h', 556 | u'\U0001D58D': 'h', 557 | u'\U0001D5C1': 'h', 558 | u'\U0001D5F5': 'h', 559 | u'\U0001D629': 'h', 560 | u'\U0001D65D': 'h', 561 | u'\U0001D691': 'h', 562 | u'\U0001D407': 'h', 563 | u'\U0001D43B': 'h', 564 | u'\U0001D46F': 'h', 565 | u'\U0001D4D7': 'h', 566 | u'\U0001D573': 'h', 567 | u'\U0001D5A7': 'h', 568 | u'\U0001D5DB': 'h', 569 | u'\U0001D60F': 'h', 570 | u'\U0001D643': 'h', 571 | u'\U0001D677': 'h', 572 | u'\U0001D6AE': 'h', 573 | u'\U0001D6E8': 'h', 574 | u'\U0001D722': 'h', 575 | u'\U0001D75C': 'h', 576 | u'\U0001D796': 'h', 577 | u'\U000102CF': 'h', 578 | u'\U00010199': 'h', 579 | u'\uFF48': 'h', 580 | u'\u210E': 'h', 581 | u'\u04BB': 'h', 582 | u'\u0570': 'h', 583 | u'\u13C2': 'h', 584 | u'\uFF28': 'h', 585 | u'\u210B': 'h', 586 | u'\u210C': 'h', 587 | u'\u210D': 'h', 588 | u'\u0397': 'h', 589 | u'\u2C8E': 'h', 590 | u'\u041D': 'h', 591 | u'\u13BB': 'h', 592 | u'\u157C': 'h', 593 | u'\uA4E7': 'h', 594 | u'\u1D78': 'h', 595 | u'\u1D34': 'h', 596 | u'\u0266': 'h', 597 | u'\uA695': 'h', 598 | u'\u13F2': 'h', 599 | u'\u2C67': 'h', 600 | u'\u04A2': 'h', 601 | u'\u0127': 'h', 602 | u'\u210F': 'h', 603 | u'\u045B': 'h', 604 | u'\u0126': 'h', 605 | u'\u04C9': 'h', 606 | u'\u04C7': 'h', 607 | u'\u043D': 'h', 608 | u'\u029C': 'h', 609 | u'\uAB8B': 'h', 610 | u'\u04A3': 'h', 611 | u'\u04CA': 'h', 612 | u'\u04C8': 'h', 613 | u'\U0001D422': 'i', 614 | u'\U0001D456': 'i', 615 | u'\U0001D48A': 'i', 616 | u'\U0001D4BE': 'i', 617 | u'\U0001D4F2': 'i', 618 | u'\U0001D526': 'i', 619 | u'\U0001D55A': 'i', 620 | u'\U0001D58E': 'i', 621 | u'\U0001D5C2': 'i', 622 | u'\U0001D5F6': 'i', 623 | u'\U0001D62A': 'i', 624 | u'\U0001D65E': 'i', 625 | u'\U0001D692': 'i', 626 | u'\U0001D6A4': 'i', 627 | u'\U0001D6CA': 'i', 628 | u'\U0001D704': 'i', 629 | u'\U0001D73E': 'i', 630 | u'\U0001D778': 'i', 631 | u'\U0001D7B2': 'i', 632 | u'\U000118C3': 'i', 633 | u'\u02DB': 'i', 634 | u'\u2373': 'i', 635 | u'\uFF49': 'i', 636 | u'\u2170': 'i', 637 | u'\u2139': 'i', 638 | u'\u2148': 'i', 639 | u'\u0131': 'i', 640 | u'\u026A': 'i', 641 | u'\u0269': 'i', 642 | u'\u03B9': 'i', 643 | u'\u1FBE': 'i', 644 | u'\u037A': 'i', 645 | u'\u0456': 'i', 646 | u'\uA647': 'i', 647 | u'\u04CF': 'i', 648 | u'\uAB75': 'i', 649 | u'\u13A5': 'i', 650 | u'\u24DB': 'i', 651 | u'\u2378': 'i', 652 | u'\u01D0': 'i', 653 | u'\u01CF': 'i', 654 | u'\u0268': 'i', 655 | u'\u1D7B': 'i', 656 | u'\u1D7C': 'i', 657 | u'\u2171': 'ii', 658 | u'\u2172': 'iii', 659 | u'\u0133': 'ij', 660 | u'\u2173': 'iv', 661 | u'\u2178': 'ix', 662 | u'\U0001D423': 'j', 663 | u'\U0001D457': 'j', 664 | u'\U0001D48B': 'j', 665 | u'\U0001D4BF': 'j', 666 | u'\U0001D4F3': 'j', 667 | u'\U0001D527': 'j', 668 | u'\U0001D55B': 'j', 669 | u'\U0001D58F': 'j', 670 | u'\U0001D5C3': 'j', 671 | u'\U0001D5F7': 'j', 672 | u'\U0001D62B': 'j', 673 | u'\U0001D65F': 'j', 674 | u'\U0001D693': 'j', 675 | u'\U0001D409': 'j', 676 | u'\U0001D43D': 'j', 677 | u'\U0001D471': 'j', 678 | u'\U0001D4A5': 'j', 679 | u'\U0001D4D9': 'j', 680 | u'\U0001D50D': 'j', 681 | u'\U0001D541': 'j', 682 | u'\U0001D575': 'j', 683 | u'\U0001D5A9': 'j', 684 | u'\U0001D5DD': 'j', 685 | u'\U0001D611': 'j', 686 | u'\U0001D645': 'j', 687 | u'\U0001D679': 'j', 688 | u'\U0001D6A5': 'j', 689 | u'\uFF4A': 'j', 690 | u'\u2149': 'j', 691 | u'\u03F3': 'j', 692 | u'\u0458': 'j', 693 | u'\uFF2A': 'j', 694 | u'\uA7B2': 'j', 695 | u'\u037F': 'j', 696 | u'\u0408': 'j', 697 | u'\u13AB': 'j', 698 | u'\u148D': 'j', 699 | u'\uA4D9': 'j', 700 | u'\u0249': 'j', 701 | u'\u0248': 'j', 702 | u'\u1499': 'j', 703 | u'\u0575': 'j', 704 | u'\uAB7B': 'j', 705 | u'\u1D0A': 'j', 706 | u'\U0001D424': 'k', 707 | u'\U0001D458': 'k', 708 | u'\U0001D48C': 'k', 709 | u'\U0001D4C0': 'k', 710 | u'\U0001D4F4': 'k', 711 | u'\U0001D528': 'k', 712 | u'\U0001D55C': 'k', 713 | u'\U0001D590': 'k', 714 | u'\U0001D5C4': 'k', 715 | u'\U0001D5F8': 'k', 716 | u'\U0001D62C': 'k', 717 | u'\U0001D660': 'k', 718 | u'\U0001D694': 'k', 719 | u'\U0001D40A': 'k', 720 | u'\U0001D43E': 'k', 721 | u'\U0001D472': 'k', 722 | u'\U0001D4A6': 'k', 723 | u'\U0001D4DA': 'k', 724 | u'\U0001D50E': 'k', 725 | u'\U0001D542': 'k', 726 | u'\U0001D576': 'k', 727 | u'\U0001D5AA': 'k', 728 | u'\U0001D5DE': 'k', 729 | u'\U0001D612': 'k', 730 | u'\U0001D646': 'k', 731 | u'\U0001D67A': 'k', 732 | u'\U0001D6B1': 'k', 733 | u'\U0001D6EB': 'k', 734 | u'\U0001D725': 'k', 735 | u'\U0001D75F': 'k', 736 | u'\U0001D799': 'k', 737 | u'\U0001D6CB': 'k', 738 | u'\U0001D6DE': 'k', 739 | u'\U0001D705': 'k', 740 | u'\U0001D718': 'k', 741 | u'\U0001D73F': 'k', 742 | u'\U0001D752': 'k', 743 | u'\U0001D779': 'k', 744 | u'\U0001D78C': 'k', 745 | u'\U0001D7B3': 'k', 746 | u'\U0001D7C6': 'k', 747 | u'\u212A': 'k', 748 | u'\uFF2B': 'k', 749 | u'\u039A': 'k', 750 | u'\u2C94': 'k', 751 | u'\u041A': 'k', 752 | u'\u13E6': 'k', 753 | u'\u16D5': 'k', 754 | u'\uA4D7': 'k', 755 | u'\u0199': 'k', 756 | u'\u2C69': 'k', 757 | u'\u049A': 'k', 758 | u'\u20AD': 'k', 759 | u'\uA740': 'k', 760 | u'\u049E': 'k', 761 | u'\u0198': 'k', 762 | u'\u1D0B': 'k', 763 | u'\u0138': 'k', 764 | u'\u03BA': 'k', 765 | u'\u03F0': 'k', 766 | u'\u2C95': 'k', 767 | u'\u043A': 'k', 768 | u'\uABB6': 'k', 769 | u'\u049B': 'k', 770 | u'\u049F': 'k', 771 | u'\U00010320': 'l', 772 | u'\U0001E8C7': 'l', 773 | u'\U0001D7CF': 'l', 774 | u'\U0001D7D9': 'l', 775 | u'\U0001D7E3': 'l', 776 | u'\U0001D7ED': 'l', 777 | u'\U0001D7F7': 'l', 778 | u'\U0001D408': 'l', 779 | u'\U0001D43C': 'l', 780 | u'\U0001D470': 'l', 781 | u'\U0001D4D8': 'l', 782 | u'\U0001D540': 'l', 783 | u'\U0001D574': 'l', 784 | u'\U0001D5A8': 'l', 785 | u'\U0001D5DC': 'l', 786 | u'\U0001D610': 'l', 787 | u'\U0001D644': 'l', 788 | u'\U0001D678': 'l', 789 | u'\U0001D425': 'l', 790 | u'\U0001D459': 'l', 791 | u'\U0001D48D': 'l', 792 | u'\U0001D4C1': 'l', 793 | u'\U0001D4F5': 'l', 794 | u'\U0001D529': 'l', 795 | u'\U0001D55D': 'l', 796 | u'\U0001D591': 'l', 797 | u'\U0001D5C5': 'l', 798 | u'\U0001D5F9': 'l', 799 | u'\U0001D62D': 'l', 800 | u'\U0001D661': 'l', 801 | u'\U0001D695': 'l', 802 | u'\U0001D6B0': 'l', 803 | u'\U0001D6EA': 'l', 804 | u'\U0001D724': 'l', 805 | u'\U0001D75E': 'l', 806 | u'\U0001D798': 'l', 807 | u'\U0001EE00': 'l', 808 | u'\U0001EE80': 'l', 809 | u'\U00016F28': 'l', 810 | u'\U0001028A': 'l', 811 | u'\U00010309': 'l', 812 | u'\U0001D22A': 'l', 813 | u'\U0001D40B': 'l', 814 | u'\U0001D43F': 'l', 815 | u'\U0001D473': 'l', 816 | u'\U0001D4DB': 'l', 817 | u'\U0001D50F': 'l', 818 | u'\U0001D543': 'l', 819 | u'\U0001D577': 'l', 820 | u'\U0001D5AB': 'l', 821 | u'\U0001D5DF': 'l', 822 | u'\U0001D613': 'l', 823 | u'\U0001D647': 'l', 824 | u'\U0001D67B': 'l', 825 | u'\U00016F16': 'l', 826 | u'\U000118A3': 'l', 827 | u'\U000118B2': 'l', 828 | u'\U0001041B': 'l', 829 | u'\U00010526': 'l', 830 | u'\U00010443': 'l', 831 | u'\u05C0': 'l', 832 | u'\u007C': 'l', 833 | u'\u2223': 'l', 834 | u'\u23FD': 'l', 835 | u'\uFFE8': 'l', 836 | u'\u0031': 'l', 837 | u'\u0661': 'l', 838 | u'\u06F1': 'l', 839 | u'\u0049': 'l', 840 | u'\uFF29': 'l', 841 | u'\u2160': 'l', 842 | u'\u2110': 'l', 843 | u'\u2111': 'l', 844 | u'\u0196': 'l', 845 | u'\uFF4C': 'l', 846 | u'\u217C': 'l', 847 | u'\u2113': 'l', 848 | u'\u01C0': 'l', 849 | u'\u0399': 'l', 850 | u'\u2C92': 'l', 851 | u'\u0406': 'l', 852 | u'\u04C0': 'l', 853 | u'\u05D5': 'l', 854 | u'\u05DF': 'l', 855 | u'\u0627': 'l', 856 | u'\uFE8E': 'l', 857 | u'\uFE8D': 'l', 858 | u'\u07CA': 'l', 859 | u'\u2D4F': 'l', 860 | u'\u16C1': 'l', 861 | u'\uA4F2': 'l', 862 | u'\u216C': 'l', 863 | u'\u2112': 'l', 864 | u'\u2CD0': 'l', 865 | u'\u13DE': 'l', 866 | u'\u14AA': 'l', 867 | u'\uA4E1': 'l', 868 | u'\uFD3C': 'l', 869 | u'\uFD3D': 'l', 870 | u'\u0142': 'l', 871 | u'\u0141': 'l', 872 | u'\u026D': 'l', 873 | u'\u0197': 'l', 874 | u'\u019A': 'l', 875 | u'\u026B': 'l', 876 | u'\u0625': 'l', 877 | u'\uFE88': 'l', 878 | u'\uFE87': 'l', 879 | u'\u0673': 'l', 880 | u'\u0140': 'l', 881 | u'\u013F': 'l', 882 | u'\u14B7': 'l', 883 | u'\u0623': 'l', 884 | u'\uFE84': 'l', 885 | u'\uFE83': 'l', 886 | u'\u0672': 'l', 887 | u'\u0675': 'l', 888 | u'\u2CD1': 'l', 889 | u'\uABAE': 'l', 890 | u'\U0001F102': 'l.', 891 | u'\u2488': 'l.', 892 | u'\u01C9': 'lj', 893 | u'\u0132': 'lj', 894 | u'\u01C8': 'lj', 895 | u'\u01C7': 'lj', 896 | u'\u2016': 'll', 897 | u'\u2225': 'll', 898 | u'\u2161': 'll', 899 | u'\u01C1': 'll', 900 | u'\u05F0': 'll', 901 | u'\u2162': 'lll', 902 | u'\u02AA': 'ls', 903 | u'\u20B6': 'lt', 904 | u'\u2163': 'lv', 905 | u'\u2168': 'lx', 906 | u'\u02AB': 'lz', 907 | u'\U0001D40C': 'm', 908 | u'\U0001D440': 'm', 909 | u'\U0001D474': 'm', 910 | u'\U0001D4DC': 'm', 911 | u'\U0001D510': 'm', 912 | u'\U0001D544': 'm', 913 | u'\U0001D578': 'm', 914 | u'\U0001D5AC': 'm', 915 | u'\U0001D5E0': 'm', 916 | u'\U0001D614': 'm', 917 | u'\U0001D648': 'm', 918 | u'\U0001D67C': 'm', 919 | u'\U0001D6B3': 'm', 920 | u'\U0001D6ED': 'm', 921 | u'\U0001D727': 'm', 922 | u'\U0001D761': 'm', 923 | u'\U0001D79B': 'm', 924 | u'\U000102B0': 'm', 925 | u'\U00010311': 'm', 926 | u'\uFF2D': 'm', 927 | u'\u216F': 'm', 928 | u'\u2133': 'm', 929 | u'\u039C': 'm', 930 | u'\u03FA': 'm', 931 | u'\u2C98': 'm', 932 | u'\u041C': 'm', 933 | u'\u13B7': 'm', 934 | u'\u15F0': 'm', 935 | u'\u16D6': 'm', 936 | u'\uA4DF': 'm', 937 | u'\u04CD': 'm', 938 | u'\u2DE8': 'm', 939 | u'\u1DDF': 'm', 940 | u'\u1E43': 'm', 941 | u'\U0001F76B': 'mb', 942 | u'\U0001D427': 'n', 943 | u'\U0001D45B': 'n', 944 | u'\U0001D48F': 'n', 945 | u'\U0001D4C3': 'n', 946 | u'\U0001D4F7': 'n', 947 | u'\U0001D52B': 'n', 948 | u'\U0001D55F': 'n', 949 | u'\U0001D593': 'n', 950 | u'\U0001D5C7': 'n', 951 | u'\U0001D5FB': 'n', 952 | u'\U0001D62F': 'n', 953 | u'\U0001D663': 'n', 954 | u'\U0001D697': 'n', 955 | u'\U0001D40D': 'n', 956 | u'\U0001D441': 'n', 957 | u'\U0001D475': 'n', 958 | u'\U0001D4A9': 'n', 959 | u'\U0001D4DD': 'n', 960 | u'\U0001D511': 'n', 961 | u'\U0001D579': 'n', 962 | u'\U0001D5AD': 'n', 963 | u'\U0001D5E1': 'n', 964 | u'\U0001D615': 'n', 965 | u'\U0001D649': 'n', 966 | u'\U0001D67D': 'n', 967 | u'\U0001D6B4': 'n', 968 | u'\U0001D6EE': 'n', 969 | u'\U0001D728': 'n', 970 | u'\U0001D762': 'n', 971 | u'\U0001D79C': 'n', 972 | u'\U00010513': 'n', 973 | u'\U0001018E': 'n', 974 | u'\U0001D6C8': 'n', 975 | u'\U0001D702': 'n', 976 | u'\U0001D73C': 'n', 977 | u'\U0001D776': 'n', 978 | u'\U0001D7B0': 'n', 979 | u'\U0001044D': 'n', 980 | u'\u0578': 'n', 981 | u'\u057C': 'n', 982 | u'\uFF2E': 'n', 983 | u'\u2115': 'n', 984 | u'\u039D': 'n', 985 | u'\u2C9A': 'n', 986 | u'\uA4E0': 'n', 987 | u'\u0273': 'n', 988 | u'\u019E': 'n', 989 | u'\u03B7': 'n', 990 | u'\u019D': 'n', 991 | u'\u1D70': 'n', 992 | u'\u0146': 'n', 993 | u'\u0272': 'n', 994 | u'\u01CC': 'nj', 995 | u'\u01CB': 'nj', 996 | u'\u01CA': 'nj', 997 | u'\u2116': 'no', 998 | u'\U0001D428': 'o', 999 | u'\U0001D45C': 'o', 1000 | u'\U0001D490': 'o', 1001 | u'\U0001D4F8': 'o', 1002 | u'\U0001D52C': 'o', 1003 | u'\U0001D560': 'o', 1004 | u'\U0001D594': 'o', 1005 | u'\U0001D5C8': 'o', 1006 | u'\U0001D5FC': 'o', 1007 | u'\U0001D630': 'o', 1008 | u'\U0001D664': 'o', 1009 | u'\U0001D698': 'o', 1010 | u'\U0001D6D0': 'o', 1011 | u'\U0001D70A': 'o', 1012 | u'\U0001D744': 'o', 1013 | u'\U0001D77E': 'o', 1014 | u'\U0001D7B8': 'o', 1015 | u'\U0001D6D4': 'o', 1016 | u'\U0001D70E': 'o', 1017 | u'\U0001D748': 'o', 1018 | u'\U0001D782': 'o', 1019 | u'\U0001D7BC': 'o', 1020 | u'\U0001EE24': 'o', 1021 | u'\U0001EE64': 'o', 1022 | u'\U0001EE84': 'o', 1023 | u'\U000104EA': 'o', 1024 | u'\U000118C8': 'o', 1025 | u'\U000118D7': 'o', 1026 | u'\U0001042C': 'o', 1027 | u'\U000114D0': 'o', 1028 | u'\U000118E0': 'o', 1029 | u'\U0001D7CE': 'o', 1030 | u'\U0001D7D8': 'o', 1031 | u'\U0001D7E2': 'o', 1032 | u'\U0001D7EC': 'o', 1033 | u'\U0001D7F6': 'o', 1034 | u'\U0001D40E': 'o', 1035 | u'\U0001D442': 'o', 1036 | u'\U0001D476': 'o', 1037 | u'\U0001D4AA': 'o', 1038 | u'\U0001D4DE': 'o', 1039 | u'\U0001D512': 'o', 1040 | u'\U0001D546': 'o', 1041 | u'\U0001D57A': 'o', 1042 | u'\U0001D5AE': 'o', 1043 | u'\U0001D5E2': 'o', 1044 | u'\U0001D616': 'o', 1045 | u'\U0001D64A': 'o', 1046 | u'\U0001D67E': 'o', 1047 | u'\U0001D6B6': 'o', 1048 | u'\U0001D6F0': 'o', 1049 | u'\U0001D72A': 'o', 1050 | u'\U0001D764': 'o', 1051 | u'\U0001D79E': 'o', 1052 | u'\U000104C2': 'o', 1053 | u'\U000118B5': 'o', 1054 | u'\U00010292': 'o', 1055 | u'\U000102AB': 'o', 1056 | u'\U00010404': 'o', 1057 | u'\U00010516': 'o', 1058 | u'\U0001D21A': 'o', 1059 | u'\U0001F714': 'o', 1060 | u'\U0001D6C9': 'o', 1061 | u'\U0001D6DD': 'o', 1062 | u'\U0001D703': 'o', 1063 | u'\U0001D717': 'o', 1064 | u'\U0001D73D': 'o', 1065 | u'\U0001D751': 'o', 1066 | u'\U0001D777': 'o', 1067 | u'\U0001D78B': 'o', 1068 | u'\U0001D7B1': 'o', 1069 | u'\U0001D7C5': 'o', 1070 | u'\U0001D6AF': 'o', 1071 | u'\U0001D6B9': 'o', 1072 | u'\U0001D6E9': 'o', 1073 | u'\U0001D6F3': 'o', 1074 | u'\U0001D723': 'o', 1075 | u'\U0001D72D': 'o', 1076 | u'\U0001D75D': 'o', 1077 | u'\U0001D767': 'o', 1078 | u'\U0001D797': 'o', 1079 | u'\U0001D7A1': 'o', 1080 | u'\U0001F101': 'o', 1081 | u'\U0001F100': 'o', 1082 | u'\u0C02': 'o', 1083 | u'\u0C82': 'o', 1084 | u'\u0D02': 'o', 1085 | u'\u0D82': 'o', 1086 | u'\u0966': 'o', 1087 | u'\u0A66': 'o', 1088 | u'\u0AE6': 'o', 1089 | u'\u0BE6': 'o', 1090 | u'\u0C66': 'o', 1091 | u'\u0CE6': 'o', 1092 | u'\u0D66': 'o', 1093 | u'\u0E50': 'o', 1094 | u'\u0ED0': 'o', 1095 | u'\u1040': 'o', 1096 | u'\u0665': 'o', 1097 | u'\u06F5': 'o', 1098 | u'\uFF4F': 'o', 1099 | u'\u2134': 'o', 1100 | u'\u1D0F': 'o', 1101 | u'\u1D11': 'o', 1102 | u'\uAB3D': 'o', 1103 | u'\u03BF': 'o', 1104 | u'\u03C3': 'o', 1105 | u'\u2C9F': 'o', 1106 | u'\u043E': 'o', 1107 | u'\u10FF': 'o', 1108 | u'\u0585': 'o', 1109 | u'\u05E1': 'o', 1110 | u'\u0647': 'o', 1111 | u'\uFEEB': 'o', 1112 | u'\uFEEC': 'o', 1113 | u'\uFEEA': 'o', 1114 | u'\uFEE9': 'o', 1115 | u'\u06BE': 'o', 1116 | u'\uFBAC': 'o', 1117 | u'\uFBAD': 'o', 1118 | u'\uFBAB': 'o', 1119 | u'\uFBAA': 'o', 1120 | u'\u06C1': 'o', 1121 | u'\uFBA8': 'o', 1122 | u'\uFBA9': 'o', 1123 | u'\uFBA7': 'o', 1124 | u'\uFBA6': 'o', 1125 | u'\u06D5': 'o', 1126 | u'\u0D20': 'o', 1127 | u'\u101D': 'o', 1128 | u'\u07C0': 'o', 1129 | u'\u09E6': 'o', 1130 | u'\u0B66': 'o', 1131 | u'\u3007': 'o', 1132 | u'\uFF2F': 'o', 1133 | u'\u039F': 'o', 1134 | u'\u2C9E': 'o', 1135 | u'\u041E': 'o', 1136 | u'\u0555': 'o', 1137 | u'\u2D54': 'o', 1138 | u'\u12D0': 'o', 1139 | u'\u0B20': 'o', 1140 | u'\uA4F3': 'o', 1141 | u'\u2070': 'o', 1142 | u'\u00BA': 'o', 1143 | u'\u1D52': 'o', 1144 | u'\u01D2': 'o', 1145 | u'\u014F': 'o', 1146 | u'\u01D1': 'o', 1147 | u'\u014E': 'o', 1148 | u'\u06FF': 'o', 1149 | u'\u00F8': 'o', 1150 | u'\uAB3E': 'o', 1151 | u'\u00D8': 'o', 1152 | u'\u2D41': 'o', 1153 | u'\u01FE': 'o', 1154 | u'\u0275': 'o', 1155 | u'\uA74B': 'o', 1156 | u'\u04E9': 'o', 1157 | u'\u0473': 'o', 1158 | u'\uAB8E': 'o', 1159 | u'\uABBB': 'o', 1160 | u'\u2296': 'o', 1161 | u'\u229D': 'o', 1162 | u'\u236C': 'o', 1163 | u'\u019F': 'o', 1164 | u'\uA74A': 'o', 1165 | u'\u03B8': 'o', 1166 | u'\u03D1': 'o', 1167 | u'\u0398': 'o', 1168 | u'\u03F4': 'o', 1169 | u'\u04E8': 'o', 1170 | u'\u0472': 'o', 1171 | u'\u2D31': 'o', 1172 | u'\u13BE': 'o', 1173 | u'\u13EB': 'o', 1174 | u'\uAB74': 'o', 1175 | u'\uFCD9': 'o', 1176 | u'\u01A1': 'o', 1177 | u'\u01A0': 'o', 1178 | u'\u13A4': 'o', 1179 | u'\U0001F101': 'o.', 1180 | u'\U0001F100': 'o.', 1181 | u'\u0153': 'oe', 1182 | u'\u0152': 'oe', 1183 | u'\u0276': 'oe', 1184 | u'\u221E': 'oo', 1185 | u'\uA74F': 'oo', 1186 | u'\uA699': 'oo', 1187 | u'\uA74E': 'oo', 1188 | u'\uA698': 'oo', 1189 | u'\u1010': 'oo', 1190 | u'\U0001D429': 'p', 1191 | u'\U0001D45D': 'p', 1192 | u'\U0001D491': 'p', 1193 | u'\U0001D4C5': 'p', 1194 | u'\U0001D4F9': 'p', 1195 | u'\U0001D52D': 'p', 1196 | u'\U0001D561': 'p', 1197 | u'\U0001D595': 'p', 1198 | u'\U0001D5C9': 'p', 1199 | u'\U0001D5FD': 'p', 1200 | u'\U0001D631': 'p', 1201 | u'\U0001D665': 'p', 1202 | u'\U0001D699': 'p', 1203 | u'\U0001D6D2': 'p', 1204 | u'\U0001D6E0': 'p', 1205 | u'\U0001D70C': 'p', 1206 | u'\U0001D71A': 'p', 1207 | u'\U0001D746': 'p', 1208 | u'\U0001D754': 'p', 1209 | u'\U0001D780': 'p', 1210 | u'\U0001D78E': 'p', 1211 | u'\U0001D7BA': 'p', 1212 | u'\U0001D7C8': 'p', 1213 | u'\U0001D40F': 'p', 1214 | u'\U0001D443': 'p', 1215 | u'\U0001D477': 'p', 1216 | u'\U0001D4AB': 'p', 1217 | u'\U0001D4DF': 'p', 1218 | u'\U0001D513': 'p', 1219 | u'\U0001D57B': 'p', 1220 | u'\U0001D5AF': 'p', 1221 | u'\U0001D5E3': 'p', 1222 | u'\U0001D617': 'p', 1223 | u'\U0001D64B': 'p', 1224 | u'\U0001D67F': 'p', 1225 | u'\U0001D6B8': 'p', 1226 | u'\U0001D6F2': 'p', 1227 | u'\U0001D72C': 'p', 1228 | u'\U0001D766': 'p', 1229 | u'\U0001D7A0': 'p', 1230 | u'\U00010295': 'p', 1231 | u'\u2374': 'p', 1232 | u'\uFF50': 'p', 1233 | u'\u03C1': 'p', 1234 | u'\u03F1': 'p', 1235 | u'\u2CA3': 'p', 1236 | u'\u0440': 'p', 1237 | u'\uFF30': 'p', 1238 | u'\u2119': 'p', 1239 | u'\u03A1': 'p', 1240 | u'\u2CA2': 'p', 1241 | u'\u0420': 'p', 1242 | u'\u13E2': 'p', 1243 | u'\u146D': 'p', 1244 | u'\uA4D1': 'p', 1245 | u'\u01A5': 'p', 1246 | u'\u1D7D': 'p', 1247 | u'\u1477': 'p', 1248 | u'\u1486': 'p', 1249 | u'\u1D29': 'p', 1250 | u'\uABB2': 'p', 1251 | u'\U0001D42A': 'q', 1252 | u'\U0001D45E': 'q', 1253 | u'\U0001D492': 'q', 1254 | u'\U0001D4C6': 'q', 1255 | u'\U0001D4FA': 'q', 1256 | u'\U0001D52E': 'q', 1257 | u'\U0001D562': 'q', 1258 | u'\U0001D596': 'q', 1259 | u'\U0001D5CA': 'q', 1260 | u'\U0001D5FE': 'q', 1261 | u'\U0001D632': 'q', 1262 | u'\U0001D666': 'q', 1263 | u'\U0001D69A': 'q', 1264 | u'\U0001D410': 'q', 1265 | u'\U0001D444': 'q', 1266 | u'\U0001D478': 'q', 1267 | u'\U0001D4AC': 'q', 1268 | u'\U0001D4E0': 'q', 1269 | u'\U0001D514': 'q', 1270 | u'\U0001D57C': 'q', 1271 | u'\U0001D5B0': 'q', 1272 | u'\U0001D5E4': 'q', 1273 | u'\U0001D618': 'q', 1274 | u'\U0001D64C': 'q', 1275 | u'\U0001D680': 'q', 1276 | u'\u051B': 'q', 1277 | u'\u0563': 'q', 1278 | u'\u0566': 'q', 1279 | u'\u211A': 'q', 1280 | u'\u2D55': 'q', 1281 | u'\u02A0': 'q', 1282 | u'\u1D90': 'q', 1283 | u'\u024B': 'q', 1284 | u'\U0001D42B': 'r', 1285 | u'\U0001D45F': 'r', 1286 | u'\U0001D493': 'r', 1287 | u'\U0001D4C7': 'r', 1288 | u'\U0001D4FB': 'r', 1289 | u'\U0001D52F': 'r', 1290 | u'\U0001D563': 'r', 1291 | u'\U0001D597': 'r', 1292 | u'\U0001D5CB': 'r', 1293 | u'\U0001D5FF': 'r', 1294 | u'\U0001D633': 'r', 1295 | u'\U0001D667': 'r', 1296 | u'\U0001D69B': 'r', 1297 | u'\U0001D216': 'r', 1298 | u'\U0001D411': 'r', 1299 | u'\U0001D445': 'r', 1300 | u'\U0001D479': 'r', 1301 | u'\U0001D4E1': 'r', 1302 | u'\U0001D57D': 'r', 1303 | u'\U0001D5B1': 'r', 1304 | u'\U0001D5E5': 'r', 1305 | u'\U0001D619': 'r', 1306 | u'\U0001D64D': 'r', 1307 | u'\U0001D681': 'r', 1308 | u'\U000104B4': 'r', 1309 | u'\uAB47': 'r', 1310 | u'\uAB48': 'r', 1311 | u'\u1D26': 'r', 1312 | u'\u2C85': 'r', 1313 | u'\u0433': 'r', 1314 | u'\uAB81': 'r', 1315 | u'\u211B': 'r', 1316 | u'\u211C': 'r', 1317 | u'\u211D': 'r', 1318 | u'\u01A6': 'r', 1319 | u'\u13A1': 'r', 1320 | u'\u13D2': 'r', 1321 | u'\u1587': 'r', 1322 | u'\uA4E3': 'r', 1323 | u'\u027D': 'r', 1324 | u'\u027C': 'r', 1325 | u'\u024D': 'r', 1326 | u'\u0493': 'r', 1327 | u'\u1D72': 'r', 1328 | u'\u0491': 'r', 1329 | u'\uAB71': 'r', 1330 | u'\u0280': 'r', 1331 | u'\uABA2': 'r', 1332 | u'\u1D73': 'r', 1333 | u'\U000118E3': 'rn', 1334 | u'\U0001D426': 'rn', 1335 | u'\U0001D45A': 'rn', 1336 | u'\U0001D48E': 'rn', 1337 | u'\U0001D4C2': 'rn', 1338 | u'\U0001D4F6': 'rn', 1339 | u'\U0001D52A': 'rn', 1340 | u'\U0001D55E': 'rn', 1341 | u'\U0001D592': 'rn', 1342 | u'\U0001D5C6': 'rn', 1343 | u'\U0001D5FA': 'rn', 1344 | u'\U0001D62E': 'rn', 1345 | u'\U0001D662': 'rn', 1346 | u'\U0001D696': 'rn', 1347 | u'\U00011700': 'rn', 1348 | u'\u217F': 'rn', 1349 | u'\u20A5': 'rn', 1350 | u'\u0271': 'rn', 1351 | u'\u1D6F': 'rn', 1352 | u'\U0001D42C': 's', 1353 | u'\U0001D460': 's', 1354 | u'\U0001D494': 's', 1355 | u'\U0001D4C8': 's', 1356 | u'\U0001D4FC': 's', 1357 | u'\U0001D530': 's', 1358 | u'\U0001D564': 's', 1359 | u'\U0001D598': 's', 1360 | u'\U0001D5CC': 's', 1361 | u'\U0001D600': 's', 1362 | u'\U0001D634': 's', 1363 | u'\U0001D668': 's', 1364 | u'\U0001D69C': 's', 1365 | u'\U000118C1': 's', 1366 | u'\U00010448': 's', 1367 | u'\U0001D412': 's', 1368 | u'\U0001D446': 's', 1369 | u'\U0001D47A': 's', 1370 | u'\U0001D4AE': 's', 1371 | u'\U0001D4E2': 's', 1372 | u'\U0001D516': 's', 1373 | u'\U0001D54A': 's', 1374 | u'\U0001D57E': 's', 1375 | u'\U0001D5B2': 's', 1376 | u'\U0001D5E6': 's', 1377 | u'\U0001D61A': 's', 1378 | u'\U0001D64E': 's', 1379 | u'\U0001D682': 's', 1380 | u'\U00016F3A': 's', 1381 | u'\U00010296': 's', 1382 | u'\U00010420': 's', 1383 | u'\uFF53': 's', 1384 | u'\uA731': 's', 1385 | u'\u01BD': 's', 1386 | u'\u0455': 's', 1387 | u'\uABAA': 's', 1388 | u'\uFF33': 's', 1389 | u'\u0405': 's', 1390 | u'\u054F': 's', 1391 | u'\u13D5': 's', 1392 | u'\u13DA': 's', 1393 | u'\uA4E2': 's', 1394 | u'\u0282': 's', 1395 | u'\u1D74': 's', 1396 | u'\U0001F75C': 'sss', 1397 | u'\uFB06': 'st', 1398 | u'\U0001D42D': 't', 1399 | u'\U0001D461': 't', 1400 | u'\U0001D495': 't', 1401 | u'\U0001D4C9': 't', 1402 | u'\U0001D4FD': 't', 1403 | u'\U0001D531': 't', 1404 | u'\U0001D565': 't', 1405 | u'\U0001D599': 't', 1406 | u'\U0001D5CD': 't', 1407 | u'\U0001D601': 't', 1408 | u'\U0001D635': 't', 1409 | u'\U0001D669': 't', 1410 | u'\U0001D69D': 't', 1411 | u'\U0001F768': 't', 1412 | u'\U0001D413': 't', 1413 | u'\U0001D447': 't', 1414 | u'\U0001D47B': 't', 1415 | u'\U0001D4AF': 't', 1416 | u'\U0001D4E3': 't', 1417 | u'\U0001D517': 't', 1418 | u'\U0001D54B': 't', 1419 | u'\U0001D57F': 't', 1420 | u'\U0001D5B3': 't', 1421 | u'\U0001D5E7': 't', 1422 | u'\U0001D61B': 't', 1423 | u'\U0001D64F': 't', 1424 | u'\U0001D683': 't', 1425 | u'\U0001D6BB': 't', 1426 | u'\U0001D6F5': 't', 1427 | u'\U0001D72F': 't', 1428 | u'\U0001D769': 't', 1429 | u'\U0001D7A3': 't', 1430 | u'\U00016F0A': 't', 1431 | u'\U000118BC': 't', 1432 | u'\U00010297': 't', 1433 | u'\U000102B1': 't', 1434 | u'\U00010315': 't', 1435 | u'\U0001D6D5': 't', 1436 | u'\U0001D70F': 't', 1437 | u'\U0001D749': 't', 1438 | u'\U0001D783': 't', 1439 | u'\U0001D7BD': 't', 1440 | u'\u22A4': 't', 1441 | u'\u27D9': 't', 1442 | u'\uFF34': 't', 1443 | u'\u03A4': 't', 1444 | u'\u2CA6': 't', 1445 | u'\u0422': 't', 1446 | u'\u13A2': 't', 1447 | u'\uA4D4': 't', 1448 | u'\u2361': 't', 1449 | u'\u023E': 't', 1450 | u'\u021A': 't', 1451 | u'\u0162': 't', 1452 | u'\u01AE': 't', 1453 | u'\u04AC': 't', 1454 | u'\u20AE': 't', 1455 | u'\u0167': 't', 1456 | u'\u0166': 't', 1457 | u'\u1D75': 't', 1458 | u'\U0001D42E': 'u', 1459 | u'\U0001D462': 'u', 1460 | u'\U0001D496': 'u', 1461 | u'\U0001D4CA': 'u', 1462 | u'\U0001D4FE': 'u', 1463 | u'\U0001D532': 'u', 1464 | u'\U0001D566': 'u', 1465 | u'\U0001D59A': 'u', 1466 | u'\U0001D5CE': 'u', 1467 | u'\U0001D602': 'u', 1468 | u'\U0001D636': 'u', 1469 | u'\U0001D66A': 'u', 1470 | u'\U0001D69E': 'u', 1471 | u'\U0001D6D6': 'u', 1472 | u'\U0001D710': 'u', 1473 | u'\U0001D74A': 'u', 1474 | u'\U0001D784': 'u', 1475 | u'\U0001D7BE': 'u', 1476 | u'\U000104F6': 'u', 1477 | u'\U000118D8': 'u', 1478 | u'\U0001D414': 'u', 1479 | u'\U0001D448': 'u', 1480 | u'\U0001D47C': 'u', 1481 | u'\U0001D4B0': 'u', 1482 | u'\U0001D4E4': 'u', 1483 | u'\U0001D518': 'u', 1484 | u'\U0001D54C': 'u', 1485 | u'\U0001D580': 'u', 1486 | u'\U0001D5B4': 'u', 1487 | u'\U0001D5E8': 'u', 1488 | u'\U0001D61C': 'u', 1489 | u'\U0001D650': 'u', 1490 | u'\U0001D684': 'u', 1491 | u'\U000104CE': 'u', 1492 | u'\U00016F42': 'u', 1493 | u'\U000118B8': 'u', 1494 | u'\uA79F': 'u', 1495 | u'\u1D1C': 'u', 1496 | u'\uAB4E': 'u', 1497 | u'\uAB52': 'u', 1498 | u'\u028B': 'u', 1499 | u'\u03C5': 'u', 1500 | u'\u057D': 'u', 1501 | u'\u222A': 'u', 1502 | u'\u22C3': 'u', 1503 | u'\u054D': 'u', 1504 | u'\u1200': 'u', 1505 | u'\u144C': 'u', 1506 | u'\uA4F4': 'u', 1507 | u'\u01D4': 'u', 1508 | u'\u01D3': 'u', 1509 | u'\u1D7E': 'u', 1510 | u'\uAB9C': 'u', 1511 | u'\u0244': 'u', 1512 | u'\u13CC': 'u', 1513 | u'\u1458': 'u', 1514 | u'\u1467': 'u', 1515 | u'\u2127': 'u', 1516 | u'\u162E': 'u', 1517 | u'\u1634': 'u', 1518 | u'\u01B1': 'u', 1519 | u'\u1D7F': 'u', 1520 | u'\u1D6B': 'ue', 1521 | u'\uAB63': 'uo', 1522 | u'\U0001D42F': 'v', 1523 | u'\U0001D463': 'v', 1524 | u'\U0001D497': 'v', 1525 | u'\U0001D4CB': 'v', 1526 | u'\U0001D4FF': 'v', 1527 | u'\U0001D533': 'v', 1528 | u'\U0001D567': 'v', 1529 | u'\U0001D59B': 'v', 1530 | u'\U0001D5CF': 'v', 1531 | u'\U0001D603': 'v', 1532 | u'\U0001D637': 'v', 1533 | u'\U0001D66B': 'v', 1534 | u'\U0001D69F': 'v', 1535 | u'\U0001D6CE': 'v', 1536 | u'\U0001D708': 'v', 1537 | u'\U0001D742': 'v', 1538 | u'\U0001D77C': 'v', 1539 | u'\U0001D7B6': 'v', 1540 | u'\U00011706': 'v', 1541 | u'\U000118C0': 'v', 1542 | u'\U0001D20D': 'v', 1543 | u'\U0001D415': 'v', 1544 | u'\U0001D449': 'v', 1545 | u'\U0001D47D': 'v', 1546 | u'\U0001D4B1': 'v', 1547 | u'\U0001D4E5': 'v', 1548 | u'\U0001D519': 'v', 1549 | u'\U0001D54D': 'v', 1550 | u'\U0001D581': 'v', 1551 | u'\U0001D5B5': 'v', 1552 | u'\U0001D5E9': 'v', 1553 | u'\U0001D61D': 'v', 1554 | u'\U0001D651': 'v', 1555 | u'\U0001D685': 'v', 1556 | u'\U00016F08': 'v', 1557 | u'\U000118A0': 'v', 1558 | u'\U0001051D': 'v', 1559 | u'\U00010197': 'v', 1560 | u'\U0001F708': 'v', 1561 | u'\u2228': 'v', 1562 | u'\u22C1': 'v', 1563 | u'\uFF56': 'v', 1564 | u'\u2174': 'v', 1565 | u'\u1D20': 'v', 1566 | u'\u03BD': 'v', 1567 | u'\u0475': 'v', 1568 | u'\u05D8': 'v', 1569 | u'\uABA9': 'v', 1570 | u'\u0667': 'v', 1571 | u'\u06F7': 'v', 1572 | u'\u2164': 'v', 1573 | u'\u0474': 'v', 1574 | u'\u2D38': 'v', 1575 | u'\u13D9': 'v', 1576 | u'\u142F': 'v', 1577 | u'\uA6DF': 'v', 1578 | u'\uA4E6': 'v', 1579 | u'\u143B': 'v', 1580 | u'\U0001F76C': 'vb', 1581 | u'\u2175': 'vi', 1582 | u'\u2176': 'vii', 1583 | u'\u2177': 'viii', 1584 | u'\u2165': 'vl', 1585 | u'\u2166': 'vll', 1586 | u'\u2167': 'vlll', 1587 | u'\U0001D430': 'w', 1588 | u'\U0001D464': 'w', 1589 | u'\U0001D498': 'w', 1590 | u'\U0001D4CC': 'w', 1591 | u'\U0001D500': 'w', 1592 | u'\U0001D534': 'w', 1593 | u'\U0001D568': 'w', 1594 | u'\U0001D59C': 'w', 1595 | u'\U0001D5D0': 'w', 1596 | u'\U0001D604': 'w', 1597 | u'\U0001D638': 'w', 1598 | u'\U0001D66C': 'w', 1599 | u'\U0001D6A0': 'w', 1600 | u'\U0001170A': 'w', 1601 | u'\U0001170E': 'w', 1602 | u'\U0001170F': 'w', 1603 | u'\U000118EF': 'w', 1604 | u'\U000118E6': 'w', 1605 | u'\U0001D416': 'w', 1606 | u'\U0001D44A': 'w', 1607 | u'\U0001D47E': 'w', 1608 | u'\U0001D4B2': 'w', 1609 | u'\U0001D4E6': 'w', 1610 | u'\U0001D51A': 'w', 1611 | u'\U0001D54E': 'w', 1612 | u'\U0001D582': 'w', 1613 | u'\U0001D5B6': 'w', 1614 | u'\U0001D5EA': 'w', 1615 | u'\U0001D61E': 'w', 1616 | u'\U0001D652': 'w', 1617 | u'\U0001D686': 'w', 1618 | u'\U000114C5': 'w', 1619 | u'\u026F': 'w', 1620 | u'\u1D21': 'w', 1621 | u'\u0461': 'w', 1622 | u'\u051D': 'w', 1623 | u'\u0561': 'w', 1624 | u'\uAB83': 'w', 1625 | u'\u051C': 'w', 1626 | u'\u13B3': 'w', 1627 | u'\u13D4': 'w', 1628 | u'\uA4EA': 'w', 1629 | u'\u047D': 'w', 1630 | u'\u20A9': 'w', 1631 | u'\uA761': 'w', 1632 | u'\U0001D431': 'x', 1633 | u'\U0001D465': 'x', 1634 | u'\U0001D499': 'x', 1635 | u'\U0001D4CD': 'x', 1636 | u'\U0001D501': 'x', 1637 | u'\U0001D535': 'x', 1638 | u'\U0001D569': 'x', 1639 | u'\U0001D59D': 'x', 1640 | u'\U0001D5D1': 'x', 1641 | u'\U0001D605': 'x', 1642 | u'\U0001D639': 'x', 1643 | u'\U0001D66D': 'x', 1644 | u'\U0001D6A1': 'x', 1645 | u'\U00010322': 'x', 1646 | u'\U000118EC': 'x', 1647 | u'\U0001D417': 'x', 1648 | u'\U0001D44B': 'x', 1649 | u'\U0001D47F': 'x', 1650 | u'\U0001D4B3': 'x', 1651 | u'\U0001D4E7': 'x', 1652 | u'\U0001D51B': 'x', 1653 | u'\U0001D54F': 'x', 1654 | u'\U0001D583': 'x', 1655 | u'\U0001D5B7': 'x', 1656 | u'\U0001D5EB': 'x', 1657 | u'\U0001D61F': 'x', 1658 | u'\U0001D653': 'x', 1659 | u'\U0001D687': 'x', 1660 | u'\U0001D6BE': 'x', 1661 | u'\U0001D6F8': 'x', 1662 | u'\U0001D732': 'x', 1663 | u'\U0001D76C': 'x', 1664 | u'\U0001D7A6': 'x', 1665 | u'\U00010290': 'x', 1666 | u'\U000102B4': 'x', 1667 | u'\U00010317': 'x', 1668 | u'\U00010527': 'x', 1669 | u'\U00010196': 'x', 1670 | u'\u166E': 'x', 1671 | u'\u00D7': 'x', 1672 | u'\u292B': 'x', 1673 | u'\u292C': 'x', 1674 | u'\u2A2F': 'x', 1675 | u'\uFF58': 'x', 1676 | u'\u2179': 'x', 1677 | u'\u0445': 'x', 1678 | u'\u1541': 'x', 1679 | u'\u157D': 'x', 1680 | u'\u2DEF': 'x', 1681 | u'\u036F': 'x', 1682 | u'\u166D': 'x', 1683 | u'\u2573': 'x', 1684 | u'\uFF38': 'x', 1685 | u'\u2169': 'x', 1686 | u'\uA7B3': 'x', 1687 | u'\u03A7': 'x', 1688 | u'\u2CAC': 'x', 1689 | u'\u0425': 'x', 1690 | u'\u2D5D': 'x', 1691 | u'\u16B7': 'x', 1692 | u'\uA4EB': 'x', 1693 | u'\u2A30': 'x', 1694 | u'\u04B2': 'x', 1695 | u'\u217A': 'xi', 1696 | u'\u217B': 'xii', 1697 | u'\u216A': 'xl', 1698 | u'\u216B': 'xll', 1699 | u'\U0001D432': 'y', 1700 | u'\U0001D466': 'y', 1701 | u'\U0001D49A': 'y', 1702 | u'\U0001D4CE': 'y', 1703 | u'\U0001D502': 'y', 1704 | u'\U0001D536': 'y', 1705 | u'\U0001D56A': 'y', 1706 | u'\U0001D59E': 'y', 1707 | u'\U0001D5D2': 'y', 1708 | u'\U0001D606': 'y', 1709 | u'\U0001D63A': 'y', 1710 | u'\U0001D66E': 'y', 1711 | u'\U0001D6A2': 'y', 1712 | u'\U0001D6C4': 'y', 1713 | u'\U0001D6FE': 'y', 1714 | u'\U0001D738': 'y', 1715 | u'\U0001D772': 'y', 1716 | u'\U0001D7AC': 'y', 1717 | u'\U000118DC': 'y', 1718 | u'\U0001D418': 'y', 1719 | u'\U0001D44C': 'y', 1720 | u'\U0001D480': 'y', 1721 | u'\U0001D4B4': 'y', 1722 | u'\U0001D4E8': 'y', 1723 | u'\U0001D51C': 'y', 1724 | u'\U0001D550': 'y', 1725 | u'\U0001D584': 'y', 1726 | u'\U0001D5B8': 'y', 1727 | u'\U0001D5EC': 'y', 1728 | u'\U0001D620': 'y', 1729 | u'\U0001D654': 'y', 1730 | u'\U0001D688': 'y', 1731 | u'\U0001D6BC': 'y', 1732 | u'\U0001D6F6': 'y', 1733 | u'\U0001D730': 'y', 1734 | u'\U0001D76A': 'y', 1735 | u'\U0001D7A4': 'y', 1736 | u'\U00016F43': 'y', 1737 | u'\U000118A4': 'y', 1738 | u'\U000102B2': 'y', 1739 | u'\u0263': 'y', 1740 | u'\u1D8C': 'y', 1741 | u'\uFF59': 'y', 1742 | u'\u028F': 'y', 1743 | u'\u1EFF': 'y', 1744 | u'\uAB5A': 'y', 1745 | u'\u03B3': 'y', 1746 | u'\u213D': 'y', 1747 | u'\u0443': 'y', 1748 | u'\u04AF': 'y', 1749 | u'\u10E7': 'y', 1750 | u'\uFF39': 'y', 1751 | u'\u03A5': 'y', 1752 | u'\u03D2': 'y', 1753 | u'\u2CA8': 'y', 1754 | u'\u0423': 'y', 1755 | u'\u04AE': 'y', 1756 | u'\u13A9': 'y', 1757 | u'\u13BD': 'y', 1758 | u'\uA4EC': 'y', 1759 | u'\u01B4': 'y', 1760 | u'\u024F': 'y', 1761 | u'\u04B1': 'y', 1762 | u'\u00A5': 'y', 1763 | u'\u024E': 'y', 1764 | u'\u04B0': 'y', 1765 | u'\U0001D433': 'z', 1766 | u'\U0001D467': 'z', 1767 | u'\U0001D49B': 'z', 1768 | u'\U0001D4CF': 'z', 1769 | u'\U0001D503': 'z', 1770 | u'\U0001D537': 'z', 1771 | u'\U0001D56B': 'z', 1772 | u'\U0001D59F': 'z', 1773 | u'\U0001D5D3': 'z', 1774 | u'\U0001D607': 'z', 1775 | u'\U0001D63B': 'z', 1776 | u'\U0001D66F': 'z', 1777 | u'\U0001D6A3': 'z', 1778 | u'\U000118C4': 'z', 1779 | u'\U000102F5': 'z', 1780 | u'\U000118E5': 'z', 1781 | u'\U0001D419': 'z', 1782 | u'\U0001D44D': 'z', 1783 | u'\U0001D481': 'z', 1784 | u'\U0001D4B5': 'z', 1785 | u'\U0001D4E9': 'z', 1786 | u'\U0001D585': 'z', 1787 | u'\U0001D5B9': 'z', 1788 | u'\U0001D5ED': 'z', 1789 | u'\U0001D621': 'z', 1790 | u'\U0001D655': 'z', 1791 | u'\U0001D689': 'z', 1792 | u'\U0001D6AD': 'z', 1793 | u'\U0001D6E7': 'z', 1794 | u'\U0001D721': 'z', 1795 | u'\U0001D75B': 'z', 1796 | u'\U0001D795': 'z', 1797 | u'\U000118A9': 'z', 1798 | u'\u1D22': 'z', 1799 | u'\uAB93': 'z', 1800 | u'\uFF3A': 'z', 1801 | u'\u2124': 'z', 1802 | u'\u2128': 'z', 1803 | u'\u0396': 'z', 1804 | u'\u13C3': 'z', 1805 | u'\uA4DC': 'z', 1806 | u'\u0290': 'z', 1807 | u'\u01B6': 'z', 1808 | u'\u01B5': 'z', 1809 | u'\u0225': 'z', 1810 | u'\u0224': 'z', 1811 | u'\u1D76': 'z', 1812 | u'\u2010': '-', 1813 | u'\u2011': '-', 1814 | u'\u2012': '-', 1815 | u'\u2013': '-', 1816 | u'\uFE58': '-', 1817 | u'\u06D4': '-', 1818 | u'\u2043': '-', 1819 | u'\u02D7': '-', 1820 | u'\u2212': '-', 1821 | u'\u2796': '-', 1822 | u'\u2CBA': '-' 1823 | } 1824 | 1825 | def unconfuse(domain): 1826 | if domain.startswith('xn--'): 1827 | domain = domain.encode('idna').decode('idna') 1828 | unconfused = '' 1829 | for i in range(len(domain)): 1830 | if domain[i] in confusables: 1831 | unconfused += confusables[domain[i]] 1832 | else: 1833 | unconfused += domain[i] 1834 | 1835 | return unconfused 1836 | 1837 | 1838 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2019.11.28 2 | certstream==1.11 3 | chardet==3.0.4 4 | click==7.1.1 5 | click-plugins==1.1.1 6 | colorama==0.4.3 7 | idna==2.9 8 | python-Levenshtein==0.12.0 9 | PyYAML==5.3.1 10 | requests==2.23.0 11 | six==1.14.0 12 | termcolor==1.1.0 13 | tld==0.11.11 14 | urllib3==1.25.8 15 | websocket-client==0.57.0 16 | XlsxWriter==1.2.8 17 | -------------------------------------------------------------------------------- /suspicious.yaml: -------------------------------------------------------------------------------- 1 | keywords: 2 | # Generic suspicious 3 | 'login': 25 4 | 'log-in': 25 5 | 'sign-in': 25 6 | 'signin': 25 7 | 'account': 25 8 | 'verification': 25 9 | 'verify': 25 10 | 'webscr': 25 11 | 'password': 25 12 | 'credential': 25 13 | 'support': 25 14 | 'activity': 25 15 | 'security': 25 16 | 'update': 25 17 | 'authentication': 25 18 | 'authenticate': 25 19 | 'authorize': 25 20 | 'wallet': 25 21 | 'alert': 25 22 | 'purchase': 25 23 | 'transaction': 25 24 | 'recover': 25 25 | 'unlock': 25 26 | 'confirm': 20 27 | 'live': 15 28 | 'office': 15 29 | 'service': 15 30 | 'manage': 15 31 | 'portal': 15 32 | 'invoice': 15 33 | 'secure': 10 34 | 'customer': 10 35 | 'client': 10 36 | 'bill': 10 37 | 'online': 10 38 | 'safe': 10 39 | 'form': 10 40 | 41 | # Apple iCloud 42 | 'appleid': 70 43 | 'icloud': 60 44 | 'iforgot': 60 45 | 'itunes': 50 46 | 'apple': 30 47 | 48 | # Email 49 | 'office365': 50 50 | 'microsoft': 60 51 | 'windows': 30 52 | 'protonmail': 70 53 | 'tutanota': 60 54 | 'hotmail': 60 55 | 'gmail': 70 56 | 'outlook': 60 57 | 'yahoo': 60 58 | 'google': 60 59 | 'yandex': 60 60 | 61 | # Social Media 62 | 'twitter': 60 63 | 'facebook': 60 64 | 'tumblr': 60 65 | 'reddit': 60 66 | 'youtube': 40 # some false positives 67 | 'linkedin': 60 68 | 'instagram': 60 69 | 'flickr': 60 70 | 'whatsapp': 60 71 | 72 | # Cryptocurrency 73 | 'localbitcoin': 70 74 | 'poloniex': 60 75 | 'coinhive': 70 76 | 'bithumb': 60 77 | 'kraken': 50 # some false positives 78 | 'bitstamp': 60 79 | 'bittrex': 60 80 | 'blockchain': 70 81 | 'bitflyer': 60 82 | 'coinbase': 60 83 | 'hitbtc': 60 84 | 'lakebtc': 60 85 | 'bitfinex': 60 86 | 'bitconnect': 60 87 | 'coinsbank': 60 88 | 89 | # Bank/money 90 | 'paypal': 70 91 | 'moneygram': 60 92 | 'westernunion': 60 93 | 'bankofamerica': 60 94 | 'wellsfargo': 60 95 | 'citigroup': 60 96 | 'santander': 60 97 | 'morganstanley': 60 98 | 'barclays': 50 99 | 'hsbc': 50 100 | 'scottrade': 60 101 | 'ameritrade': 60 102 | 'merilledge': 60 103 | 'bank': 15 104 | 105 | # Ecommerce 106 | 'amazon': 60 107 | 'overstock': 60 108 | 'alibaba': 60 109 | 'aliexpress': 60 110 | 'leboncoin': 70 111 | 112 | # Other 113 | 'netflix': 70 114 | 'skype': 60 115 | 'github': 60 116 | 'onedrive': 60 117 | 'dropbox': 60 118 | 119 | # Miscellaneous & SE tricks 120 | 'cgi-bin': 50 121 | '-com.': 20 122 | '.net-': 20 123 | '.org-': 20 124 | '.com-': 20 125 | '.net.': 20 126 | '.org.': 20 127 | '.com.': 20 128 | '.gov-': 30 129 | '.gov.': 30 130 | '.gouv-': 40 131 | '-gouv-': 40 132 | '.gouv.': 40 133 | # FR specific 134 | 'suivi': 50 135 | 'laposte': 50 136 | 137 | tlds: 138 | '.ga': 139 | '.gq': 140 | '.ml': 141 | '.cf': 142 | '.tk': 143 | '.xyz': 144 | '.pw': 145 | '.cc': 146 | '.club': 147 | '.work': 148 | '.top': 149 | '.support': 150 | '.bank': 151 | '.info': 152 | '.study': 153 | '.click': 154 | '.country': 155 | '.stream': 156 | '.gdn': 157 | '.mom': 158 | '.xin': 159 | '.kim': 160 | '.men': 161 | '.loan': 162 | '.download': 163 | '.racing': 164 | '.online': 165 | '.center': 166 | '.ren': 167 | '.gb': 168 | '.win': 169 | '.review': 170 | '.vip': 171 | '.party': 172 | '.tech': 173 | '.science': 174 | '.business': 175 | 176 | --------------------------------------------------------------------------------