浏览器是本地主机的网关:使用WebAssembly和Go进行客户端端口扫描
网站倾向于通过浏览器扫描用户的开放端口,以更好地识别新用户或回访用户。浏览器能否滥用“localhost”?能否通过WebAssembly实现这一点?本文将通过实际演示(http://ports.sh)和代码示例(https://github.com/avilum/portsscan)展示浏览器如何被滥用来攻击本地服务,甚至穿透组织或从浏览器运行远程代码。
客户端指纹与代码执行
每个用户在访问网页时都有独特的指纹。客户端指纹帮助网站在多个网站间跟踪用户活动。指纹由设备、浏览器、屏幕大小、IP地址等多种因素组合而成。网站(如eBay)通过JavaScript等前端技术在用户计算机上运行代码。随着技术的发展,JavaScript、TypeScript、Deno等语言逐渐普及,而WebAssembly(WASM)的出现使得下一代恶意软件更加复杂。
WebAssembly运行时允许将语言编译为二进制代码,由浏览器的WebAssembly运行时执行。WASM不仅速度更快,还解耦了编程语言,专注于“做什么”。尽管WASM带来了许多新API和功能,但它也成为安全研究者和黑客的目标。目前,Rust、Go等语言已提供对WebAssembly的现成支持。
研究WebAssembly运行时(使用Go)
本文探讨了如何通过浏览器上下文映射主机的开放端口,并使用低级语言实现。端口扫描技术用于发现资产和服务器,许多操作系统在启动时会在localhost上运行服务(如IPC、SSH、SMTP等)。通过WASM,可以轻松发现易受攻击的服务。
作者选择Go语言,因其易于使用的Net/Socket和HTTP标准库API。以下是实现流程:
- 用户访问网页。
- 浏览器初始化WebAssembly运行时。
- 自动运行编译为WebAssembly二进制的Go端口扫描器。
编写端口扫描器
作者尝试了多种方法,发现浏览器代理(有时会阻止)WebAssembly请求和响应。最终选择使用Go的“http”包,因为浏览器主要处理应用层协议(如HTTP)。以下是关键发现:
- 响应分类:连接拒绝(端口关闭)、超时(端口可能开放或关闭)、HTTP响应(端口开放且有HTTP服务)。
- CORS问题:localhost的HTTP服务通常缺少跨域头,浏览器会阻止请求。通过添加特定HTTP头,作者成功绕过了这一问题。
- TLS/SSL服务:跳过SSL握手可以扫描任何TCP开放端口,而不仅是支持SSL的服务。
实际演示
作者通过Python启动本地服务器(python3 -m http.server 5000
),并在浏览器中运行端口扫描。扫描结果通过netstat和nmap验证,确认了WASM扫描器的准确性。
安全风险与攻击场景
localhost通常被视为“安全”环境,但本文展示了如何通过浏览器轻易扫描和攻击本地服务。以下是两个攻击场景:
- Linux RPC漏洞(CVE-2017-8779):通过访问网页触发拒绝服务攻击。
- Windows打印后台程序远程代码执行漏洞(CVE-2021-34527):利用浏览器访问本地服务,以SYSTEM权限运行任意代码。
结论
本文展示了网页如何通过WebAssembly与用户的本地主机服务通信,并映射其网络。尽管目前无法使用原始TCP/UDP会话,但随着WASI标准的推进,浏览器的攻击面将进一步扩大。WebAssembly和WASI是强大的技术,但浏览器作为操作系统的发展趋势也带来了严重的安全风险。
演示地址:
- HTTP服务扫描:http://ports.sh
- HTTPS服务扫描:https://ports.sh
代码仓库:https://github.com/avilum/portsscan(欢迎贡献!)