前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >干货 | 能看懂的PHP反序列化字符逃逸漏洞

干货 | 能看懂的PHP反序列化字符逃逸漏洞

作者头像
网络安全自修室
发布2023-02-26 15:48:24
1.2K0
发布2023-02-26 15:48:24
举报

1

免责声明

本公众号提供的工具、教程、学习路线、精品文章均为原创或互联网收集,旨在提高网络安全技术水平为目的,只做技术研究,谨遵守国家相关法律法规,请勿用于违法用途,如果您对文章内容有疑问,可以尝试加入交流群讨论或留言私信,如有侵权请联系小编处理。

2

内容速览

1、引子

  • 在php中,反序列化的过程中必须严格按照序列化规则才能成功实现反序列化,例如
代码语言:javascript
复制
<?php
  	$str = "a:2:{i:0;s:4:"flag";i:1;s:6:'mikasa';}"
  	var_dump(unserialize($str));
?>;
#输出结果
/*
array(2){
	[0]=>; string(4) "flag"
  [1]=>; string(6) "mikasa"
}
*/

  • 一般情况下,按照我们的正常理解,上面例子中变量str是一个标准的序列化后的字符串,按理来说改变其中任何一个字符都会导致反序列化失败。但事实并非如此。如果在str结尾的花括号后加一些字符
代码语言:javascript
复制
<?php
  	$str = "a:2:{i:0;s:4:"flag";i:1;s:6:'mikasa';}abc"
  	var_dump(unserialize($str));
?>;
#输出结果依然和上面的相同

  • 这说明了反序列化的过程是有一定识别范围的,在这个范围之外的字符(如花括号外的abc)都会被忽略,不影响反序列化的正常进行、

2、php反序列化的几大特性

PHP 在反序列化时,底层代码是以 ; 作为字段的分隔,以 } 作为结尾(字符串除外)并且是根据长度判断内容的

  • 注意点,很容易以为序列化后的字符串是;}结尾,实际上字符串序列化是以;}结尾的,但对象序列化是直接}结尾
  • php反序列化字符逃逸,就是通过这个结尾符实现的 当长度不对应的时候会出现报错

3、反序列化字符逃逸

反序列化之所以存在字符串逃逸,最主要的原因是代码中存在针对序列化(serialize())后的字符串进行了过滤操作(变多或者变少)。

反序列化字符逃逸问题根据过滤函数一般分为两种,字符数增多和字符数减少

(1)字符数增多的利用示例
代码语言:javascript
复制
<?php
  	function filter($str){<!-
- -->
  			return str_replace('x','yy',$str);
		}
		
		$username = "mikasa";
		$password = "biubiu";
		$user = array($username,$password);
		
		$str1 = filter(serialize($user));
		//$str2 = filter($_GET['user']);

		var_dump(unserialize($str1));
		//var_dump(unserialize($str2));
?>;

问:如果我能控制进行反序列化的字符串,该如何使var_dump打印出来的password对应的值是123456,而不是biubiu

  • 正常情况下反序列化字符串$str1的值为a:2:{i:0;s:6:"mikasa";i:1;s:6:"biubiu";}
  • 那么把username的值变为mikasaxxx,当完成序列化,filter函数处理后的结果为a:2:{i:0;s:9:"mikasayyyyyy";i:1;s:6:"biubiu";}
  • 因为比之前多了三个字符,反序列化时肯定是会失败的!
  • 所以,可以利用多出来的字符串做一些坏事?想要password是123456,反序列化化前的字符串要是 a:2:{i:0;s:6:"mikasa";i:1;s:6:"123456";}

如果说我们输入的是

  • a:2:{i:0;s:26:"mikasa";i:1;s:6:"123456";}";i:1;s:6:"biubiu";}
  • 多出的字段是 ";i:1;s:6:"123456";} 数一下是20个字符,
  • 一个x会导致多出一个字符,所以加上20个x,";i:1;s:6:"biubiu";}部分的内容会被当作无效部分被忽略???所以最终输入是
  • a:2:{i:0;s:46:"mikasaxxxxxxxxxxxxxxxxxxx";i:1;s:6:"123456";}";i:1;s:5:"aaaaa";}
  • filter之后,会变为
  • a:2:{i:0;s:46:"mikasayyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";i:1;s:6:"123456";}";i:1;s:5:"aaaaa";}
(2)字符串减少时
代码语言:javascript
复制
<?php
  	function filter($str){<!-
- -->
  			return str_replace("xx","y",$str);
		}
		
		$username = "mikasa";
		$password = "biubiu";
		$user = array($username,$password);
		
		$str1 = filter(serialize($user));
		//$str2 = filter(serialize($_GET['user']));
		
		var_dump(unserialize($str1));
		//var_dump(unserialize($str2));
?>;

问:如果我能控制进行反序列化的字符串,该如何使var_dump打印出来的password对应的值是123456,而不是biubiu

  • 正常情况下反序列化字符串$str1的值为 a:2:{i:0;s:6:"mikasa";i:1;s:6:"biubiu";}

那么把username的值变为mikasaxxxxxx,当完成序列化,filter函数处理后的结果为a:2:{i:0;s:12:"mikasayyy";i:1;s:6:"biubiu";}

  • 因为比之前少了三个字符,反序列化时肯定是会失败的,mikasayyy的长度为9,还会继续往后吞3个字符!但这样会造成语法错误!
  • 所以,是否可以利用变化的字符长度做一些坏事?(吞掉原有的password值,再添加新值!) 构建的注入表达式是(吞)
  • a:2:{i:0;s:?:"mikasa";i:1;s:5:"biubiu";}";i:1;s:6:"123456";}
  • 所以要吞掉的内容是";i:1;s:5:"biubiu";} 一共是20个字符!所以需要添加40个x 所以最终的输入时
  • a:2:{i:0;s:46:"mikasaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";i:1;s:5:"biubiu";}";i:1;s:6:"123456";}
  • filter之后,会变为
  • a:2:{i:0;s:46:"mikasayyyyyyyyyyyyyyyyyyyy";i:1;s:5:"biubiu";}";i:1;s:6:"123456";}

4、总结

  • 当字符增多:在输入的时候再加上精心构造的字符。经过过滤函数,字符变多之后,就把我们构造的给挤出来。从而实现字符逃逸
  • 当字符减少:在输入的时候再加上精心构造的字符。经过过滤函数,字符减少后,会把原有的吞掉,使构造的字符实现代替
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-12-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 网络安全自修室 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、引子
  • 2、php反序列化的几大特性
  • 3、反序列化字符逃逸
    • (1)字符数增多的利用示例
      • (2)字符串减少时
      • 4、总结
      相关产品与服务
      文件存储
      文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档