freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

PHP字符逃逸导致的对象注入
渔夫也爱摸鱼 2021-12-27 11:19:20 131477
所属地 四川省

php序列化数据格式

参考:https://www.neatstudio.com/show-161-1.shtml

  • NULL,boolean ,integer,double

N;
b:<digit>;
i:<number>;
d:<number>;

true时digit=1,false时digit=0

  • string

s:<length>:"<value>";

length 字符串长度,数字前可以带有正号+

  • 数组

a:<n>:{<key 1><value 1><key 2><value 2>...<key n><value n>}

n 数组个数,key1、key2……数组下标,

【示例】

<?php
  $arr = array('a','b','c');
  $sarr = serialize($arr);
  print_r($sarr);

输出结果

a:3:{i:0;s:1:"a";i:1;s:1:"b";i:2;s:1:"c";}
  • 对象

O:<length>:"<class name>":<n>:{<field name 1><field value 1><field name 2><field value 2>...<field name n><field value n>}

length表示class name的长度,n表示对象中的字段个数,这些字段包括在对象所在类及其祖先类中用 var、public、protected 和 private 声明的字段,但是不包括 static 和 const 声明的静态字段

【示例】

O:6:"people":2:{s:4:"name";s:2:"xy";s:3:"age";s:2:"18";}
对象类型:长度:"名字":类中变量的个数:{类型:长度:"名字";类型:长度:"值";......}

【类型字母详解】

a - array                  b - boolean  
d - double                 i - integer
o - common object          r - reference
s - string                 C - custom object
O - class                  N - null
R - pointer reference      U - unicode string

规则研究

如下示例:

$a[] = 'jelly'
$b = serialize($a);//	a:1:{i:0;s:5:"jelly";}

如果我在$a中拼接了jelly"};,此时为,反序列化字符串为:a:1:{i:0;s:8:"jelly";}";},注入的";}似乎不影响其结果,会不会是s:8部分其主要的控制作用呢

现在来处理几种情况,然后查看反序列化的结果

a:1:{i:0;s:5:"jelly";}123				//	a[] = 'jelly'
a:1:{i:0;s:5:"jelly";}";}123			//	a[] = 'jelly'
a:1:{i:0;s:8:"jelly";}";}123			//	a[] = 'jelly";}'

测试发现,s:<n>在n个字符结束后,必须以;}结尾,其中的";}符号并不会影响其反序列化。确定结尾后,后面再多字符也不会影响反序列化结果,记住这个规则,后面我们将会巧妙利用这个规则

字符逃逸

假设存在一下代码,$username可控,$password被写死保证密码不能修改,其组成的数组数据被序列化,然后过滤。最后反序列过滤后的字符串,利用其数据。

function filter($string){
    $a = str_replace('x','zz',$string);
    return $a;
}
$username = "jelly";
$password = "strong";
$user = array($username, $password);
$r = filter(serialize($user));			
var_dump(unserialize($r));

示例数据的序列化如下

a:2:{i:0;s:5:"jelly";i:1;s:6:"strong";}

这里只有username可控,如果在username中注入jelly";i:1;s:6:"123456";},试图修改其密码,最后序列化字符串会如下

//	$username = jelly";i:1;s:6:"123456";}
a:2:{i:0;s:25:"jelly";i:1;s:6:"123456";}";i:1;s:6:"123456";}

这里我们额外注入了";i:1;s:6:"123456";}20个字符,其中具有";}试图闭合其中的一些符号,但s:25会使我们注入的";}毫无效果

恰好这里的过滤规则具有一个添加字符的效果,这里我们额外注入了";i:1;s:6:"123456";}20个字符,那我们注入20个'x',经过'x'->'zz'的过滤,会多20个字符出来,使得我们注入的20个payload字符逃出s:25的范围。所以这种手动一般叫做字符逃逸

如果我先把$password改成123456,就可以注入以下语句

a:2:{i:0;s:45:"jellyxxxxxxxxxx";i:1;s:6:"123456";}";i:1;s:6:"strong";}
//  filter() 过滤后 x->zz
a:2:{i:0;s:45:"jellyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz";i:1;s:6:"123456";}";i:1;s:6:"123456";}

另外如果过滤规则是 xx->z,即可以减少字符串,也可以减少到第一个值吞掉第二个值,然后注入

参考:

PHP字符逃逸导致的对象注入:https://blog.csdn.net/dengyu810/article/details/103213750

# web安全
本文为 渔夫也爱摸鱼 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
渔夫也爱摸鱼 LV.3
NjE5MzM0MTY3
  • 7 文章数
  • 22 关注者
ThinkPHP框架渗透实战
2022-01-17
如何编写Python漏洞验证脚本(单线程和多线程)
2022-01-09
不只会利用工具:理解bypass disable_functions
2022-01-02
文章目录