返回指定目录中的文件和目录的数组.
scandir("."):得到该文件下的所有文件和文件夹
(2) print_r() 函数print_r() 函数用于打印变量,以更容易理解的形式展示。
参数为要打印的变量,如果给出的是 string、integer 或 float 类型变量,将打印变量值本身。如果给出的是 array,将会按照一定格式显示键和元素。object 与数组类似。
(3) localeconv() 函数:返回一包含本地数字及货币格式信息的数组。而数组第一项就是.
(4) current() 函数:返回数组中的当前单元, 默认取第一个值。
所以 current(localeconv())两个函数连用,返回的就是 ' . ' 点
注:pos() 是current() 的别名。
(5) array函数array_reverse() 函数:顾名思义,反转数组。
array_flip() 函数: 反转/交换数组中的键和值,成功则返回交换后的数组,失败返回NULL。
array_rand()函数:从数组中随机取出一个或多个单元,如果只取出一个,返回随机单元的键名。 如果不止一个,返回包含随机键名的数组。第二个参数number默认为1.
键与值反转交换后,数组里 文件名变为了值。array_rand()从数组中随机取出一个单元的键名,不断刷新访问就会不断随机返回,具体题目中多刷新几次就出来flag文件了。
所以 array_rand( array_flip() )配合使用可随机返回当前目录下的文件名。
这几个函数没被过滤的话可以构造:
?exp= print_r(array_rand(array_flip(scandir(current(localeconv() ) ) ) ) )
(6) next() 函数reset()函数:将数组的内部指针指向第一个单元
end()函数:将数组的内部指针指向最后一个单元
next()函数:将数组的内部指针向前移动一位
prev()函数:将数组的内部指针倒回一位
在刚才 scandir() 函数返回的数组中,第一位是点(.),此时指针默认指向该位(也就是第一位),通过next()函数,将指针移动到下一位,也就是点点(..)
再比如我们下面那道 [GXYCTF2019]禁止套娃 1。
print_r(scandir(current(localeconv())))得到flag文件在数组倒数第二位。
因此我们可以将数组逆转后,再next(),指针就到了我们flag文件所处位置。
next(array_reverse(scandir(current(localeconv())))) 即得到了我们flag文件名。
highlight_file()高亮显示,或者show_source()读取,得到flag
(7) time有关函数time()函数:返回自 Unix 纪元(January 1 1970 00:00:00 GMT)起的当前时间的秒数。
localtime()函数:返回本地时间。
localtime()函数可以接受参数,并且第一个参数可以直接接受time()
(8) chr()&chdir()&dirname()函数chr()与ord()互补,返回ascll码对应的字符. 什么时候用呢?
因为当秒数为46时,chr(46)=”.”,可以用来获取点(.) 当localeconv()被过滤时可用。
chr 函数以256为一个周期,所以 chr(46) , chr(302) , chr(558) 都等于 "."
所以使用 chr(time()) ,一个周期必定出现一次 "."
chr(current(localtime(time()))) :
数组第一个值每秒+1,所以最多60秒就一定能得到46,用 current或pos 就能获得 "."
chdir("..")返回上一级目录。scandir()出来的数组里有 . (当前目录) 和 ..(上一级目录)。
print_r(scandir(next(scandir(getcwd))));可查看上级目录文件
dirname():返回上一级目录,路径中的目录部分。
getcwd():返回当前目录。
可用chdir(dirname(getcwd))来更改目录。
(9) file()函数readfile()函数:读取文件并写入到输出缓冲。 echo(readfile())
readgzfile()函数:readgzfile 也可读文件,常用于绕过过滤
(10)session方法session_id可以获取PHPSESSID的值,而我们知道PHPSESSID允许字母和数字出现,而flag.php符合条件.因此我们在请求包中cookie:PHPSESSID=flag.php,使用session之前需要通过session_start()告诉PHP使用session,php默认是不主动使用session的。session_id()可以获取到当前的session id。这样可以构造payload:? exp=readfile(session_id(session_start()));
[GXYCTF2019]禁止套娃 1git泄露 与 无参数rce。
代码审计:
过滤了php伪协议的各个关键字,伪协议行不通。继续看到第二个过滤,就是无参数RCE,函数一直套,然后套出我们想要的命令,a(b (c( ) ) ),但是不能带参数。
preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])
限制我们传输进来的必须是纯小写字母的函数,而且不能携带参数。
(?R)? 意思为递归整个匹配模式。所以正则的含义就是匹配无参数的函数,内部可以无限嵌套相同的模式(无参数函数).
!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])
preg_match的主要功能就是过滤函数,把一些常用不带参数的函数关键部分都给过滤了,
这个过滤不严格,file,readfile,print_r(),next,localeconv,scandir,pos还可以用.
传入 ?exp=print_r(scandir(pos(localeconv()))); 爆出flag路径
用array_reverse() 将数组内容反转一下,利用next()指向flag.php文件==>highlight_file()高亮输出: 传入 ?exp=show_source(next(array_reverse(scandir(pos(localeconv())))));
或 ?exp=highlight_file(next(array_reverse(scandir(pos(localeconv())))));
得到flag 。