Compare commits

...

2 Commits

Author SHA1 Message Date
Achim D. Brucker 98073736fc Added basic documentation. 2019-08-10 14:09:48 +01:00
Achim D. Brucker 3311ba575e Initial commit. 2019-08-10 11:58:04 +01:00
2 changed files with 137 additions and 2 deletions

View File

@ -1,7 +1,37 @@
# Unsanitize Safelinks: A Utility for Microsoft's Safelinks
Both the home and personal online offerings of Microsoft Outlook (e.g., Outlook.com, Office 365 Home,
or Office 365 Personal) and the professional Office 365 offerings (e.g., as part of Office 365 Advanced
Threat Detection) might rewrite links in received emails with the goal of protecting users against
certain treats (e.g., phishing).
For various reasons, one might to rewrite these `"safelinks" back into their original form. The script
[unsantize-safelinks](./unsantize-safelinks) does exactly this. This can, for example, be used for
displaying mails with mails nicely in [mutt](https://www.mutt.org). In your "muttrc" you need to
add/edit the following configuration:
```muttrc
set display_filter="unsanitize-safelinks"
```
If you want to also rewrite the links when using tools such as urlscan, use:
```muttrc
macro index,pager \cb "<pipe-message> unsanitize-safelinks| urlscan<Enter>"
```
And the following trick rewrites the links prior to editing a message (e.g., when replying):
```muttrc
set editor ="unsanitize-safelinks -i %s && $EDITOR %s"
```
Finally, if links should be rewritten when viewing the HTML-part, you need to edit your your ".mailcap"
entry for type "text/html":
```mailcap
text/html; unsanitize-safelinks -i --html %s && /usr/bin/sensible-browser %s; description=HTML Text; nametemplate=%s.html
```
## Author
@ -15,6 +45,5 @@ SPDX-License-Identifier: BSD-2-Clause
## Master Repository
The master git repository for this project is hosted
The master git repository for this project is hosted
<https://git.logicalhacking.com/adbrucker/safelinks-tool>.

106
unsanitize-safelinks Executable file
View File

@ -0,0 +1,106 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019 Achim D. Brucker.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# SPDX-License-Identifier: BSD-2-Clause
import sys
import os.path as path
import os
import stat
import argparse
import re
from bs4 import BeautifulSoup
from urllib.parse import urlparse, parse_qs, urlunparse
def sanitize_safelink(url):
if "safelinks.protection.outlook.com" in url:
target = urlparse(parse_qs(urlparse(url).query)['url'][0])
return target.geturl()
else:
return url
def unsanitize_txt(content):
return re.sub(
r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-\'\/\+-;=\?-@.&+_]|[!*,]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)',
lambda x: (sanitize_safelink(x.group(1))), content).rstrip()
def unsanitize_html(content):
soup = BeautifulSoup(content, "html.parser")
for a in soup.findAll('a'):
if a.has_attr('originalsrc'):
a['safelink'] = a['href']
a['href'] = a['originalsrc']
del a['originalsrc']
return str(soup)
def main():
"""Main function of the safelink tool."""
parser = argparse.ArgumentParser()
parser.add_argument(
"--html",
help="HTML",
action="store_true",
default=False)
parser.add_argument(
"-i",
"--in-situ",
help="modify file",
action="store_true",
default=False)
parser.add_argument(
"-v", "--verbose", help="increase verbosity", action="store_true")
parser.add_argument('file', nargs='?', default=None)
args = parser.parse_args()
# parse command line
if args.file:
fhandle = open(args.file)
else:
fhandle = sys.stdin
content = ""
for line in fhandle:
content += line
if fhandle is not sys.stdin:
fhandle.close()
if args.html:
content=unsanitize_html(content)
else:
content=unsanitize_txt(content)
if args.file and args.in_situ:
st = os.stat(args.file)
os.chmod(args.file, st.st_mode | stat.S_IWRITE)
with open(args.file, "w+") as fhandle:
fhandle.write(content)
fhandle.truncate()
fhandle.close
else:
print(content)
if __name__ == "__main__":
main()