记一道代码审计题目

前言

这个题目好像做了两遍了。。。。从这道题目里面学到的东西还是需要记录一下

正文

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?php


$info = "";
$req = [];
$flag="xxxxxxxxxx";

ini_set("display_error", false);
error_reporting(0);


if(!isset($_POST['number'])){
header("hint:6c525af4059b4fe7d8c33a.txt");

die("have a fun!!");
}

foreach([$_POST] as $global_var) {
foreach($global_var as $key => $value) {
$value = trim($value);
is_string($value) && $req[$key] = addslashes($value);
}
}


function is_palindrome_number($number) {
$number = strval($number);
$i = 0;
$j = strlen($number) - 1;
while($i < $j) {
if($number[$i] !== $number[$j]) {
return false;
}
$i++;
$j--;
}
return true;
}


if(is_numeric($_REQUEST['number'])){

$info="sorry, you cann't input a number!";

}elseif($req['number']!=strval(intval($req['number']))){

$info = "number must be equal to it's integer!! ";

}else{

$value1 = intval($req["number"]);
$value2 = intval(strrev($req["number"]));

if($value1!=$value2){
$info="no, this is not a palindrome number!";
}else{

if(is_palindrome_number($req["number"])){
$info = "nice! {$value1} is a palindrome number!";
}else{
$info=$flag;
}
}

}

echo $info;

直接来看代码
分析过后我们发现这段代码得满足四个条件
1.必须是字符串
2.参数number与变换为整形再变换为字符串的number相等
3.number参数反转后必须相等
4.不是水仙花数

似乎1跟2条件冲突,3跟4条件也冲突,如何构造呢?
下面就给出两种办法

1.number=0e00%00或者0e00%20
这里的%00表示空字符串,%20表示是空格,这样一来就满足了上述四个条件
利用%00绕过第一个字符串判断,然后第二个条件都是变为0再比较,下面更是满足3和4的条件

2.利用函数溢出的方法
number=2147483647%00
从这一个题目里面学到一个新点
那就是Intval最大的值取决于操作系统。
32位系统最大带符号的 integer 范围是 -21474836482147483647。举例,在这样的系统上,intval(‘1000000000000’) 会返回 2147483647
所以在第三个条件的时候翻转变成7463847412再变成整形也是2147483647,绕过第三个条件,第四个条件也就一起绕过了。

小结

intval()转换的时候,会将从字符串的开始进行转换知道遇到一个非数字的字符。
即使出现无法转换的字符串,intval()不会报错而是返回0。

所以呢现在这个intval函数我觉得的有几个点可以去利用的
1.溢出
2.16进制通常是配合is_numeric()使用
3.科学计数法
下面就是一个科学计数法的例子

1
2
var_dump((int)('1e-1000')>0);
var_dump('1e-1000'>0);

结果

1
2
bool(true)
bool(false)
1
2
var_dump((int)('1e-10')>0);
var_dump('1e-10'>0);

结果

1
2
bool(true)
bool(true)

在科学计数法字符串转换为数字时,如果 E 后面的数小于某个值会弄成 double 类型,再强制转换为 int 类型时可能会有奇妙的结果,测试发现某变量为 1e-1000 时已经可以触发这个漏洞绕过两个检查,使得某变量既大于 0 又不大于 0。


听说,打赏我的人最后都成了大佬。



文章目录
  1. 1. 前言
  2. 2. 正文
  3. 3. 小结