Code-Breaking Puzzles(第一篇)

题目连接:easy - function
环境:Apache/2.4.25(Debian) PHP/7.2.12
题目源码:

1
2
3
4
5
6
7
8
9
<?php
$action = $_GET['action'] ?? '';
$arg = $_GET['arg'] ?? '';

if(preg_match('/^[a-z0-9_]*$/isD', $action)) {
show_source(__FILE__);
} else {
$action('', $arg);
}

简单分析源码发现正则过滤了字母和数字,导致无法直接调用函数,但根据^$可以去猜测可能在参数头部或者末尾添加某个字符去绕过正则。最终fuzz找到在开头添加%5c可以绕过正则匹配。接下来就是考虑如何调用函数,使得第二个参数可控。在P总的博客里有给出提示function PHP函数利用技巧
最后找到,可以用create_function()实现代码注入,关于create_function()可以参考这篇文章PHP create_function()代码注入
于是开始构造payload,但发现并不知道flag所在的文件。想到可以用scandir去列目录。
截图
得到flag文件名
关于scandir,参考PHP手册。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
scandir
(PHP 5, PHP 7)

scandir — 列出指定路径中的文件和目录

说明
array scandir ( string $directory [, int $sorting_order [, resource $context ]] )
返回一个 array,包含有 directory 中的文件和目录。

参数
directory
要被浏览的目录

sorting_order
默认的排序顺序是按字母升序排列。如果使用了可选参数 sorting_order(设为 1),则排序顺序是按字母降序排列。

可以通过file()或file_get_contents()来读取文件
最终payload:?action=\create_function&arg=1;}var_dump(file("/var/www/flag_h0w2execute_arb1trary_c0de"));/*