学网安渗透
扫码加我吧
免费&进群
来Track安全社区投稿~
千元稿费!还有保底奖励~
PHP弱类型简介
强类型是两个区别类型的变量不可用同一起内存存储
弱类型是两个区别类型的变量能够用同一起内存存储
PHP 是弱类型语言 弱类型简单来讲便是数据类型能够被忽略的语言,和强类型语言的强制数据类型定义区别,弱类型能够一个变量赋区别数据类型的值
$var = 1;
$var = array();
$var = "string";
?>
弱类型的语言对变量的数据类型无限制,你能够在任何地时候将变量赋值给任意的其他类型的变量,同期变量亦能够转换成任意地其他类型的数据。 例如在 $a == $b 的比较中
$a = null; $b = false; //为真
$a = ; $b = 0; //一样为真
php虽然属于弱语言,然则里面亦有有些强语言类型关联的强制定义数据类型的办法
例如php里的 == 和 === 之间的区别
== 为松散比较 只比较值,不比较数据类型
而 === 为严格比较,不仅比较值亦比较类型,能够看作是强语言的强制数据类型要相同
然而,php 内核的研发者本来是想让程序员借由这种不需要声明的体系,更加有效的研发,因此在几乎所有内置函数以及基本结构中运用了非常多松散的比较和转换,防止程序中的变量由于程序员的不规范而频繁的报错,然而这却带来了安全问题。
php 内核之 zval 结构
在 PHP 中声明的变量,在 ZE 中都是用结构体 zval 来保留的 php 内核中弱类型的封装
typedef struct _zval_struct zval;
struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uint refcount__gc;
zend_uchar type; /* active type */
zend_uchar is_ref__gc;
};
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
} zvalue_value;
其中 php 经过 type 判断变量类型 存入 value。
类型转换问题
zval.type 决定了存储到 zval.value 的类型。当源代码进行有些未限制类型的比较,或数学运算的时候,可能会引起 zval.type 的改变,同期影响 zval.value 的内容改变。
比较操作符
=== 在进行比较的时候,会先判断两种字符串的类型是不是相等,再比较
== 在进行比较的时候,会先将字符串类型转化成相同,再比较
倘若比较一个数字和字符串或比较触及到数字内容的字符串,则字符串会被转换成数值并且比较根据数值来进行 比较简单,不太多举例。
Hash 比较缺陷
"0e132456789"=="0e7124511451155" //true
"0e123456abc"=="0e1dddada" //false
"0e1abc"=="0" //true
在进行比较运算时,倘若遇到了 0e\d + 这种字符串,就会将这种字符串解析为科学计数法。倘若不满足 0e\d + 这种模式,就会当作字符串进行比较,因此不会相等。
十六进制转换
"0x1e240"=="123456" //true
"0x1e240"==123456 //true
"0x1e240"=="1e240" //false
当其中的一个字符串是 0x 开头的时候,PHP 会将此字符串解析作为十进制而后再进行比较。
类型转换
$test=1 + "10.5"; // $test=11.5(float)
$test=1+"-1.3e3"; //$test=-1299(float)
$test=1+"bob-1.3e3";//$test=1(int)
$test=1+"2admin";//$test=3(int)
$test=1+"admin2";//$test=1(int)
?>
PHP 手册:当一个字符串欸当作一个数值来取值,其结果和类型如下:倘若该字符串无包括’.’,’e’,’E’ 并且其数值值在整形的范围之内该字符串被当作 int 来取值,其他所有状况下都被做为 float 来取值,该字符串的起始部分决定了它的值,倘若该字符串以合法的数值起始,则运用该数值,否则其值为 0。
intval () 函数:intval () 转换的时候,会将从字符串的起始进行转换晓得遇到一个非数字的字符。即使显现没法转换的字符串,intval () 不会报错而是返回 0。
var_dump(intval(2)) //2
var_dump(intval(3abcd)) //3
var_dump(intval(abcd)) //0
bool 诈骗
当存在 json_decode 和 unserialize 的时候,部分结构会被解释成 bool 类型。 json_decode 示例代码:
$json_str = {"user":true,"pass":true};
$data = json_decode($json_str,true);
if ($data[user] == admin && $data[pass]==secirity)
{
print_r(logined in as bool."\n");
}
运行结果:logined in as bool
unserialize 示例代码:
$unserialize_str = a:2:{s:4:"user";b:1;s:4:"pass";b:1;};
$data_unserialize = unserialize($unserialize_str);
var_dump($data_unserialize[user]);
if ($data_unserialize[user] == admin && $data_unserialize[pass]==secirity)
{
print_r(logined in unserialize."\n");
}
运行结果:
bool(true)
logined in unserialize
数字转换问题
$user_id = ($_POST[user_id]);
if ($user_id == "1")
{
$user_id = (int)($user_id);
#$user_id = intval($user_id);
$qry = "SELECT * FROM `users` WHERE user_id=$user_id;";
}
$result = mysql_query($qry) or die(
. mysql_error() . );能够让 user_id=0.999999999999999999999 即能够绕过判断,并且最后执行查找的结果却是 user_id=0 的数据。
var_dump("1" == 0.9999999999999999);//false
var_dump("1" == 0.99999999999999999);//true
?>
int 和 intval 在转换数字的时候都是就低的
print((int)0.9999999999999);//0
print((int)1.1);//1
intval 还有个尽力模式,便是转换所有数字直到遇到非数字为止,倘若采用:
if (intval($qq) === 123456)
{
$db->query("select * from user where qq = $qq")
}
能够传入 123456 union select version() 进行注入。
PHP5.4.4 特殊状况
这个版本的 php 的一个修改引起两个数字型字符溢出引起比较相等
$ php -r var_dump("61529519452809720693702583126814" == "61529519452809720000000000000000");
bool(true)
PHP弱类型害处
害处详细表此刻例如像有些数据验证上,两个变量类型不匹配时进行类型转换时可能会将传递的参数类型转换,有些函数存在松散性的问题,调用时,给函数传递函数没法处理的参数类型然则无报错,直接返回null,这些都有可能产生各样问题
这儿以一个ctf题,举例: 示例代码:
$pass=@$_GET[pass];
$pass2=@$_GET[pass2];
@$pass1=asdasdasd;
if(strcmp($pass,$pass2)==0 && $pass != $pass2){
echo "$pass1";
}else{
echo "aaaa!";
}
?>
这儿需要传入两个变量,对比两个参数要相同且两个字符串内容要区别 那样怎么才可让它相同呢,这儿能够经过传入数组去让它等
分别传入不同的数组,结果为
传入参数相同期
经过数组就绕过了限制,详细为何能够看后面关于该函数的介绍
函数分析
平常函数:md5(),sha1(),strcmp(),switch(),array_search(),in_array(),json_decode(),intval(),strpos(),is_numeric()
1.1:MD5(),sha1()
这个函数用于对字符串进行MD5加密 函数格式:md5(要加密的字符串,规定的输出格式)绕过办法
经过传入数组去绕过,这两个函数不可处理数组数据,md5还有一个加密的问题
示例代码:
$flag = "1234";
if (isset($_GET[name]) and isset($_GET[passwd]))
{
if ($_GET[name] == $_GET[passwd])
echo
error ; else if (md5($_GET[name]) === md5($_GET[passwd]))
die(Flag: .$flag);
else
echo
Invalid passwd. ;}
else
echo
Login first! ;?>
测试效果如下
问题在于该函数不可处理数组内容,处理数组会出错,返回结果都为false
这儿的sha1() 亦是一样道理
sha1函数用于把字符串转换为sha-1加密处理
函数格式: sha1(需要处理的字符串,需要的输出格式,二进制或16进制)
测试代码:
$flag = "flag{mkluiop}";
if (isset($_GET[name]) and isset($_GET[passwd]))
{
if ($_GET[name] == $_GET[passwd])
echo
Your password can not be your name! ;else if (sha1($_GET[name]) === sha1($_GET[passwd]))
die(Flag: .$flag);
else
echo
Invalid passwd. ;}
else
echo
Login first! ;?>
测试效果如下
这儿处理数组的结果都返回了false 都相等,引起绕过
1.2 md5加密相等问题
关于md5还有个科学计数法的问题 绕过方式php在处理0e开头,后接的字符都为数字的的字符串的时候,会将全部字符串解析为科学计数法,当有另一个0e开头的字符串和这个进行对比时,php会都当作0来处理
示例如下
var_dump(‘0e45511255’ == ‘0e1455155’);
var_dump(‘0e45511255’ == ‘0’);
?> 得到结果为
md5编码时,部分被加密的字符亦会是0e开头的
示例代码
$m1 = md5(s1091221200a);
$a = @$_GET[a];
$m2 = @md5($a);
if(isset($a)) {
if ($a != s1091221200a && $m1 == $m2) {
echo "good";
} else {
echo "hahaha";
}
}
?>
这儿咱们传入一个md5编码后开头是0e的字符串,网上找了一个,aabC9RqS,其他的还有非常多,网址 https://www.cnblogs.com/R4v3n/articles/7716671.html
得到结果为
1.3 strcmp()
这个函数的功效是比较两个字符串并且区分体积写
当字符串1大于字符串2就返回>0,当字符串1少于字符串2就返回<0,相等则返回0 函数格式: strcmp(第1个需要比较的字符串,第二个需要比较的字符串)绕过方式经过传入数组去绕过,该函数处理数组时会出现错误,strcmp会返回结果0,引起绕过
测试代码
$pass1="ASDSADSADAD";
if(isset($_GET[pass])){
if(strcmp($_GET[pass],$pass1)==0){
echo "233";
}else{
echo " ";
}
}
?>
测试效果如下
1.4 json_decode()
这个函数用于解码json格式的字符串
函数格式 json_decode(需要解码的字符串) 绕过方式当有区别类型的数据时,该函数会转换为同一类型比较,这儿会把原有的数据的数据类型转换为和传入数据的数据类型相同
测试代码
if (isset($_GET[m])) {
$m = json_decode($_GET[m]);
$flag ="dfdfgdg";
if ($m->flag == $flag) {
echo "233";
}
else {
echo "haha";
}
}
else{
echo "hahaha";
}
?>
这儿要传入一个json格式的字符,字符要用json格式去编写,这儿设定名叫作为flag,传入json格式字符为{“flag”:0},为何这儿传入的值要是0呢?这儿当咱们传入数字时,它会转化为同一类型进行比较(这儿关键点在于,要把字符转换为数字有效,由于字符转换为数字会出问题,字符会被转为0),这儿字符被转为0,咱们传入的参数为0,因此相等
测试如下
1.5 switch函数绕过方式switch选取的时候,处理的变量会被强转为int类型
这个函数通常用于按照多个要求选取执行区别动作,和if…. else类似
函数格式
switch(表达式,一般是变量)
{
case xxxx1:
当要求符合xxxx1时执行的代码
break;
case xxxx2:
当要求符合xxxx2时执行的代码
break;
….
} 这儿的问题在于switch选取的时候,处理的变量会被强转为int类型
测试代码
$a=$_GET[$a];
switch ($a) {
case 1:
echo "error";
break;
case 2:
echo "error2";
break;
case 3:
echo "error3";
break;
case 4:
echo "233";
break;
}
?>
这儿当咱们输入字符串时,会被强转为int类型的 当咱们输入字符串4abcdesdf的时候,这个$a就会被强转为int类型,使$a的值为4
测试效果如下
1.6 in_array函数
函数格式 in_array(需要在数组内搜索的数值,被搜索的数组,一个可选参数,设置TURE检测数据和数组值类型是不是相同) 绕过方式这个函数的功效是检测数组中是不是存在某个值,当无最后的检测参数为true时,默认为松散比较,引起弱类型,传入区别数据类型来绕过
关键就在于这个最后的检测的参数,倘若无这个参数的话,就会运用松散比较来判断
示例代码
$array=[1,2,3];
var_dump(in_array(aaa, $array));
var_dump(in_array(1aa, $array));
?>
测试结果如下
这儿倘若无设置检测参数为ture的话,会进行松散比较,数据类型区别的话,会进行适当的类型转换,这儿aaa被转换为int类型,被转换为0,匹配失败,然则1aa 在转换时被转换为1,匹配成功
1.7 array_search()函数绕过方式1.传入区别数据类型来绕过,无最后的检测参数为true时,默认为松散比较,引起弱类型 2.当数据类型区别会先把原有数据的数据类型的进行转换,引起弱类型的产生
该函数的功效是在数组中搜索某个键值,并返回键名 函数格式 array_search(要搜索的键值,被搜索的数组,设置TURE检测数据和数组值类型是不是相同)
这个函数有两个问题
第1个 测试代码
$array=[1,2];
var_dump(array_search(aaa, $array));
var_dump(array_search(2aa, $array));
?>
测试效果如下
和前面in_array同样,当无设定检测参数为true时,会进行松散比较,会把数据类型进行转换,而后执行
第二个问题
测试代码:
if(!is_array($_GET[a])){exit();}
$a=$_GET[a];
for($b=0;$b
if($a[$b]==="admin"){
echo "error";
exit();
}
$a[$b]=intval($a[$b]);
}
print_r($a);
if(array_search("admin",$a)===0){
echo "233";
}
else{
echo "false";
}
?>
测试效果如下
首要,这儿是判断数组的,因此要首要弄个数组,这儿设置数组值为0,而后判断字符串admin的值和这个0是不是相等,这儿数据类型区别会先把admin这个字符串类型的进行转换,结果为0,因此相等
1.8 intval() 函数
该函数用于获取变量的整数值
函数格式 intval(要转换的参数,指定转换需要的进制) 绕过办法:该函数处理本身不可处理的字符串时并不会报错,直接返回0,当函数内有其他的操作时,会把字符串这些转为数字类型再操作,况且在处理有些特殊数据的时候会有区别的处理结果
找了网上常用的intval函数处理区别数据的结果的测试代码,改了一下
echo intval(25); //25
echo ;
echo intval(2.5); //2
echo ;
echo intval(25); //25
echo ;
echo intval(+25); //25
echo ;
echo intval(-25);//-25
echo ;
echo intval(025);//21
echo ;
echo intval(025);//25
echo ;
echo intval(1e10);//1410065408
echo ;
echo intval(1e10);//1
echo ;
echo intval(0x1A);//26
echo ;
echo intval(25000000);//25000000
echo ;
echo intval(250000000000000000000);//2007498752
echo ;
echo intval(420000000000000000000);//2147483647
echo ;
echo intval(25, 8);//25
echo ;
echo intval(0x42);//0
echo ;
echo intval(array());//0
echo ;
echo intval(array(aaa, abb));//1
echo ;
echo intval(aaa, 8);//0
echo ;
echo intval(fgh);//0
echo ;
echo intval(1e10+8);//1410065416
echo ;
echo intval(0x2000+8);//8200
?>
测试结果如下
这儿网上找了一个ctf题的代码,测试一下
@$a=$_GET[a];
if(intval($a) < 2000 && intval($a +1) >2050){
echo "hahahah";
}
else
{
echo "233";
}
?>
这儿需要你传入$a的值少于2000,且加1后大于2050,那样怎么样才可绕过呢? 回看上面的,看这个函数是怎么处理区别类型的字符串的,看最后一条和倒数第七条,当咱们只是传入一个单引号闭合的0x2000时,这儿当作一个字符串去处理该参数,返回结果为1,当后面在该函数内进行加操作时,该参数为16进制的字符串,被解析为十进制数字去处理,能够在电脑上打开计算器试下
后续进行了加8操作,得到8200,本题就能够经过此方式来完成
传入参数0x2000 得到结果
1.9 is_numeric函数
这个函数用于检测变量是不是只由数字构成,否则返回false 函数格式is_numeric(目的字符)绕过办法
当传入数字开头,字母在后的字符串时,参数能够绕过某些检测,从而进行到下一步,而php处理区别字符串时又会把两个字符串转换到同一类型去处理
测试代码
@$a="hehehehehe";
@$temp = $_GET[p];
if(is_numeric($temp)){
die("hahha");
}
else if($temp>2010) {
echo $a;
}
?>
这个代码里需要传入一个参数,参数需求大于2010又不可是数字,倘若数字就会半途中断从而没法输出变量a里的内容,这儿咱们输入一个2020a的字符串,输入后因为不是纯数字,执行到下一步,又由于php在处理数据对比时会将两个数据转换为同一类型的,从而达到绕过效果
结果如下
2.0 strpos函数
strpos函数用于查询目的字符在字符串中显现的第1次的位置
函数格式:strpos(字符串,目的字符) 绕过办法
strpos在处理数组时直接返回null,而无返回false,引起问题出现
测试代码
if (isset ($_GET[a])) {
if(@ereg("^[1-9]+$", $_GET[a]) === FALSE)
echo 必须输入数字才行;
else if (strpos ($_GET[a], #asdafdasdadas) !== FALSE)
die("bababab");
else
echo hoho;
}
?>
这儿经过数组的形式去传入一个数字,首要绕过第1道检测,而后在第二处strpos检测时,经过数组去绕过,直接返回null,从而绕过
2.1 strlen函数 + intval函数
让你传一个值,这个值长度要少于4,又要比500000大,你要怎样处理?
测试代码:
highlight_file(__FILE__);
$num = @$_GET[num];
if(isset($num) && strlen($num) <= 4 && intval($num + 1) > 500000)
{
echo file_get_contents(flag);
}
绕过办法:5e5 由于在strlen()函数的判断中,5e5被认为是字符串,长度为3,然则当他跟数字比较或进行数学运算的时候,会被当成科学计数法,转成数字,亦便是5乘以10的5次方,亦便是500000,500000+1,自然是比500000大的申明:本公众号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,
所有渗透都需获取授权,违者后果自动承担,与本号及作者无关,请谨记守法.
没看够~?欢迎关注!
分享本文到伴侣圈,能够凭截图找老师领取
上千教程+工具+交流群+靶场账号哦
分享后扫码加我!
回顾往期内容
Xray挂机刷漏洞
零基本学黑客,该怎么学?
网络安全人员必考的几本证书!
文库|内网神器cs4.0运用说明书
代码审计 | 这个CNVD证书拿的有点容易
【精选】SRC快速入门+上分小秘籍+实战指南
点赞+在看支持一下吧~感谢看官老爷~
你的点赞是我更新的动力
|