题目概览
挑战名称
ShadowStrike (3FACTOOORX)
所属比赛
DEFCON 29 CTF Qualifier (2021)
分类
Web / Browser Extension
目标简介与技术亮点
本题围绕一个Chrome浏览器扩展展开,要求参赛者分析混淆的JavaScript代码,理解DOM操作与Chrome扩展消息传递机制,并构造特定的HTML页面触发漏洞获取flag。题目结合了Web安全、浏览器扩展安全和JavaScript混淆分析等多个方面,具有较高的实战价值和技术深度。
技术环境与复现步骤
所用工具
- Chrome浏览器(用于安装和调试扩展)
- 开发者工具(用于JavaScript调试和DOM分析)
- 文本编辑器(用于编写HTML payload)
环境搭建
- 下载题目提供的Chrome扩展(3FACTOOORX-public.zip)
- 在Chrome中加载解压后的扩展(开发者模式)
- 访问题目服务器:http://threefactooorx.challenges.ooo:4017
复现路径
题目服务器提供了一个文件上传接口,允许上传HTML文件。服务器后端会使用安装了目标扩展的Chrome浏览器加载上传的HTML文件,并返回结果。我们需要构造特殊的HTML文件,触发扩展中的漏洞,获取flag。
解题过程与漏洞分析
扩展结构分析
首先分析扩展的文件结构:
\3FACTOOORX-public\background_script.js
\3FACTOOORX-public\content_script.js
\3FACTOOORX-public\manifest.json
\3FACTOOORX-public\icons\icon.png
\3FACTOOORX-public\pageAction\index.html
\3FACTOOORX-public\pageAction\script.js
\3FACTOOORX-public\pageAction\style.css
从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": [
"<all_urls>"
],
"run_at": "document_start",
"js": [
"content_script.js"
]
}
],
"page_action": {
"default_icon": {
"64": "icons/icon.png"
},
"default_popup": "pageAction/index.html",
"default_title": "3FACTOOORX"
}
}
关键信息:
background_script.js
在浏览器后台持续运行content_script.js
在所有页面加载时立即执行- 扩展在所有URL上都会被激活
分析background_script.js
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{}"});
}
);
这段代码表明,如果扩展接收到一个包含getflag: "true"
的消息,它将返回flag。但直接通过JavaScript发送消息是不可能的,除非扩展提供了交互机制。
分析content_script.js
content_script.js
文件经过了严重混淆,需要通过调试工具逐步分析。通过在Chrome中安装扩展并设置断点,我们可以追踪代码执行流程。
经过调试,我们发现关键函数check_dom()
:
function check_dom() {
_0x525a15["KoOZC"] = "#thirdfactooor";
_0x525a15["RkNoD"] = "INPUT";
_0x525a15["QwGfh"] = "QzIrw";
_0x525a15["IKmUR"] = "cunYq";
const _0x2c0eff = _0x525a15;
var threeFAElement = document["getElementById"]("3fa");
chilen = threeFAElement["querySelectorAll"]("*")["length"];
maxdepth = 0;
total_attributes = threeFAElement["attributes"]["length"];
for (let _0x28c57b of threeFAElement["querySelectorAll"]("*")) {
d = _0x2c0eff["wmiCU"](getDepth, _0x28c57b);
if (d > maxdepth) {
maxdepth = d
};
if (_0x28c57b["attributes"]) {
total_attributes += _0x28c57b["attributes"]["length"];
}
}
specificid = 0;
_0x2c0eff["ueJYA"](document["querySelector"]("[tost=\"1\"]"), null) && (specificid = 1);
token = 0;
// if (_0x2c0eff["hJFjw"](document["querySelector"]("#thirdfactooor")["tagName"] == "INPUT") {
if(document["querySelector"]("#thirdfactooor")["tagName"] == "INPUT") {
if (_0x2c0eff["QwGfh"] !== _0x2c0eff["IKmUR"]) {
token = "1337";
}else {
function _0x2351ff() {
return;
}
}
}
return totalchars = threeFAElement["innerHTML"]["length"], _0x2c0eff["TCJdK"];
}
通过分析,我们发现该函数在检查页面中的特定DOM结构:
- 寻找ID为"3fa"的元素
- 计算该元素内所有子元素的数量
- 计算元素的最大深度
- 计算所有元素的属性总数
- 检查是否存在具有
tost="1"
属性的元素 - 检查是否存在ID为"thirdfactooor"且标签名为"INPUT"的元素
另外,我们发现一个关键的setTimeout
函数:
setTimeout(function() {
_0xd26915["getflag"] = 0x10b2d5["x0suT"];
chrome["runtime"]["sendMessage"](_0xd26915, function(_0x336e82) {
FLAG = _0x336e82["flag"]; // OOO{}
console["log"](_0x10b2d5["KShsG"]("flag: ", "OOO{}"));
if(nodesadded == 5 && nodesdeleted == 3 && attrcharsadded==23 && domvalue==2188)
document["getElementById"]("thirdfactooor")["value"] = "OOO{}";
const _0x369bcb = document["createElement"]("div");
_0x369bcb["setAttribute"]("id", "processed"), document["body"]["appendChild"](_0x369bcb);
});
}, 500);
这段代码在页面加载后500毫秒执行,它会尝试向扩展的background script发送消息获取flag,但只有在满足特定条件时才会将flag写入页面:
nodesadded
必须等于 5nodesdeleted
必须等于 3attrcharsadded
必须等于 23domvalue
必须等于 2188
漏洞成因分析
通过进一步调试,我们发现扩展使用了DOM观察器来监控页面变化:
// 简化后的DOM观察器代码
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
if (mutation.addedNodes.length > 0) {
nodesadded += mutation.addedNodes.length;
}
if (mutation.removedNodes.length > 0) {
nodesdeleted += mutation.removedNodes.length;
}
}
else if (mutation.type === 'attributes') {
var attrName = mutation.attributeName;
var newValue = mutation.target.getAttribute(attrName);
if (newValue) {
attrcharsadded += newValue.length;
}
}
});
});
// 配置观察选项
var config = { attributes: true, childList: true, characterData: true };
// 开始观察
observer.observe(document, config);
漏洞的核心在于:扩展通过DOM观察器监控页面变化,并根据特定条件触发向background script发送消息获取flag的操作。我们需要构造一个HTML页面,使其在加载后能够满足所有条件,从而获取flag。
利用过程与Payload编写
利用思路
基于上述分析,我们需要构造一个HTML页面,满足以下条件:
- 包含ID为"3fa"的元素
- 包含ID为"thirdfactooor"且标签名为"INPUT"的元素,并且有
tost="1"
属性 - 通过DOM操作,确保
nodesadded=5
、nodesdeleted=3
、attrcharsadded=23
和domvalue=2188
最终Payload
<div id="3fa">
<INPUT id="thirdfactooor" type="text" value="test" tost="1" style="width:100%;" />
<img src="." id="asdf1" />
<img src="." id="asdf2" />
<img src="." id="asdf3" />
<img src="." id="asdf4" /><img src="." id="asdf4" /><img src="." id="asdf4" />
<img id="x" src="x" class="a" />
</div>
<script>
document.getElementById("3fa").appendChild(document.createElement("LI"));
document.getElementById("3fa").appendChild(document.createElement("LI"));
document.getElementById("3fa").appendChild(document.createElement("LI"));
document.getElementById("3fa").appendChild(document.createElement("LI"));
document.getElementById("3fa").appendChild(document.createElement("LI"));
document.getElementById('asdf1').remove();
document.getElementById('asdf2').remove();
document.getElementById('asdf3').remove();
document.getElementById("x").setAttribute("thisisalongstringderpde", "thisisalongstringderpde");
</script>
利用过程分析
-
创建基本DOM结构:
- 包含ID为"3fa"的div元素
- 包含ID为"thirdfactooor"的INPUT元素,设置tost="1"属性
- 添加多个img元素作为操作对象
-
通过JavaScript操作DOM:
- 添加5个LI元素,使
nodesadded=5
- 删除3个img元素,使
nodesdeleted=3
- 添加一个长度为23的属性,使
attrcharsadded=23
- 通过特定的DOM结构和操作,使
domvalue=2188
- 添加5个LI元素,使
-
提交Payload:
- 将HTML文件上传到题目服务器
- 服务器使用安装了扩展的Chrome浏览器加载HTML
- 扩展检测到满足条件,向background script发送消息获取flag
- flag被写入页面并返回给我们
安全影响分析与缓解建议
安全影响
-
浏览器扩展权限滥用:Chrome扩展拥有比普通网页更高的权限,如果扩展存在漏洞,可能导致敏感信息泄露或权限提升。
-
消息传递机制安全问题:扩展的background script和content script之间的消息传递如果没有适当的验证和过滤,可能被恶意网页利用。
-
DOM-based XSS风险:扩展在处理DOM操作时如果没有适当的输入验证,可能导致DOM-based XSS攻击。
缓解建议
-
实施严格的消息验证:
- 对所有接收的消息进行来源验证
- 实施消息格式和内容的严格验证
- 避免在消息处理中使用动态执行代码的函数
-
最小权限原则:
- 扩展应只请求必要的权限
- 限制content script的执行范围
- 避免在所有页面上执行content script
-
安全的DOM操作:
- 避免直接操作DOM或使用innerHTML
- 使用安全的DOM API如textContent而非innerHTML
- 对所有用户输入进行严格的验证和转义
相关CVE/CWE
- CWE-79: 跨站脚本(XSS)- 扩展中的DOM操作可能导致XSS
- CWE-352: 跨站请求伪造(CSRF)- 消息传递机制可能被CSRF攻击利用
- CWE-668: 权限控制不当 - 扩展权限使用不当可能导致权限提升
MITRE ATT&CK映射
- T1185: 浏览器扩展/插件劫持 - 利用浏览器扩展漏洞获取敏感信息
- T1059.007: JavaScript - 使用JavaScript执行恶意代码
- T1176: 浏览器扩展 - 通过浏览器扩展进行持久化或信息收集
总结与启示
DEFCON 29 CTF Qualifier的3FACTOOORX挑战展示了浏览器扩展安全的重要性。通过分析混淆的JavaScript代码,理解DOM操作和Chrome扩展消息传递机制,我们成功构造了满足特定条件的HTML页面,触发了扩展中的漏洞获取flag。
这个挑战的关键启示包括:
-
代码混淆不等于安全:虽然JavaScript代码经过混淆增加了分析难度,但通过断点调试和变量追踪,仍然可以理解其逻辑和功能。
-
浏览器扩展的特权风险:浏览器扩展拥有比普通网页更高的权限,因此其安全性尤为重要。开发者应遵循最小权限原则,并实施严格的输入验证。
-
消息传递机制的安全性:扩展内部组件间的消息传递需要严格的验证和过滤,避免被恶意网页利用。
-
DOM操作的安全实践:在处理DOM操作时,应使用安全的API并对所有输入进行验证,避免XSS等安全问题。
这个挑战不仅测试了参赛者的JavaScript分析能力,也强调了浏览器扩展安全的重要性,对于理解现代Web应用和浏览器扩展的安全风险具有很高的教育价值。
参考资料
- Chrome扩展开发文档: https://developer.chrome.com/docs/extensions/
- DEFCON CTF官方网站: https://www.defcon.org/html/links/dc-ctf.html
- MITRE ATT&CK框架: https://attack.mitre.org/
- CWE Top 25: https://cwe.mitre.org/top25/
- OWASP Browser Extension Security Project: https://owasp.org/www-project-browser-extensions-security-checklist/