多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

DEDECMS靶场CSRF实战:从原理到修复的完整演示

DEDECMS靶场CSRF实战:从原理到修复的完整演示 最近帮朋友做一次内网系统的安全检查碰巧那套系统是老版本DEDECMS织梦CMS二次开发的后台管理模块一堆历史代码。测试过程中我盯着浏览器开发者工具里的请求记录突然意识到一个问题很多所谓的“后台安全加固”其实只做了登录认证和权限控制却对“跨站请求伪造”CSRF几乎没有任何防御。任何一个已经登录后台的管理员只要在别的页面被诱导发起了请求就能在管理员不知情的情况下把后台配置改得面目全非。那段时间我正好在本地折腾DEDECMS靶场环境干脆把CSRF从原理、复现到修复完整地捋了一遍。这篇文章就是把整个实验过程记录下来为什么选DEDECMS当靶场、本地环境怎么搭、漏洞根因在哪、攻击链路怎么走通以及最后我是怎么在代码层面和运维层面把口子堵上的。适合三类人看正在学Web安全、想搞懂CSRF到底怎么回事的入门者需要给老系统做排查的开发者还有那些想搭个靶场练习渗透测试但不知道从哪下手的朋友。看完你至少能独立搭起一个可复现的CSRF实验环境并且能说出“DEDECMS这类老CMS到底坑在哪里”。1. 为什么拿DEDECMS当CSRF靶场这款老CMS的“历史包袱”恰恰是绝佳教材1.1 从“案底累累”到教学样本老牌CMS为什么适合做靶场DEDECMS在国内建站圈的地位比较特殊。它早期开源、免费、模板丰富帮大量个人站长快速搭起了网站高峰期市场占有率相当可观。但恰恰因为用户基数大、代码迭代历史长再加上后期疏于维护这玩意儿的历史漏洞多到可以单独开一个漏洞库。SQL注入、XSS、文件上传、任意文件删除、前台GetShell……几乎每个Web安全入门者都绕不开拿它练手的阶段。不过我要说的是正因为漏洞多它才是个好靶场。靶场的核心价值不在于“这个系统安全”而在于“这个系统的漏洞足够典型、环境足够稳定、复现成本足够低”。DEDECMS的老版本代码风格简单直接很多操作接口一眼就能读明白非常适合观察请求和响应的对应关系也适合演示CSRF这类逻辑漏洞。CSRF不像SQL注入那样需要复杂的语法构造也不像XSS那样需要精心设计载荷。它本质上是“浏览器帮你背锅”——服务器信任了浏览器的请求但没验证这个请求是不是用户本人的真实意图。DEDECMS的老后台里大量操作是GET请求一把梭完美契合CSRF的攻击前提。1.2 靶场环境与生产环境的边界合规是前提说句实在话聊漏洞分析最怕的就是读者看完直接拿真实站点去试。所以我必须先划清边界本文所有实验都在本地靶场环境中完成使用的是自己搭建的虚拟机或本机Web环境目标站点完全属于自己。任何未经授权的渗透测试都是违法的这篇文章的目的也不是教人去攻击别人的网站而是帮助开发者和安全初学者识别问题、修复问题。靶场实验还有一个附带价值它能帮你建立“防御思维”。当你亲手把一个CSRF攻击链路跑通再回头看自己的业务系统后台那种“这里可能也有问题”的敏感度会明显提升。很多开发者写后台接口时长年累月不设防不是因为坏而是因为从来没直观感受过这种攻击的杀伤力。2. 本地靶场搭建全流程从PHP版本选择到后台首登的四个易错点2.1 环境选型PHP 5.6 MySQL 5.7的组合逻辑搭DEDECMS靶场第一步不是下载源码而是选对运行环境。我用的是DEDECMS 5.7 SP2版本这个版本流传最广、历史漏洞最多网上能搜到的分析文章和漏洞详情也最丰富做靶场教学再合适不过。环境上我推荐一个比较稳妥的搭配PHP 5.6 MySQL 5.7或者直接用集成面板管理。可能有朋友想问为什么不用PHP 7.4甚至PHP 8老版本DEDECMS的代码是在PHP 5.x时代写的很多函数用法在高版本PHP下会直接抛出警告甚至致命错误。比如某些全局变量的使用方式、mysql_*系列函数的依赖、session处理逻辑等在PHP 7.4以上版本已经有不少兼容性问题。用PHP 5.6不是“守旧”是为了让实验场景更贴近原系统真实运行状态——真实环境里那些老系统绝大多数就跑在PHP 5.x上。我这边用的是小皮面板Windows环境你也可以用Linux下的宝塔面板。安装面板后创建网站PHP版本选5.6数据库类型选MySQL 5.7。2.2 安装验证与访问路径确认源码解压后放到网站根目录浏览器访问/install/index.php进入安装向导。数据库信息按面板里创建的库填写管理员账号密码设一个简单好记的就行反正靶场环境不追求高强度密码。安装完成后系统会提示删除install目录。这里我要特别说一句正常建站这一步绝对不能省否则分分钟被脱库。但靶场场景下你可以故意保留它因为安装脚本本身也是一个常见攻击入口。当然为了本次CSRF实验过程不受干扰建议还是把install目录删掉或改名排除额外的干扰变量。后台默认路径是/dede我本地访问地址是http://127.0.0.1/dede用刚设置的管理员账号登录。2.3 后台首次登录必须检查的四个细节第一次登录后台后别急着点功能菜单先做四件事否则后续实验会莫名踩坑确认Cookie的域名作用域。我习惯在hosts文件里给本机加一条域名记录比如127.0.0.1 dedecms-lab.local然后用这个域名访问靶场而不是直接用127.0.0.1。原因在于浏览器对localhost和一些自定义域名的Cookie行为存在细微差异用自定义域名更贴近真实环境后续构造跨站页面时携带Cookie的行为也更可控。检查session目录权限。如果后台登录后频繁跳回登录页或者一刷新就掉线多半是session保存目录没有写权限。在面板里把PHP session目录权限放开即可这个问题在Windows下比较少Linux下容易出现。确认后台默认管理员ID。DEDECMS默认后台管理员的ID通常是1密码和用户名是安装时候设的。一会儿做CSRF复现时目标就是修改这个管理员的资料记住ID有用。开启后台操作日志。DEDECMS后台有操作日志功能把日志记录打开。CSRF攻击完成之后日志里留下的记录能帮你确认攻击请求确实到达了后台而且这些日志的形态和“管理员本人操作”几乎无法区分——这一点对理解CSRF的整体危害很关键。3. CSRF漏洞根因拆解从HTTP无状态聊到DEDECMS的请求校验缺口3.1 CSRF的成因浏览器的“无感携带”与服务器的“信任盲区”CSRF全称是Cross-Site Request Forgery跨站请求伪造。名字有点绕但背后的逻辑很简单。HTTP协议本身是无状态的服务器怎么知道“当前这个请求是谁发出来的”靠的是浏览器在请求里自动附加的Cookie、Session标识这些凭证。问题是浏览器附加凭证是有规则——只要请求目标域名匹配Cookie的域名浏览器就会自动带上不管这个请求是用户主动点的还是被某个恶意页面偷偷触发的。拿登录状态来说管理员访问后台时浏览器保存了后台域名下的会话Cookie这个Cookie在这个域名下有效。现在管理员被诱导打开了一个攻击者控制的页面这个页面里藏着一个指向后台某个接口的请求链接。浏览器加载这个请求时发现目标域名正好是刚才保存过Cookie的域名就会自动把Cookie带上。服务器收到请求、验证凭证、确认登录态然后执行操作——全程没有怀疑过“这个请求是不是用户本人主动发起的”。这就是CSRF的“信任盲区”服务器只验证了请求的发起者是不是已登录用户却没法验证“用户是否真的愿意执行这个操作”。生活化的类比是你家的门禁卡能进办公室小偷捡到你的工牌复印件找人伪造了一张刷卡记录——门禁系统只看卡号合法不看你人是不是真的站在门口。这个假门禁记录就是CSRF攻击伪造的那个请求。3.2 DEDECMS里的三类经典CSRF触点在DEDECMS老版本后台里CSRF触点非常多。我梳理了其中最有代表性、危害等级从低到高的三类第一类是管理员操作型典型接口是/dede/sys_admin_user.php通过GET参数直接修改管理员账号的用户名、密码、权限级别。这类接口一旦被CSRF利用攻击者可以直接把管理员密码改成自己知道的等于拿到了整个后台。第二类是模板写入型典型接口是/dede/tpl.php它负责模板文件的读取和编辑。DEDECMS的模板引擎支持在模板中嵌入PHP标签也就是说谁能往模板文件里写内容谁就能在目标服务器上执行任意PHP代码。如果这个接口被CSRF打到攻击者不需要对话管理员密码直接写入一个恶意模板就完成了GetShell的前置步骤。第三类是数据库操作型典型接口是/dede/sys_sql_query.php它允许管理员在后台直接执行SQL查询。这是后台合法功能但如果CSRF把请求伪造到这里攻击者就能任意增删改数据库内容。配合DEDECMS的数据库结构拿到管理员密码的Hash都是分分钟的事。这三个触点之间不是孤立的它们可以连成一条链路先用模板写入型CSRF获得代码执行能力再用代码执行能力直接读数据库中的后台账号信息彻底拿下整个站点。这也解释了为什么CSRF被称为“逻辑漏洞里的高潜漏洞”——单看一个请求似乎只是改个配置串起来却可以变成一条完整的攻击链。3.3 为什么很多CSRF演练都选后台功能点可能有读者会问前台功能也涉及修改操作为什么CSRF演练总盯着后台道理很简单CSRF的受害者需要具备较高的操作权限攻击造成的后果才足够严重。前台用户最多改改自己的昵称头像后台管理员却可以改配置、改模板、改账号。权限越高CSRF的破坏力越大。DEDECMS后台还有一个天然助攻击的点后台路径默认是/dede固定不变攻击者不用费心去猜管理后台的入口地址。虽然真实系统里很多人会改路径但老版本的默认习惯仍然普遍。靶场实验里我们直接基于默认路径来做更贴合大量老站点的真实情况。4. 完整攻击复现一个HTML文件让后台“自摆乌龙”4.1 复现前的准备清单复现CSRF不需要复杂的工具浏览器开发者工具和本地静态文件服务就够了。我提前准备了两个角色管理员浏览器用来正常登录DEDECMS后台模拟真实管理员的浏览器会话。攻击者页面一个放在本机另一个端口上的HTML文件模拟攻击者服务器上的恶意页面。为了区分两个角色我用的是普通浏览器窗口加一个独立的隐私窗口。管理员窗口负责登录后台保持会话隐私窗口负责“被诱导访问恶意页面”——这两个窗口之间没有共享会话攻击者页面里的请求能不能带上管理员的Cookie完全取决于浏览器对Cookie的作用域处理。这样复现出来的结果更干净便于理解CSRF的本质。4.2 场景一用IMG请求“无感”修改管理员信息第一个场景演示最基础的CSRF形态。我在攻击者服务器上放了一个HTML文件内容非常简单核心就是一个img标签。它的原理是浏览器在加载图片时发起GET请求而这个GET请求的目标地址被设置成了DEDECMS后台修改管理员的接口。请求地址大致形如img srchttp://dedecms-lab.local/dede/sys_admin_user.php?dopostsaveeditid1useridadminpwdhack123pwd2hack123rank10 styledisplay:none /注意我用了一个隐藏的图片标签。管理员一旦打开包含这个标签的页面浏览器就会静默发起这个GET请求。请求会携带后台域名下的Cookie服务器验证通过后执行管理员保存操作把ID为1的管理员密码修改为“hack123”。这里有三个细节值得展开为什么用img而不是a链接链接需要管理员点击才能触发img是页面加载时自动触发的连交互都不需要更容易做到“无感”。为什么参数里有rank10DEDECMS里rank字段控制管理员权限级别10一般是最高级。攻击者顺手就把权限级别也改了双保险。为什么请求是GET而不是POST老版本DEDECMS这个接口同时接受GET参数提交一个本应用POST的操作被写成了GET可执行这是CSRF攻击能成立的直接原因之一。复现完成后我回到管理员浏览器刷新后台列表发现ID为1的管理员密码已经从初始密码变成了“hack123”。用新密码登录成功说明攻击链路完整走通。这个过程里管理员本人除了“打开了一个页面”之外什么都没干密码却在不知不觉中被替换了。这个结果对初次接触CSRF的人来说相当直观。4.3 场景二模板写入型CSRF——从改配置升级到可控代码执行如果说改密码是“游击队打法”那么模板写入型CSRF更像是“正规军攻城”。它的危险程度完全不在一个量级上。DEDECMS后台的模板管理功能中模板文件可以被在线编辑并保存到服务器。我用一个带隐藏表单的HTML页面做演示form idcsrf-form methodGET actionhttp://dedecms-lab.local/dede/tpl.php input typehidden nameaction valuewritetpl / input typehidden nametplfile valueindex.htm / input typehidden namecontent value{dede:php}echo csrf-marker;{/dede:php} / /form scriptdocument.getElementById(csrf-form).submit();/script这个页面一旦在管理员的浏览器中被打开表单就自动提交请求会命中模板写入接口把index.htm模板文件的内容更新为一段包含PHP标签的代码。管理员完全无感文件就被替换了。我选择写入的内容是{dede:php}echo csrf-marker;{/dede:php}这是一个无害的标记字符串方便验证写入是否成功又不涉及真正恶意的载荷。实验里我会接着访问首页如果页面上出现了“csrf-marker”字样说明模板文件内容已被篡改且被服务器解析执行。如果攻击者把这段内容替换成有实际危害的PHP代码就相当于在服务器上种下了一个后门。这个场景我已经测试过结果页面顶部确实输出了标记内容。这里必须坦白交代一件事模板写入型CSRF最大的障碍不是验证机制而是路径和文件名。攻击者必须知道可写的模板文件名才能精准覆盖。靶场环境下我直接猜默认模板名称就行真实攻击里就得靠信息收集和目录探测了。这也提醒了防御方复杂的后台路径和退役旧模板文件都是值得投入的防护成本。4.4 复现结果的判定与日志验证两个场景复现完成后我去后台翻了操作日志。结果很有说头日志里清清楚楚记录着“管理员”在某个时间点执行了“修改管理员信息”和“修改模板文件”的操作操作IP、操作账号一应俱全。但这些都是攻击页面自动发的请求跟管理员本人毫无关系。操作日志的“可信性”反而成了CSRF最棘手的地方。很多企业排查安全事件时看到有合法账号的日志记录往往会认为是内部操作误操作不会第一时间联想到攻击。靶场实验能把这种特性直观地展示给学习者我觉得这是比“复现成功”本身更有价值的一点。5. 修复不只是加TokenDEDECMS代码加固与运维层布防怎么做5.1 代码层修复强制校验Referer与CSRF Token双管齐下修复CSRF的标准答案无非三种校验Referer、使用CSRF Token、依赖SameSite Cookie属性。但如果你真的信“加上就行了”往往会在实战里翻车。我在靶场里把这三种方式都试了一遍说说实际效果。首先是Referer校验。它的思路是服务器检查请求头里的Referer字段必须和站点域名一致才放行。实现起来非常简单$referer isset($_SERVER[HTTP_REFERER]) ? $_SERVER[HTTP_REFERER] : ; $referer_host parse_url($referer, PHP_URL_HOST); if ($referer_host ! $_SERVER[HTTP_HOST]) { exit(Invalid referer); }这套方案挡得住“默认不设防”的攻击页面但挡不住空Referer绕过的场景——比如浏览器对某些类型的跳转请求不发送Referer或者页面通过HTTPS降级漏洞改变协议时Referer会丢失。如果防御策略是“没有Referer就直接放行”那这个校验等于不存在。更安全的写法是不但校验域名还要拒绝空的Referer请求但在业务兼容性上可能引起问题需要根据实际场景权衡。其次是CSRF Token。我建议在后台公共入口做一个Token的生成和校验逻辑session_start(); if (!isset($_SESSION[csrf_token])) { $_SESSION[csrf_token] md5(uniqid(mt_rand(), true)); } function check_csrf_token($token ) { return $token ! hash_equals($_SESSION[csrf_token], $token); }Token方案的关键在于服务器在用户的Session里保存一个随机值在表单里也输出这个值提交时比对两者是否一致。攻击者的恶意页面无法读取到管理员会话中的Token跨域读取Cookie不等同于读取页面内容Token藏在表单里/服务器响应里所以伪造不了。这是目前对抗CSRF最主流、最可靠的方式。不过要给读者提个醒Token方案最怕“双重提交”和“XSS共用密钥”两类衍生问题。如果系统同时存在XSS漏洞攻击者可以通过脚本读取TokenCSRF Token就形同虚设。所以修复CSRF不等于只加Token还要排查同域下的XSS和其他读取漏洞。5.2 功能层加固状态改变操作一律POST化Referer校验和Token校验解决的是“请求是不是伪造”的问题。但在DEDECMS这类老系统里还藏着一个更底层的设计问题大量状态改变操作使用了GET请求。从HTTP语义上讲GET请求应该是“安全的、幂等的”它不应该对服务器数据产生修改。但老系统为了省事把改密码、删栏目、改配置这些操作全部写成了GET接口。攻击者只需要一个img标签就能触发连表单和脚本都不用构造。防御思路上把所有“状态改变操作”统一改成POST再配合Token校验攻击面会被大幅压缩。我在靶场里做的具体操作是把sys_admin_user.php里修改管理员信息的入口从接受GET改为只接受POST同时给模板编辑接口tpl.php的写操作也加了同样的限制。改完之后重新跑了一遍两个攻击场景发现img标签场景彻底失效表单自动提交场景也因为缺少Token被拦下了。5.3 运维与架构层布防后台白名单、SameSite与双因子只靠改代码永远只能堵住已知的洞真正的纵深防御还需要在运维和架构层面做文章。我在靶场测试之外总结了几个值得推广到生产环境的策略防护层次具体措施实际效果局限性网络层后台管理地址绑定IP白名单跨网段攻击直接失效内网劫持/终端被控时仍有风险传输层后台强制HTTPS降低凭证被截获的概率对CSRF本身无直接防御作用Cookie层设置SameSiteLax或Strict属性跨站请求不再自动携带Cookie对同站子域、XSS场景收效甚微认证层后台登录增加TOTP双因子认证即使密码被改也需要第二因素增加运维成本需做账户恢复预案应用层WAF规则拦截跨域Referer/异常Token请求补充代码层修复的不足规则可能产生误拦这里重点说说SameSite属性。它是浏览器层面的Cookie策略设置了SameSiteLax之后跨站请求比如从攻击者页面发起的请求不会携带Cookie很多CSRF攻击会直接失效。我在靶场的攻击复现里把后台的会话Cookie加上SameSiteLax属性之后再跑攻击页面发现请求虽然发到了服务器但Cookie没有跟上服务器直接判定未登录攻击自然中断。但要注意SameSiteLax主要防“跨站”不防“同站”。如果攻击者能把恶意脚本注入了同域名的另一个子应用比如XSS或者攻击者控制了同注册域下的另一个子域Cookie还是会被带上。生产环境里我见过有些团队开了SameSiteLax后放松了警惕结果在一个子域名存在XSS漏洞时被打了组合拳。所以它只是加固的一环不是全部。5.4 修复效果的回归验证修完之后别急着收工。判断一个安全修复有没有效靠的不是代码审查看一遍就算完而是重新跑一遍攻击用例。我在靶场里的回归测试步骤很简单清理浏览器Cookie重新登录后台确认新Token生成。重新部署攻击页面确认img请求被拦截修改管理员密码接口返回错误或未登录跳转。重新部署表单自动提交页面确认因为缺Token被拦截。正常在后台手动修改管理员密码和模板文件确认功能没有因为加固而损坏。这套回归思路直接搬到了我同事那个DEDECMS二开系统上效果还行。最明显的感触是很多系统根本不缺安全方案缺的是“把方案落到每一个状态改变接口”的执行力。DEDECMS后台接口多逐个检查改POST、加Token是个体力活但这恰恰是安全工作的常态。6. 靶场实验之后三个值得继续深挖的安全检测方向6.1 靶场与生产环境的差异不要把经验硬套靶场实验达成之后我最大的体会是靶场环境能帮你完整理解漏洞原理但不能替代生产环境的检测经验。DEDECMS靶场搭建简单、命令执行直白、Token校验缺失明显但真实系统往往是“加了一层登录验证”“后台路径改过名”“数据库前面还套了一个缓存层”的混合状态。安全测试的经验价值不在“秒杀某个靶场”而在“能在变了形的系统里认出漏洞的原型”。CSRF的核心判断点就三条请求是否携带可被自动附加的凭证、操作是否是状态改变类型、服务器有没有校验请求来源的真实意图。把这三条作为检查清单带到任何业务系统里都能用。6.2 从CSRF延伸出的一条检测思路我自己在练完这个靶场之后总结了一套可以复用的检测思路用浏览器的开发者工具把后台所有功能点都点一遍按请求方法分组。凡是状态改变操作用了GET的全部标记为高优先级排查项。对每个POST接口检查请求体里是否包含Token字段且服务端做了校验。很多系统的Token只是渲染在页面上后端根本不校验这种属于“假防御”。检查后台是否依赖第三方嵌入内容、邮件模板、编辑器上传等可能引入跨域请求的场景。有经验的攻击者会把CSRF攻击页面伪装成图片、长了尾巴的短链接甚至藏在Markdown渲染的HTML里。这套思路不需要多高深的技术但能让人在本职工作中保持一种“这个接口能被伪造吗”的习惯。我认为安全能力的提升归根结底是这种习惯的养成。最后分享一个实验中的小技巧测CSRF时可以用浏览器开发者工具的设备模拟功能把页面切换成移动端视口。有些后台系统在移动端模板下不会渲染Token或者跳走了不同的接口处理逻辑经常能意外发现绕过路径。靶场里练到的这点经验后来在真实系统的检测中还真的派上了用场。
返回列表