信息搜集
web1
右键打开网页源代码
web2
右键打不开,使用快捷键Command + Option + U
web3
F12打开开发者工具,定位到网络面板,展开所有的响应标头,向下滑找到flag
在 Web 里,“抓包”就是把浏览器和服务器之间的 HTTP/HTTPS 请求拦下来、看清楚、必要时改一改的过程,用来分析网站有哪些接口、传了什么参数、Cookie 里有什么等。最基础的是用浏览器自带的 F12 开发者工具里的 Network 面板:刷新页面或执行操作,就能看到每个请求的 URL、方法(GET/POST)、参数、请求头和响应内容,这是做信息搜集、理解网站数据流的必备手段。更进一步会用到 Burp Suite、Fiddler、Charles、mitmproxy 等“抓包代理”工具,把浏览器流量导到它们身上,这样不仅能查看,还能拦截并修改请求(比如改参数、改 Content-Type、伪造前端发不出来的奇怪请求),在 CTF 和 Web 安全测试中,抓包几乎是所有漏洞利用的起点。 这道入门题目里面,利用开发者工具的网络面板,对页面进行刷新,查看https://0853d982-ccf9-40d3-bfc0-0c86f69a89b2.challenge.ctf.show/这条记录,明显看到其响应体里的flag信息ctfshow{…}, 通过这次题目训练,对抓包有了较为基础的理解
web4
题目提示robos.txt可能泄露信息,尝试访问url/robots.txt,响应结果出现flagishere.txt文件,又尝试访问url/flagishere.txt,拿到flag
robots.txt 是放在网站根目录下的一个纯文本文件,相当于一个用来告诉搜索引擎爬虫“哪些地方可以爬,哪些地方不要爬” 的说明书。这道入门题目中 ,提示了robots.txt的信息,进而可以在题目url中添加robots.txt的后缀,获取到/flagishere.txt的关键信息,继续访问/flagishere.txt的内容,获取到flag
web5
根据题目提示:phps源码泄露有时候能帮上忙,在地址栏输入/index.phps,下载文件,打开后发现flag
phps泄露一般指的是服务器把 “.phps” 结尾的 PHP 源码文件直接当“高亮源码”给你看了,导致代码泄露,在ctf中,主要包括两种方式第一种比较基础,为直接修改后缀,添加index.phps的后缀可以直接下载php源码,进而直接获取flag等直接信息;第二种稍为进阶,利用/ robots.txt / 备份目录。这道题目提示为phps源码泄露,直接利用第一种方式,添加后缀直接下载源码,获取到flag信息
web6
在url后加www.zip,然后得到文本文档,这个题需要注意的是点开文本文档是拿不到flag,需要把文件名复制到url后面回车得到
dirsearch脚本的初步使用与解压源码 dirsearch:一个用字典暴力枚举 Web 目录 / 文件的 Python 脚本;www.zip:把整站源码打包备份成 www.zip 放在网站根目录,却没做好访问控制,结果你可以直接通过 URL 把它下回来。先扫描,后访问,得到对应的flag信息。
web7
直接访问url/.git/index.php
版本控制与git仓库的初步理解 Git 是一个分布式的版本控制系统,广泛应用于代码管理。它允许开发者追踪项目文件的更改历史,并协作开发。 Git 泄露 、版本控制漏洞是常见的安全问题,在开发者没有适当配置 Git 的情况下,直接利用dirsearch进行扫描,得到对应的git文件与ok状态的访问地址;之后直接进行访问,得到对应的flag
web8
直接访问url/.svn/
版本控制与svn仓库的初步理解 在 CTF Web 题中, SVN(Subversion)和版本控制系统经常作为 漏洞和信息泄露的来源 ,类似于 Git,但其工作方式和使用场景有所不同。通过对 SVN 版本控制系统的配置不当或目录泄露,攻击者可以访问到项目的源代码、历史记录、敏感信息甚至是 flag。 svn泄露 、版本控制漏洞是常见的安全问题,在开发人员和系统管理员忽略配置 svn的情况下,直接利用dirsearch进行扫描,得到对应的.svn文件与ok状态的访问地址;之后直接进行访问,得到对应的flag
web9
直接访问url/index.php.swp
vim缓存信息泄露的初步理解 “vim 缓存信息泄露”,本质就是出题人 / 开发在服务器上用 vim 编辑源码 ,留下了各种 编辑器缓存 / 备份文件 (.swp、~、.bak 等),结果这些文件也被 Web 服务器当成普通文件对外开放了,导致 源代码泄露 。 根据提示信息,采取手动猜路径的方法,直接得到.swp文件,得到flag。
web10
F12,cookie中包含flag,url解码
cookie的初步理解 在ctf中, cooki相当于“服务器放在你浏览器里的小纸条,你用它上交‘身份’,而我们要想法看懂、改掉甚至伪造这张纸条。 根据题目中对于cookie的提示,先采用最简单的抓包方式,直接利用f12开发者工具进行抓包,获取到对应的信息如下,从中可以明显看到cookie中包含flag信息
web11
通过dns检查查询flag https://zijian.aliyun.com/ TXT 记录,一般指为某个主机名或域名设置的说明。
查找flag.ctfshow.com域名下的txt记录
由于动态更新,txt记录会变,最终flag flag{just_seesee}
web12
查看robots.txt文件
| |
查看源代码找到密码,访问url/admin/输入用户名:admin 和密码
web13
根据题目提示 技术文档 在页面下面发现 document 下载发现里面存在后台地址和用户名密码登录成功获 得flag
web14
根据提示,打开网页源码,搜索editor,访问editor发现编辑器,在上传文件的图片空间里,/var/www/html下面发现flag url/nothinghere/fl0000g.txt,访问目录得到flag
web15
根据提示在页面下方发现QQ号码,url/admin,忘记密码,通过QQ号码查找到地址在西安,输入然后重置密码,获得flag
web16
url/tz.php 发现PHPINFO能点进去找到flag
根据题目对于php探针的提示,同时了解到php相关概念后,采用最基础的直接猜路径,在靶场url后添加 /phpinfo.php等探针类型依次尝试,最后添加/tz.php后访问成功,确定该web网页使用的是雅黑php探针;之后继续查看phpinfo,经过一番搜索后得到flag
web17
下载了dirsearch,扫描url得到[20:13:23] 200 - 934B - /backup.sql ,直接访问url/backup.sql,下载sql文件得到flag
web18
查看源代码,发现js/Flappy_js.js ,在里面发现\u4f60\u8d62\u4e86\uff0c\u53bb\u5e7a\u5e7a\u96f6\u70b9\u76ae\u7231\u5403\u76ae\u770b\u770b直接丢给CyberChef,解出你赢了,去幺幺零点皮爱吃皮看看,url/110.php,得到flag
web19
查看源代码,发现$u===‘admin’ && $p ===‘a599ac85a73384ee3219fa684296eaa62667238d608efa81837030bd1ce1bf04,密文为AES加密,密钥为key = “0000000372619038”;偏移量为iv = “ilove36dverymuch”;模式为CBC填充为ZeroPadding编码为Hex,通过CyberChef解出密码,回到原页面输入用户名和密码得到flag
web20
用dirsearch扫描,得到[19:27:25] 301 - 169B - /db -> http://f83cd3ef-7cf5-4e10-a200-c49856940f2d.challenge.ctf.show/db/,再dirsearch -u https://f83cd3ef-7cf5-4e10-a200-c49856940f2d.challenge.ctf.show/db/ -e sql,bak,txt,zip,db,sqlite -x 400,403,404,得到[19:29:20] 200 - 348KB - /db/db.mdb ,直接url//db/db.mdb ,下载一个db.mdb文件,用mdbtools直接strings db.mdb | grep -i “flag"找到flag(mac打不开,win直接用记事本打开检索flag)
知识点汇总
1. 基础源代码与客户端行为 (Web 1-3, 10, 18-19)
这部分考查对浏览器基本工具和前端逻辑的理解。
- 查看源码:了解 HTML 结构、注释、隐藏表单项。
- 控制台约束绕过:学会使用快捷键(
Cmd/Ctrl + Opt + U)或view-source:协议绕过右键禁用。 - 开发者工具 (F12):
- Network 面板:观察 HTTP 响应头(Headers)和响应体(Body),识别 Flag 或敏感接口。
- Application 面板:查看 Cookie、LocalStorage 存储的敏感信息。
- 前端逻辑分析:
- JS 逆向/分析:查看
.js文件中的硬编码逻辑(如 Web 18 的 Unicode 编码、Web 19 的 AES 加密参数)。 - 编码转换:识别 Unicode(
\uXXXX)、Base64、Hex 等,并学会使用 CyberChef 进行解码。
- JS 逆向/分析:查看
2. 敏感文件与配置泄露 (Web 4-9, 17, 20)
开发或运维在配置服务器时的疏忽,导致了后端信息的直接暴露。
- 爬虫规则泄露:
/robots.txt本意是引导爬虫,却常泄露后台目录(如/admin/)或备份文件名。 - 源码泄露类型:
- PHPS:
.phps是 PHP 源码的高亮显示文件。 - 备份文件:常见的
.bak、.zip、.tar.gz、.sql(Web 17 数据库备份)。 - 编辑器缓存:Vim 异常退出产生的
.swp文件(如/index.php.swp)。 - 数据库文件:
.mdb(Access)、.sqlite、.db等(Web 20)。
- PHPS:
- 目录扫描工具:
- Dirsearch / Gobuster:使用字典暴力枚举隐藏目录,这是 Web 安全测试的“基操”。
3. 版本控制系统泄露 (Web 7-8)
- Git 泄露:
.git/目录如果未删除,攻击者可以通过特定的工具(如 GitHack)还原整个项目的源代码和提交历史。 - SVN 泄露:
.svn/目录同样包含代码版本信息。
4. 域名与服务侦察 (Web 11, 16)
- DNS 记录查询:
- TXT 记录:常用于配置 SPF 或域名校验,但也常被 CTF 题目用来藏匿 Flag。
- PHP 探针:
- 如
tz.php(雅黑探针)、phpinfo.php。它们会暴露服务器的绝对路径、PHP 版本、已安装插件等敏感环境信息,是提权和进一步渗透的重要依据。
- 如
5. 后台管理与逻辑缺陷 (Web 12-15)
- 后台地址搜集:通过
robots.txt、技术文档、甚至页面底部的版权信息或联系方式(如 QQ 号)。 - 弱口令/硬编码密码:在 JS 代码或公开的说明文档中直接寻找默认密码。
- 密码找回漏洞:通过社工手段(如 Web 15 的 QQ 归属地查询)获取密保问题的答案,重置后台管理员密码。
- 富文本编辑器漏洞:
- Editor 路径:如 UEditor、KindEditor。通过其内置的文件浏览器或图片上传管理功能(Web 14),可以直接遍历服务器目录。
爆破
web21
前提条件:已知用户名是admin。打开代理和Burp Suite,随便输入密码123尝试登陆同时利用Burp Suite抓包。解码发现格式为admin:123,可以进行爆破。爆破原理:利用多个payload(进攻指令),对返回数据进行对比分析,得到唯一不同的就是可能的密码。将所抓包send to intruder,选择sniper模式。加载题目所给字典,设置前缀admin:(因为字典中只包含了密码),并对其进行base64编码(匹配Authorization请求头格式)。进行爆破,找到状态不同的即为正确答案。解码,登录,找到flag。
web22
域名更新后,flag.ctf.show域名失效,内容是flag{ctf_show_web}
web23
写脚本,但我不会,得到/?token=422
web24
终端运行php -r ‘mt_srand(372619038); echo mt_rand();‘得到1155388967**%** ,然后填入?r=1155388967得到flag
web25
mt_scrand(seed)这个函数的意思,是通过分发seed种子,然后种子有了后,靠mt_rand()生成随机 数。 在之前自己还以为需要暴力破解cookie,最后师傅们给我介绍了一个脚本,专门用来跑mt_srand()种子和 mt_rand()随机数的 这里自己解释一下为什么每一次的mt_rand()+mt_rand()不是第一次的随机数相加?? 因为生成的随机数可以说是一个线性变换(实际上非常复杂)的每一次的确定的但是每一次是不一样的,所以不能 进行第一次*2就得到mt_rand()+mt_rand() 使用说只要我们得到种子就可以在本地进行获得自己想要的值 解题:通过随机数来寻找种子 我们让 ?r=0 得到随机数。这里我得到的是 183607393 每一次不一样(因为flag值在变化) 然后下载 php_mt_seed4.0 我们在linux下面使用 gcc进行编译 gcc php_mt_seed.c -o php_mt_seed 之后运行脚本添加随机数 ./php_mt_seed 183607393
找到对应的版本这里自己的运气好第一个出来的自己验证了一下发现就是这个 注:可能存在多个种子需要自己进行判断 通过种子找到第一个随机数就是上面的随机数。
payload: ?r=183607393 Cookie: token=794171094
web26
打开bp抓包点击安装后的请求包,发送至Repeater重发器模块,点击Send发送,查看响应包,即可获取flag
web27
burpsuit爆破,学生学籍信息查询系统可以查询学号,录取名单有姓名和身份证号码(不全)所以爆破身份证号,得到身份证号:621022199002015237登录得到学号,然后登录得到flag
这题主要是身份证出生日期爆破,先拦截然后将出生日期设置为变量,attack type默认为狙击手模式,Payloads选项卡中payload type改为Dates模式,payload settings中为Dates设置起始和终止日期,注意Format项改为自定义的yyyyMMdd,然后开始爆破,爆破结束后length字段降序排序,相应包最长的应该就是响应成功的包
web28
打开靶机,发现跳转到url/0/1/2.txt,发现上两级目录都是纯数字,猜测爆破一下目录试试,打开bp抓到请求包,发送到Intruder攻击模块将目录中的0和1设置为变量,Attack type设置为Cluster bomb模式,Payloads中两个Payload type都改为Numbers,给Numbers设置初始值0和终止值为100,开始爆破,爆破结束后,将Status code字段升序排序,找到一个状态码为200的响应包,查看响应包,可获取falg
知识点汇总
1. HTTP 认证与 Base64 爆破 (Web 21)
- Authorization 头:Web 21 涉及的是 HTTP Basic 认证。浏览器会将用户名和密码以
admin:password的格式拼接,再进行 Base64 编码。 - Intruder 技巧:
- Payload Processing:在 Burp 中,不能直接爆破密码,需要使用
Add prefix (admin:)(添加前缀)和Base64-encode(编码)处理插件,使 Payload 符合服务器要求的格式。
- Payload Processing:在 Burp 中,不能直接爆破密码,需要使用
2. PHP 伪随机数漏洞 (Web 23, 24, 25)
这是 CTF Web 题中的经典考点。**“伪”**随机意味着它是可以被预测的。
- 种子 (Seed) 与序列:
mt_srand($seed):设置随机数种子。mt_rand():根据种子生成随机数。- 核心原理:只要种子确定,生成的随机数序列(第一个、第二个…第 n 个)就是完全固定的。
- 逆推种子 (php_mt_seed):
- 如果你知道
mt_rand()输出的一个或多个结果,就可以使用工具(如php_mt_seed)通过穷举法逆向推算出原始的$seed。
- 如果你知道
- 跨请求保持:在 Web 25 中,种子一旦在当前会话中固定,后续的所有
mt_rand()调用都遵循该种子的序列。
3. 复杂爆破模式 (Web 27, 28)
Burp Suite 的 Attack Type 选择是解题效率的关键:
- Sniper (狙击手):一个变量,或者多个变量轮流爆破(最常用)。
- Cluster Bomb (集束炸弹):多个变量的笛卡尔积。例如 Web 28 中,目录 A 是 0-100,目录 B 是 0-100,总共会尝试 $100 \times 100 = 10,000$ 次请求。
- Payload Types:
- Dates (日期):专门用于爆破身份证号、生日等(Web 27)。可以自定义格式如
yyyyMMdd。 - Numbers (数字):用于爆破学号、ID、目录名。
- Dates (日期):专门用于爆破身份证号、生日等(Web 27)。可以自定义格式如
4. 逻辑绕过与安装包残留 (Web 26)
- 安装文件利用:很多 CMS 在安装成功后不会自动删除
install.php或相关逻辑。Web 26 提示我们,通过抓取安装过程中的请求并重发(Repeater),可能绕过前端限制直接获取系统初始化的敏感信息(如 Flag)。
| 维度 | 掌握程度 | 关键工具/命令 |
|---|---|---|
| 爆破技术 | 熟练掌握多字段、特定格式、日期格式爆破 | Burp Suite (Intruder: Cluster Bomb) |
| 加密处理 | 了解 HTTP Basic 认证流程 | Base64 编码/解码 |
| 随机数安全 | 理解种子泄露导致随机数可预测 | php_mt_seed, mt_srand |
| 信息分析 | 能从录取名单等零散信息中提取爆破字典 | 观察力 + 构造字典能力 |
命令执行
web29
代码逻辑分析
error_reporting(0);: 关闭错误报告,防止报错信息泄露。if(isset($_GET['c'])): 检查是否通过 GET 请求传递了参数c。if(!preg_match("/flag/i", $c)): 核心防御逻辑。使用正则表达式检查变量$c中是否包含 “flag” 字符串(i表示不区分大小写)。如果不包含,则执行下一步。eval($c);: 这是一个极其危险的函数,它会将字符串$c当作 PHP 代码直接执行。highlight_file(__FILE__);: 如果没有参数c,则显示当前源代码。
绕过思路
由于后端过滤了 flag 这个词,我们无法直接使用类似 system("cat flag.php"); 的命令。我们需要通过一些技巧来绕过正则检测。
1. 使用通配符 (Wildcards)
在 Linux Shell 中,? 匹配单个字符,* 匹配任意字符。
- Payload:
?c=system("cat f*"); - Payload:
?c=system("cat fla?.php");
2. 使用 PHP 变量拼接
我们可以将字符串拆开,避开正则检测。
- Payload:
?c=$a="fla";$b="g.php";system("cat ".$a.$b);
这两种都可以,但要查看源代码才能得到flag
web30
代码的核心逻辑是:通过 GET 方式接收参数 c,在过滤了关键词 flag、system 和 php(不区分大小写)后,将内容传递给 eval() 执行。
第一步:查看目录文件
首先确定 flag 文件的确切名称。
| |
第二步:读取文件内容
假设目录下有 flag.php,使用通配符绕过:
| |
查看源代码
web31
代码的核心逻辑是:通过 GET 方式接收参数 c,在经过一个正则表达式过滤后,使用 eval() 执行该字符串。
核心限制分析
正则表达式 /flag|system|php|cat|sort|shell|\.| |\’/i 禁用了以下内容:
- 关键词:
flag,system,php,cat,sort,shell(且不区分大小写)。 - 特殊符号:
.(点),(空格),'(单引号)。
绕过思路
1. 绕过 system 限制
虽然 system 被禁用了,但 PHP 中还有其他执行系统命令的函数:
passthru()exec()shell_exec()- 反引号 (```):这是
shell_exec()的快捷方式,非常适合绕过关键字过滤。
2. 绕过空格限制
在 Linux 环境下,可以使用以下字符代替空格:
%09(Tab 键的 URL 编码)${IFS}(Shell 的内部字段分隔符)$IFS$9
3. 绕过 flag 和 cat 限制
- 文件名通配符:用
f*或f???代替flag。 - 替代命令:用
tac(倒序读取),more,less,nl(带行号读取) 代替cat。
构造 Payload
利用反引号和 tac
利用 echo 配合反引号执行命令。
| |
%09绕过空格。tac绕过cat。f*绕过flag。
web32
1. 代码逻辑分析
error_reporting(0);:关闭错误报告,增加调试难度。isset($_GET['c']):检查是否通过 GET 请求传入了参数c。preg_match(...):这是一个黑名单过滤。如果你的输入包含以下任何字符或单词,程序就会停止:- 关键字:
flag,system,php,cat,sort,shell,echo - 特殊符号:
.(点),(空格),'(单引号), ``` (反引号),;(分号),((左括号)
- 关键字:
eval($c);:如果绕过了过滤,参数c的内容将作为 PHP 代码执行。
2. 绕过思路
由于 ( 和 ; 被过滤,我们无法直接调用函数(如 system()),也无法写出标准的多行语句。我们需要利用 PHP 的语言构造器和短标签特性。
A. 绕过分号 ;
在 PHP 的 eval() 中,你可以使用 ?>(PHP 结束标签)来代替分号。
B. 绕过括号 (
include 和 require 是 PHP 的语言构造器,不是函数,因此调用它们不需要括号。 例如:include $_GET[1]?>
C. 绕过空格
在 Linux 环境下,URL 中可以使用 %09 (Tab 键) 或 $IFS$9 等方式绕过。但在 PHP 代码中,如果 include 后紧跟变量,有时连空格都不需要。
D. 绕过 flag 等关键字
最常用的技巧是参数逃逸:在 c 中执行一个不被过滤的语句,去调用另一个不受过滤限制的参数(如 $_GET[1])。
3. 常见的攻击 Payload
利用 include 和伪协议读取文件
| |
- 原理:
c的内容是include$_GET[1]?>,没有触碰任何黑名单。 - 执行:它会包含参数
1指向的内容。由于flag.php直接读取会被服务器解析而不显示源码,我们使用php://filter将其转为 Base64 编码,读出来后再自行解码。
web33
1. 核心过滤分析
正则表达式
| |
过滤了以下内容:
- 关键词:
flag,system,php,cat,sort,shell,echo(堵死了直接读取和常用的系统调用)。 - 符号:
.(点):无法直接写文件名或后缀。(空格):无法分隔命令参数。'和"(引号):无法构造字符串。- `` `(反引号):无法执行 Shell 命令。
;(分号):无法结束语句(关键限制)。((括号):无法直接调用函数,如system()或eval()。
2. 绕过思路:文件包含 (Include)
在 PHP 中,include 是一个语言结构而非函数,因此它不需要括号。利用这一点,我们可以尝试通过 include 包含一个受控的外部变量。
由于分号 ; 被禁,我们可以利用 PHP 的闭合标签 ?> 来代替分号结束当前的语句。
Payload 构造:
| |
include$_GET[1]:include后面直接跟变量,绕过了括号限制;使用$_GET数组绕过了引号限制(PHP 数组键名不加引号在某些配置下会当作字符串处理,或者利用 PHP 特性直接拼接)。?>:成功绕过分号;限制,告诉 PHP 解析器当前代码段结束。1参数:因为正则只检测变量c,所以我们在参数1中可以自由书写被禁用的关键词,如php、flag、.等。php://filter:使用伪协议读取文件并将内容进行 Base64 编码。这是因为flag.php通常包含 PHP 代码,直接 include 会被解析而不显示内容,编码后可以拿到源码。
web34
以下内容被禁止了:
- 关键词:
flag,system,php,cat,sort,shell,echo - 特殊字符:
.(点),(空格),'(单引号), ``(反引号),;(分号),((左括号),:(冒号),"` (双引号)
解题思路:反解绕过与通配符
由于括号 ( 被禁用,我们无法直接调用 system() 或 eval() 等函数。然而,PHP 的 include 是一个语句(Language Construct),它在不需要括号的情况下也可以工作。
我们可以通过以下链条实现绕过:
- 利用
include包含伪协议:由于无法直接写字符串,我们可以利用 PHP 的动态特性。 - 利用
$_GET传参绕过:虽然变量$c受到正则限制,但我们可以利用 PHP 不限制其他参数的特点,通过$_GET传入我们要执行的恶意代码。 - 配合通配符或反撇号:由于本题过滤了反撇号,我们需要寻找替代方案。
Payload
可以尝试使用 PHP 伪协议配合数据流 或者 包含 /proc/self/fd 等技巧。但最简单且最经典的方法是利用 include 结合 $_GET:
| |
代码解析:
include$_GET[1]?>:include不需要括号。$_GET[1]避开了正则对变量$c的内容检查。?>是 PHP 的闭合标签,用于替代被禁用的分号;。
&1=...:- 在参数
1中,我们可以自由使用被过滤的字符(如php,flag,.等)。 - 使用
php://filter协议将flag.php的内容进行 Base64 编码读出(防止被服务器直接解析而不显示)。
- 在参数
Web35
代码逻辑分析
代码通过 $_GET['c'] 接收参数,并使用 preg_match 进行了严格的黑名单过滤。被过滤的关键字和字符包括:
- 关键字:
flag,system,php,cat,sort,shell,echo - 特殊字符:
.(点),(空格),'(单引号), ``(反引号),;(分号),((左括号),:(冒号),"(双引号),<(小于号),=` (等于号)
核心难点
- 禁用了括号
(:这意味着我们无法直接调用任何函数(如system()或passthru())。 - 禁用了分号
;:这意味着我们只能执行一条语句,且不能使用传统的语句结束符。 - 禁用了空格:需要寻找替代符。
解题思路:利用 include 和伪协议
由于禁用了括号,我们无法进行函数调用,但 PHP 中的 include 是一个语句(language construct),它不需要括号即可运行。
我们可以利用 include 配合 PHP 伪协议 或者 通配符 来绕过限制。
方案一:利用 include 配合通配符(推荐)
在 PHP 中,如果开启了 short_open_tag,我们可以通过 include 包含一个包含通配符的文件路径。但在本题中,最巧妙的方法是利用 include 包含 /proc/self/fd/ 下的文件或者利用临时文件,但在没括号的情况下,最简单的思路是:利用 PHP 标签绕过。
由于禁用了许多关键字符,我们可以尝试使用 ?> 来闭合当前的 PHP 标签,然后直接书写我们想执行的内容。
方案二:利用取反/异或绕过(如果环境允许)
通常用于绕过正则限制,但因为禁用了括号,这条路很难走通。
方案三:利用 include 包含 POST 数据
这是最常用的技巧。虽然 c 被过滤了很多,但我们可以让 c 执行 include 某个外部来源。
Payload 构造:
| |
逻辑解析:
include$_GET[1]:include不需要括号,且后面可以直接跟变量。?>:用来替代分号;。在 PHP 中,结束标签?>隐含了一个分号的作用。- 绕过空格:由于空格被过滤,但在
include和变量之间,如果环境支持,有时可以不加空格或利用某些特殊编码。 - 变量注入:通过
$_GET[1]传入我们真正想执行的、带有敏感字符的 payload(如flag),因为preg_match只检查变量c,不检查变量1。
web36
核心限制分析
正则表达式封锁了:
- 关键字:
flag,system,php,cat,echo等(无法直接执行系统命令或读取文件)。 - 符号:
.(点) 和/(斜杠):无法直接指定路径。;(分号):无法结束语句。(和)(括号):最致命的限制,这意味着无法调用任何函数(如system())。(空格):无法分隔命令。'和"(引号):无法定义字符串。
- 数字:
0-9全被封死。
绕过思路:利用 PHP 语言特性
既然无法使用括号调用函数,我们必须利用 PHP 中的 语言结构 (Language Constructs)。include 就是一个不需要括号且能执行代码的语言结构。
1. 配合通配符与 $_GET 数组
虽然 c 受到了严格过滤,但我们可以引入一个新的参数(如 a),而 a 是不受过滤的。 PHP 允许使用 $_GET{a}(花括号)来代替 $_GET['a'](方括号),从而绕过对引号的限制。
2. 利用 PHP 闭合标签
由于分号 ; 被禁用,我们可以使用 PHP 的结束标签 ?> 来强制结束当前的 eval 语句,这在 PHP 中具有替代分号的作用。
最终 Payload 构造
我们可以利用 include 包含一个由另一个参数传入的伪协议流。
Payload 示例:
| |
逻辑解析:
c=include$_GET{a}?>:- 没有使用括号、分号、空格或数字,完全绕过了正则。
include后面直接跟变量在 PHP 中是合法的。?>代替了分号。
&a=...:- 后端脚本只检查
$_GET['c'],不检查$_GET['a']。 - 我们在
a中构造完整的读取逻辑:利用php://filter将flag.php的内容转为 Base64 编码输出(直接包含.php文件会被执行而看不到源码,所以需要编码)。
- 后端脚本只检查
web37
核心代码审计
error_reporting(0);: 屏蔽所有报错信息。这意味着即使包含失败,页面也不会显示路径错误或权限错误,增加了盲测的难度。if(!preg_match("/flag/i", $c)):- 这是代码的关键防御机制。使用正则表达式检查变量
$c。 /i修饰符表示不区分大小写。- 意图:防止用户直接通过
?c=flag.php读取 flag。
- 这是代码的关键防御机制。使用正则表达式检查变量
include($c);: 漏洞触发点。PHP 会尝试将被包含文件作为 PHP 脚本执行。echo $flag;: 关键点。注意,这个echo在include之后。这意味着只要flag.php被成功包含,其中定义的$flag变量就会进入当前作用域,并被这行代码打印出来。
payload
| |
web38
代码逻辑分析
- 目标:注释提示
flag in flag.php,说明我们的目标是读取或包含flag.php。 - 输入控制:通过
$_GET['c']接收参数。 - 正则过滤:
preg_match("/flag|php|file/i", $c)。- 这个正则表达式会检查变量
$c中是否包含关键字flag、php或file(不区分大小写)。 - 如果匹配到这些词,代码就不会执行
include($c)。
- 这个正则表达式会检查变量
- 漏洞点:
include($c)。这是一个文件包含函数,如果能绕过过滤并成功包含flag.php,由于代码最后有一句echo $flag;,变量$flag(通常定义在flag.php中)就会被打印出来。
做法和37差不多
| |
web39
$c = $_GET['c'];:从 URL 参数 c 获取输入。
if(!preg_match("/flag/i", $c)):第一道防线。正则表达式检查输入中是否含有 flag(不区分大小写)。如果你的输入里有这四个字母,直接出局。
include($c.".php");:核心漏洞点 & 第二道防线。
- 这里存在文件包含漏洞(LFI)。
- 它强制在你的输入后面加上
.php后缀。这意味着如果你直接输入index,它会包含index.php。
目标: 读取 flag.php 的内容。
挑战: 不能输入 flag,且要处理掉尾部的 .php。
为了绕过上述限制,我们使用 data:// 协议。它允许我们将输入的数据当作“文件内容”让 PHP 去解析执行。
步骤一:绕过 flag 关键字过滤
由于正则只检查变量 $c 的内容,我们不能直接写 flag.php。
- 技巧:使用通配符。在 Linux Shell 指令中,
*可以匹配任意字符。 - 我们将
flag.php写成fla*.php或f*。这样在匹配正则时,字符串里没有flag,可以成功绕过。
步骤二:处理强制添加的 .php 后缀
题目代码是 include($c.".php")。
- 如果你输入
?c=data://text/plain,<?php phpinfo(); ?> - 最终包含的语句变成了:
include("data://text/plain,<?php phpinfo(); ?>.php")
关键原理: PHP 在执行 include 包含的代码时,一旦遇到 ?> (PHP 闭合标签),就会认为 PHP 代码段已经结束。之后的任何内容(包括自动拼接的 .php)都会被当作 普通字符串/HTML 直接显示在页面上,而不会被当作 PHP 代码解析执行。
payload
| |
- 注入参数: URL 变为
index.php?c=data://text/plain,<?php system("tac fla*.php")?> - 正则校验:
preg_match检查字符串data://text/plain,<?php system("tac fla*.php")?>。 由于使用的是fla*,字符串中不包含完整的flag,校验通过。 - 代码拼接: PHP 执行
include语句:include("data://text/plain,<?php system("tac fla*.php")?>.php"); - 伪协议解析: PHP 解释器读取
data://流中的内容:- 代码部分:
<?php system("tac fla*.php")?> - 命令执行:
system调用系统 Shell。tac命令反向读取文件(常用于绕过对cat的过滤,且效果一致)。fla*.php被 Shell 解析为flag.php。 - 执行结果:
flag.php的内容被打印到页面源码中。
- 代码部分:
- 后续忽略: 最后的
.php位于?>之后,PHP 引擎将其视为纯文本直接输出,不影响代码逻辑。
web40
第一步:确认环境与注入点
打开题目页面,看到源码。首先确认变量 c 是通过 GET 方式传入的。
- 注入点:
URL/?c= - 目标:读取服务器上的
flag.php。
第二步:测试并寻找“当前目录”
在无法使用 '.' 的情况下,我们需要确认 PHP 能否找到当前目录。
- 在浏览器输入:
?c=print_r(localeconv()); - 观察结果:应该能看到一个数组输出。
- 确认逻辑:数组的第一个元素(
[decimal_point])通常是.。 使用pos()提取它:?c=print_r(pos(localeconv()));页面如果只显示一个.,说明这步成功了。
第三步:查看文件列表
我们需要确认 flag.php 到底在不在当前目录下,以及它排在第几个。
输入 Payload:
?c=print_r(scandir(pos(localeconv())));观察返回的数组,假设结果如下:
1 2 3 4 5 6Array ( [0] => . [1] => .. [2] => flag.php [3] => index.php )注意:此时
flag.php的索引是 2。
第四步:移动指针定位文件
这是最关键的一步。我们需要让 PHP 的“准星”对准 flag.php。
- 尝试反转数组:
?c=print_r(array_reverse(scandir(pos(localeconv()))));- 结果:
Array ( [0] => index.php [1] => flag.php [2] => .. [3] => . ) - 分析:此时
flag.php排在第二个位置。
- 结果:
- 使用
next()移动指针: 在 PHP 中,数组刚产生时指针指向第一个(index.php)。调用next()后,指针会向后移动一位,指向flag.php。
第五步:读取文件源码(最终 Payload)
现在万事俱备,我们要把 print_r 换成能读取文件内容的函数(如 show_source 或 highlight_file)。
操作步骤:
在浏览器地址栏输入最终 Payload:
1?c=show_source(next(array_reverse(scandir(pos(localeconv())))));按下回车。
查看结果:页面上会直接喷出
flag.php的源代码(通常带有语法高亮)。
核心知识点整理
1. PHP 无参数函数注入 (Parameterless Function Injection)
这是本题的核心考点。当正则过滤了数字、字母以外的大部分字符时,你无法传参(如 system('ls')),只能利用 “函数嵌套” 的返回值作为下一个函数的参数。
- 特征:
a(b(c())); - 局限:必须寻找那些不需要参数就能返回有用信息的 PHP 内置函数。
2. 目录定位与获取
在没有引号的情况下,获取“当前目录”字符串(.)是所有操作的第一步。
localeconv():返回本地化信息数组。其第一个元素decimal_point始终是.。pos()/current():返回数组中的第一个元素。- 组合技:
pos(localeconv())得到.。
- 组合技:
getcwd():直接获取当前工作目录的绝对路径字符串。
3. 文件系统操作
scandir():核心函数,用于列出指定路径下的所有文件和目录,并返回一个数组。- 组合技:
scandir(pos(localeconv()))得到当前目录下的文件列表数组。
- 组合技:
4. 数组指针与顺序控制
由于 scandir 返回的数组通常以 . 和 .. 开头,而 flag.php 往往排在后面,我们需要操作数组指针来选中它。
array_reverse():将数组顺序颠倒。常用于让排在末尾的文件排到前面。- 指针移动函数:
pos()/current():指向当前(第 1 个)元素。next():将指针后移一位(指向第 2 个)。end():将指针指向最后一位。
array_flip():交换数组的键和值。常配合array_rand()使用,实现随机挑选文件。
5. PHP 引用传递限制 (Pass-by-reference)
这是一个进阶坑点。PHP 某些函数(如 next(), end())要求传入的是一个变量,而不是函数的返回值(临时值)。
- 报错信息:
Only variables should be passed by reference。 - 解决方法:
- 使用
array_slice():它可以切取数组片段而不操作指针,不要求引用传递。 - 使用
item()逻辑:如果环境支持,直接用[index]访问,但通常中括号会被过滤。
- 使用
6. 文件读取函数
拿到文件名字符串后,最后一步是读取内容。
show_source()/highlight_file():读取 PHP 文件并进行语法高亮,最适合读 flag。readfile():直接读取并输出文件内容。file_get_contents():读取内容,但由于是无参数执行,通常外层还需要配合print_r打印出来。