ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CTF做题不是靠猜:常见Web安全题型的分析思路与排查方法总结

CTF做题不是靠猜:常见Web安全题型的分析思路与排查方法总结 一、引言为什么猜是CTF Web题最大的敌人打过几场CTF的人都会有一种熟悉的挫败感面对一个登录框把admin or 11#、admin--、 or 11挨个丢进去页面纹丝不动换个思路拿字典跑目录跑出robots.txt和index.php就再无下文。最后看WP发现入口是响应头里一个不起眼的X-Powered-By: PHP/7.4.3配合题目给的附件版本号指向一个特定CVE。问题不在于payload背得少而在于把解题过程当成了穷举而不是推理。CTF Web题和真实渗透最大的区别是题目一定是可解的出题人必然留下了一条完整的证据链。这条链通常由三部分组成——信息泄露点 → 逻辑缺陷点 → 利用原语。所谓猜本质是跳过了前两步直接在第三步盲试。而专业选手的做法是先穷尽信息收集再基于收集到的信息做可证伪的假设最后用最小成本的实验去验证假设。本文按这个思路梳理几类高频Web题型的分层排查方法。补充什么是可证伪的假设假设不是这里可能有SQL注入而是如果参数id存在单引号闭合的SQL注入那么提交id1应该导致数据库报错页面返回500或出现SQL语法错误信息。这个假设可以被实验证伪如果页面正常返回假设就不成立。专业选手的思维流程是观察 → 提出假设 → 设计实验 → 收集结果 → 更新假设。每一步都留下记录避免重复劳动。很多队伍在比赛中反复尝试同一个payload就是因为没有把失败的结果转化为排除条件。补充信息泄露点的常见位置。除了响应头还包括HTML注释中的调试信息、JS文件里的API路径、robots.txt中的隐藏目录、/.git/泄露的源码、/.svn/、www.zip、backup.sql、index.php.bak、Dockerfile、docker-compose.yml、package.json、composer.json。甚至错误页面的Stack trace会暴露绝对路径和框架版本。信息收集阶段的目标不是找到漏洞而是画出一张地图知道有哪些入口、哪些技术栈、哪些可能的信任边界。补充逻辑缺陷点的典型形式。逻辑缺陷往往不是代码层面的漏洞而是业务规则被绕过。例如注册时前端限制用户名不能为admin但后端没有校验修改密码时通过user_id参数越权修改他人密码优惠券可以重复使用订单金额在前端计算后端直接信任文件下载功能只校验文件名后缀不校验文件路径。这些缺陷的共同点是校验发生的位置与使用数据的位置不一致。做题时看到任何校验都要问一句这个校验是在前端还是后端校验的对象和使用时的对象是同一个吗补充利用原语的组合。单一漏洞往往不足以getshell但多个小漏洞可以串联。例如任意文件读取 日志包含 代码执行SSRF Redis未授权 写文件XSS CSRF 越权操作。出题人通常会把利用链拆成几个步骤每一步都对应一个信息泄露点或逻辑缺陷点。因此不要轻易放弃一个看起来没用的信息它可能是链条中的一环。二、核心原理Web题的本质是信任边界错位不管题型怎么变漏洞的根源都可以归结为一句话数据从低信任区流入高信任区时没有被正确地重新校验。把它拆成三个可操作的观察维度1. 数据流方向。用户输入 → 应用处理 → 危险汇聚点Sink。危险汇聚点包括SQL 执行、命令执行、文件读写、模板渲染、反序列化、HTTP 请求发出。做题时先找到 Sink再倒推输入是否可控、中间是否被过滤。2. 校验发生的时机。很多题目的漏洞不是没有校验而是校验和使用的对象不一致。比如前端 JS 校验文件后缀、后端只校验Content-Type、解压时用文件名却在校验时用了另一个字段——这就是典型的 TOCTOU检查与使用时间差与解析不一致。3. 黑盒下的可观测信号。没有源码时你唯一能依赖的是行为差异状态码、响应长度、响应时间、回显内容、报错信息、Set-Cookie 变化。把每一次请求的这几个维度记录下来做差分是黑盒排查的基本功。一句话总结方法论先定位 Sink再确定可控性最后绕过过滤构造利用链。补充信任边界的可视化。想象一条数据流水线浏览器 → 前端JS → HTTP请求 → Web服务器 → 后端语言 → 框架 → 业务代码 → 数据库/文件系统/操作系统。每一个箭头都是一个信任边界。低信任区的数据进入高信任区时必须经过校验、过滤、转义或参数化。漏洞就发生在这个边界上要么校验缺失要么校验可以被绕过要么校验后的数据被篡改。例如前端JS校验文件后缀但攻击者可以直接抓包修改请求绕过了前端边界后端只校验Content-Type但攻击者可以修改Content-Type为image/png绕过了传输边界服务端用黑名单过滤后缀但攻击者用.phtml绕过绕过了服务端边界。理解边界就能预测攻击面。补充可观测信号的详细列表与差分方法。黑盒测试时建议用表格记录每次请求的以下字段信号说明可能含义HTTP状态码200/302/403/404/500500常表示后端异常可能注入响应长度Content-Length长度变化可能表示回显差异响应时间毫秒级时间盲注或SSRF的线索回显内容关键字、报错联合注入、报错注入的直接证据Set-Cookie新session、权限标记身份认证逻辑缺陷Location302跳转目标隐藏路径或参数Server/X-Powered-By版本信息已知CVE的入口差分方法发送两个仅有一个参数不同的请求比较上述信号。例如?id1和?id1如果后者返回500且报错包含You have an error in your SQL syntax则SQL注入假设成立。如果两者完全相同则排除单引号闭合。差分是黑盒测试的核心比盲目猜测高效得多。补充为什么从Sink倒推更有效正向从输入推导容易迷失在大量的参数和过滤中。而从Sink倒推目标明确先找到eval、system、unserialize、file_put_contents等危险函数然后问三个问题这个Sink在哪里被调用调用时传入的参数是否可控如果可控中间经过了哪些过滤这种倒推法可以快速定位关键代码避免在无关逻辑上浪费时间。代码审计时尤其如此先用正则搜危险函数再逐个分析调用链比通读全部代码快一个数量级。三、常见题型的分析思路3.1 SQL 注入从有没有到能不能不要一上来就sqlmap。先手工确认三件事闭合方式数字型、单引号、双引号、括号甚至)组合。回显类型联合回显、报错回显、布尔盲注、时间盲注。这决定了后续利用的成本。过滤情况空格、逗号、union、select是否被拦是否有 WAF。只有联合回显才值得上sqlmap盲注场景手工脚本往往更稳。下面是一个带二分优化的布尔盲注脚本importrequests URLhttp://target/index.phpCHARSET0123456789abcdefghijklmnopqrstuvwxyz{}_-SIGHello# 页面中的布尔信号字符串defcond(sql):rrequests.get(URL,params{id:f1 and ({sql})-- -},timeout5)returnSIGinr.textdefextract(sql):result,pos,1whileTrue:lo,hi32,126whilelohi:# 二分逼近 ASCII 值mid(lohi)//2ifcond(fascii(substr(({sql}),{pos},1)){mid}):lomid1else:himidiflo32:# 取到空白/结束符收工breakresultchr(lo)print(result)pos1returnresultprint(extract(select group_concat(flag) from flag))关键点在于用ascii()做数值比较避免引入引号被过滤用二分把单字符的请求数从 95 次压到 7 次。如果目标禁用substr可以换mid、substring如果禁用ascii换ord或直接字符串比较。时间盲注场景下把cond换成基于sleep()的响应耗时判断即可但要注意网络抖动建议每个判定采样 23 次取中位数。补充手工确认注入点的标准流程。第一步判断是否存在注入提交?id1观察是否报错提交?id1 and 11和?id1 and 12观察页面差异。第二步判断闭合方式尝试?id1 --、?id1 --、?id1) --、?id1) --直到页面恢复正常。第三步判断回显类型如果是联合回显用order by确定列数例如?id1 order by 3 --然后?id1 union select 1,2,3 --看回显位置。如果是报错回显用updatexml(1,concat(0x7e,(select database())),1)。如果是布尔盲注用and ascii(substr((select database()),1,1))100。如果是时间盲注用and if(ascii(substr((select database()),1,1))100,sleep(2),0)。第四步判断过滤如果空格被过滤用/**/、、%09代替如果逗号被过滤用join或limit offset如果union被过滤用union all、大小写混合、内联注释/*!union*/。第五步如果确认是联合回显且过滤不严可以用sqlmap自动化命令为sqlmap -u http://target/index.php?id1 --batch --dbs --tables --dump。补充常见问题FAQ。为什么-- -需要空格SQL注释--后面必须跟空格或控制字符否则会被当成减号。在URL中空格需要编码为%20或所以写成-- -或--。为什么用ascii()因为ASCII码是数字可以直接用、比较避免在payload中引入单引号减少被过滤的风险。时间盲注如何减少误判先测量正常请求的基线时间例如?id1平均耗时200ms。然后使用sleep(2)如果响应时间超过2秒则条件为真。每个条件采样23次取中位数避免网络抖动导致的假阳性。盲注脚本跑得太慢怎么办可以使用二分法如上例将单字符的请求数从95次降到7次。还可以使用group_concat一次取出多个值或者用hex()将结果转为十六进制减少特殊字符的干扰。3.2 文件包含与文件上传文件包含题的排查顺序是能不能包含 → 能包含什么 → 内容从哪来。伪协议php://filter/convert.base64-encode/resourceindex.php读源码是第一步很多时候读完源码题目就结束了。无文件上传点时考虑日志包含/var/log/nginx/access.log、Session 文件包含/tmp/sess_xxx、/proc/self/environ。有allow_url_includeOn时data://和php://input是首选。文件上传题的绕过维度是正交的建议按层逐个排除而不是随机组合层级常见校验绕过思路前端JS 后缀白名单抓包直接改传输Content-Type改为image/png服务端后缀黑名单.phtml、.php5、.Php、.php.、.php::$DATA内容getimagesize文件头加 GIF89a解析中间件配置Apache 多后缀1.php.jpg、Nginx%00截断补充伪协议的详细原理与利用条件。php://filter/convert.base64-encode/resourceindex.php将index.php的内容进行base64编码后返回。因为PHP代码被编码不会被解析所以可以读取源码。这是文件包含题最常用的第一步。php://filter/convert.base64-decode/resource...将目标资源的内容进行base64解码。常用于写入文件时绕过内容过滤例如file_put_contents写入的内容不能包含?但可以写入base64字符串然后用php://filter解码。data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjJ10pOz8将base64字符串作为文件内容。需要allow_url_includeOn且PHP版本支持data://。php://input将POST请求体作为PHP代码执行。需要allow_url_includeOn且Content-Type不是multipart/form-data。phar://可以触发反序列化常用于文件操作函数。补充日志包含的详细路径与条件。日志包含需要满足三个条件一是存在文件包含漏洞二是知道日志文件的绝对路径三是能够控制日志内容。常见日志路径Apache/var/log/apache2/access.log、/var/log/httpd/access_logNginx/var/log/nginx/access.logSSH/var/log/auth.log控制日志内容的方法在User-Agent、Referer、URL中插入PHP代码。例如发送请求GET /?php system($_GET[c]);? HTTP/1.1日志中就会记录这段代码。然后通过文件包含?file/var/log/nginx/access.logcid执行。补充Session文件包含。PHP的Session文件通常存储在/tmp/sess_PHPSESSID。如果能够控制Session中的某个值并且知道Session ID就可以包含该文件。例如在登录框的用户名处输入?php system($_GET[c]);?然后通过文件包含?file/tmp/sess_PHPSESSIDcid执行。补充文件上传绕过的更多技巧。.htaccess如果允许上传.htaccess文件可以写入AddType application/x-httpd-php .jpg然后上传1.jpg其中包含PHP代码访问时就会被解析。user.iniPHP的user.ini可以设置auto_prepend_file1.jpg然后上传1.jpg访问任意PHP文件时都会自动包含1.jpg。竞争上传有些题目会先上传临时文件再校验校验失败则删除。可以在删除前访问临时文件执行代码。二次渲染图片上传后会被重新渲染普通图片马会失效。可以使用copy /b 1.png shell.php 2.png合并或者使用GIF89a文件头加PHP代码。解析漏洞Apache的多后缀解析1.php.jpgNginx的%00截断PHP5.3.4IIS的1.asp;.jpg。这些漏洞依赖于中间件版本和配置需要根据题目环境判断。3.3 SSTI 与反序列化先确认语言指纹SSTI 的排查非常标准化提交{{7*7}}、${7*7}、% 7*7 %、#{7*7}观察哪个被求值就能确定模板引擎族。更多硬核网安与AI工具包请扫码获取完整源码Jinja2 下常见的沙箱逃逸路径是.__class__.__mro__[1].__subclasses__()找os._wrap_close或
返回列表