无字母数字的绕过方法

php代码

 <?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__);
 }

题目的限制:

  1. webshell长度不超过35位

  2. 除了不包含字母数字,还不能包含$_

PHP7.0版本巧妙解法

在PHP7.0版本之后进行了改动如下

7版本相对于5版本的更新内容.png

PHP7前是不允许用($a)();这样的方法来执行动态函数的,但PHP7中增加了对此的支持。所以,我们可以通过('phpinfo')();来执行函数,第一个括号中可以是任意PHP表达式。但是这样依然有字符,所以需要构造一个可以生成phpinfo这个字符串的PHP表达式即可。payload如下(不可见字符用url编码表示):

 (~%8F%97%8F%96%91%99%90)();
 取反 --- 反码 --- ~

PHP5版本的绕过

此时,我们尝试用PHP7的payload,将会得到一个错误。因为PHP5版本不支持这种方法。所以我们无法通过这种方法来继续下去。

此时我换种方法,我们是不是可以通过文件来执行。然后通过执行该文件的方式来绕过字母数字的限制?

在PHP代码中,如果存在文件上传,无论PHP代码是否接收该文件,都会生成临时文件。然后等待PHP代码执行完成之后立马删除文件。我们是不是可以通过上传文件,然后再通过代码中的GET传参执行该文件呢?

所以接下来问题很明显了

  • 代码中最后是通过eval函数执行的,但是他不能执行Linux命令

  • Linux下如何执行没有执行权限的文件?

  • 如何抢在删除文件前执行该文件?

  • 如何精准找到临时文件的位置?

解决问题

第一个问题:代码中最后是通过eval函数执行的,但是他不能执行Linux命令。

在Linux系统中可以通过反引号执行命令,因为反引号不属于“字母”、“数字”,所以我们可以执行系统命令。

第二个问题:Linux下如何执行没有执行权限的文件?

shell下可以利用.来执行任意脚本,.或者叫period,它的作用和source一样,就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则. file的意思就是用bash执行file文件中的命令。用. file执行文件,是不需要file有x权限的。那么,如果目标服务器上有一个我们可控的文件,那不就可以利用.来执行它了。

第三个问题:如何抢在删除文件前执行该文件?

在PHP中如果在代码运行过程中接收到的临时文件,是不会立刻删除的。等到整个PHP代码全部执行完毕之后才会立刻删除临时文件。所以我们先加上sleep,增加代码执行时间。

并且也不用担心POST的提交是提交到这个php代码中的,此时的get和pos请求是同步触发的。也就意味着PHP的代码不执行结束,临时文件是不会被删除的。

第四个问题:如何精准找到临时文件的位置?

就算能执行文件了,但是如果想精确匹配到文件。我们依然需要文件目录和文件名称。但是PHP生成的临时文件名称是随机的,不固定。并且在写匹配路径的时候也需要写字母或者数字,仍然过不去正则。

在PHP的配置文件中,可以找到临时文件生成目录。

 vim /etc/php/7.3/fpm/php.ini
 .....
 sys_temp_dir="/tmp" # 临时文件目录
 .....
 update_tmp_dir = "/tmp" # 上传文件临时目录
 .....

现在就剩下文件名称了。此时就可能想到学的Linux下模糊匹配。对于通配符,可能大部分知道的都只有*?

  • *可以代替0个及以上任意字符

  • ?可以代表1个任意字

所以我们可以试一下使用/*/????????? 或者/???/?????????来匹配文件。此时会发现有大量的文件,根本找不到想要的文件。

所以只使用以上两个通配符就解决不了问题了。所以需要去官方文档查看更多的glob通配符。阅读Linux的文档( glob(7) - Linux manual page ),可以学到更多有趣的知识点。

其中我们发现可以发现,glob支持用[^x]的方法来构造“这个位置不是字符x”。那么,我们用这个姿势干掉一部分不是连续字母的。因为PHP生成的临时文件名称全是随机的大小写字母加数字。所以临时文件名称不可能存在特殊字符。通过[^.][^-][^_]可以排除一些内容,但是这样发现依然很多内容。

所以我们需要找到临时文件的通性,我们通过不断的生成文件,我们发现PHP生成的临时文件是有规律的,文件名字中大小写各有百分之五十的概率。并且Linux的文件名称基本上没有大写字母。所以我们可以匹配文件名称的最后一个字母。

但是要如何实现匹配大写字母呢?

glob的文档,我们可以发现一个和正则表达式类似,glob支持利用[0-9]来表示一个范围。

并且通过查看ascii编码发现大写字母都是字@ 和 [ 之间。那么,我们可以利用[@-[]来表示大写字母。

经过查看资料修改,此时的匹配语句如下。此时可以匹配到文件了。

 /???/????????[@-[]

构造语句,执行命令

通过BurpSuite软件进行抓包、改包。来上传文件。由于文件上传的时候需要一个特殊的格式。我们可以编写一个HTML的网页用来上传文件。

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Document</title>
 </head>
 <body>
     <form action="web.php" method="post" enctype="multipart/form-data">
         <input type="file" name="file" id="">
         <input type="submit" value="提交">
     </form>
 </body>
 </html>

通过GET传递的参数,需要到eval里写代码匹配到文件然后执行。在PHP的官方文档中,明确说明传递的参数如果写代码是需要先加上?>,之后在写PHP代码。

所以构建的code参数如下

 ?code=?><?=`. /???/????????[@-[]`;?>

修改POST的包来进行文件上传。并且同时通过GET传递参数访问临时文件。

注意如果是在URL之中填写的话注意空格会被编码。所以需要使用加号代替。并且对符合要进行编码,避免错误。加号不需要再次编码,否则无法显示内容。

  • 11
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值