这一周自己学习了PHP的基本语法和对PHP弱类型进行总结,下边就是我的分享。
一、PHP的基本语法
PHP的基本语法,我自己主要是在 http://www.w3school.com.cn/php/index.asp 这个网站上学习的,里边介绍的非常详细。如果没有PHP基础的,可以去那个网站上学习。我主要是介绍PHP弱类型,以及对PHP弱类型的总结。
二、PHP弱类型的总结
因为在ctf比赛中,PHP弱类型的题也出现不少,有必要学习PHP弱类型。所以自己也是在网上找一些PHP弱类型的知识。
---
#<center> PHP弱类型总结与例题</center> #
在ctf比赛中,PHP弱类型的题也出现了不少,所以有必要去了解和和掌握这类型的题。自己也是总结了这几周做PHP弱类型的题以及在网上找的相关知识,来做一个整体的PHP弱类型总结。
# 0x01、PHP中"=="与"==="的符号比较
<?php
$a==$b;
$a===$b;
?>
== 在进行比较时,先将字符串的类型转化为相同,再次进行比较
===在进行比较时,先判断两种字符的类型是否相等,再比较值是否相等
如例题:
<?php
if(isset($_GET['name']) and isset($_GET['password'])){
if($_GET['name']==$_GET['password'])
echo '<p>Your password can not be your name!</p>';
else if(sha1($_GET['name'])===sha1($_GET['password']))
die('Flag:'.$flag);
else
echo '<p>Invalid password.</p>';
}
else{
echo '<p>Login first!</p>';
?>
这就是一道典型的PHP弱类型的题,但需要有PHP基本的句法知识,此题还涉及到安全哈希加密算法sha1。下边我们对代码进行分析
isset() -- 来检测变量是否设置
对name和password,我们可以让其类型为数组,但让数组里的数值不相等。 所以我们可以再这个网站.php后加上一个语句
?name[]=a$password[]=b
这样回车即可得到flag
# 0x02、 数字和字符串或有数字的字符串,会转化成数值进行比较
PHP不会严格检验传入的变量,也可以将变量自由的转换类型
例如:在$a=$b的比较中
$a=null;$b=false;//判断为真
$a=''; $b=0; //判断也为真
详细比较,如下所示
<?php
var_dump("justinlee"==0); //ture
var_dump("1justinlee"==1);//ture
var_dump("justinlee1"==1);//ture
var_dump("justin1"==1); //false
var_dump("justinlee1"==0);//ture
var_dump("0e12345"=="0e456789");//ture
?>
观察上面代码,"justinlee"==0 比较时,因为justinlee是字符串,会被强制转化为数值,而结果是0,就和0相等。"1justinlee"就会被转化为1,所以"1justinlee"==1就为ture。
对"justinlee1"==1为ture和"justin1"==1为flase,这是为什么呢?原来是当一个字符串当作一个数值来取值时,其结果和类型如下:如果该字符串没有包含'.','e','E'时,并且其数值在整形的范围之内,该字符串被当作为int来取值,其他所有情况下都被作为float来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值。否则其值为0
"0e12345"=="0e456789"在进行比较时,会将这类字符串识别为科学记数法,0的多少次方都是0,所以相等。
# 0x03、MD5绕过
代码如下
<?php
$md51==md5('QNKCDZO');
$a=@$_GET['a'];
$md5=@md5($a);
if(isset($a)){
if($a!='QNKCDZO'&&$md51 == $md52){
echo"nctf{************}";}
else{
echo"false!!!";}
}
else{
echo"please input a";}
?>
这是一道md5绕过题,分析代码得,QNKCDZO是用MD5函数加密,然后赋值给md51,if后边是判断输入的a不等于QNKCDZO,而且md51=a。首先,对QNKCDZO加密,去浏览器搜索MD5函数,进行加密。加密后的结果如下所示
md5:0e83040045199349405802421990391
可以看到加密后的结果是以0e开头的,而md5开头是0e的字符串 上边提到过,0e在比较的时候会将其视作为科学计数法,所以无论0e后面是什么,0的多少次方还是0
所以去百度找以0e开头MD5的值,如下
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
随便从中找一个a值输入,此题便可得到flag值
# 0x04、strcmp漏洞绕过
如例题
<?php
$password="***************"
if(isset($_POST['password'])){
if (strcmp($_POST['password'], $password) == 0) {
echo "Right!!!login success";
exit();
} else {
echo "Wrong password..";}
?>
分析代码得
strcmp是比较两个字符串,如果str1<str2 则返回<0 如果str1大于str2返回>0 如果两者相等 返回0
我们是不知道$password的值的,题目要求strcmp判断的接受的值和$password必需相等,strcmp传入的期望类型是字符串类型,如果传入的是个数组,它会如何比较呢?当传入password[]=xxxx时,因为函数接受不到不符合得类型,将出现错误,但是还是判断其相等。所以我们可以用password[]=xxxx进行绕过。
# 0x05、Json绕过
<?php if (isset($_POST['message'])) {
$message = json_decode($_POST['message']);
$key ="*********";
if ($message->key == $key) {
echo "flag";
}
else {
echo "fail";
}
}else{
echo "~~~~"
}
?>
输入一个json类型的字符串,json_decode函数解密成一个数组,判断数组中key的值是否等于$key的值,但是$key的值我们不知道,但是可以利用0=="justinlee"这种形式绕过
# 0x06、array_search is_array绕过
代码如下:
<?php
if(!is_array($_GET['test'])){exit();}
$test=$_GET['test'];
for($i=0;$i<count($test);$i++){
if($test[$i]==="admin"){
echo "error";
exit();}
$test[$i]=intval($test[$i]);}
if(array_search("admin",$test)===0){
echo "flag";}
else{
echo "false";
}
?>
分析代码,首先我们要了解array_search is_array的意思。
php搜索数组中我们一般会用到array_search和is_array两个函数。array_search()和is_array()一样,在数组中查找一个键值。如果找到了该值,匹配元素的键名会被返回。如果没找到,则返回 false。
所以先判断传入的是不是数组,然后循环遍历数组中的每个值,并且数组中的每个值不能和admin相等,并且将每个值转化为int类型,再判断传入的数组是否有admin,有则返回flag。即payload test[]=0可以绕过。
下面是array_search语法的介绍
array_search(value,array,strict)
value、array是参数,必需填写的,strict可选 函数判断array中的值是存在value,存在则返回该值的键值 第三个参数默认为false,如果设置为true则会进行严格过滤。
<?php
$a=array(0,1);
var_dump(array_search("admin",$a));//int(0)=>返回键值0
var_dump(array_seach("1admin",$a));//int(1)==>返回键值1
?>
array_search函数类似于==,也就是$a=="admin",所以是$a=0。当然如果第三个参数为true则就不能绕过。