作者:錦行科技
常見的弱類型問題
類型轉換問題
類型轉換是無法避免的問題。例如需要將GET或者是POST的參數轉換為int類型,或者是兩個變量不匹配的時候,PHP會自動地進行變量轉換。但是PHP是一個弱類型的語言,導致在進行類型轉換的時候會存在很多意想不到的問題。
數學運算
當php進行一些數學計算的時候
<?php
var_dump(0 == '0'); // true
var_dump(0 == 'abc'); // true
var_dump(0 === 'abc'); // false
var_dump(1 == '1abc'); // true
var_dump('1e0'=='1e2'); // false
var_dump('0.0'==0); // true
var_dump('0.0'==''); //false
//還有下面這樣的
if(md5('s878926199a')==0){
echo 'true';
}
?>
因為md5('s878926199a')=0e545993274517709034328855841020就是0的n次方,所以還是等于0
但是要注意:
"0e123456abc"=="0e1dddada"http://false
這種返回的是為假
語句條件的松散判斷
<?php
if (isset($_GET['which']))
{
$which = $_GET['which'];
switch ($which)
{
case 0:
case 1:
case 2:
require_once $which.'.php';
break;
}
}
?>
函數的松散判斷
<?php
if(strcmp('1a',1)){
echo 'test';
}
?>
<?php
var_dump(in_array("1a",
array(1,2,3)));
?>
In_array函數和array_search函數的問題可以在in_array函數后面加一個true選項,就能解決比如:
<?php
if(in_array("1a", array(1,2,3),true)){
echo 'true';
}
?>
md5()
$array1[] = array(
"foo" => "bar",
"bar" => "foo",
);
$array2 = array("foo", "bar",
"hello", "world");
var_dump(md5($array1)==
md5($array2));
//回顯為true
十六進制轉換
還存在一種十六進制余字符串進行比較運算時的問題。例子如下:
"0x1e240"=="123456"//true
"0x1e240"==123456//true
"0x1e240"=="1e240"//false
當其中的一個字符串是0x開頭的時候,PHP會將此字符串解析成為十進制然后再進行比較,0×1240解析成為十進制就是123456,所以與int類型和string類型的123456比較都是相等。
下面我們來看一個dedecms的弱類型安全問題。
漏洞分析
dedecms/member/resetpassword.php //75行
else if($dopost == "safequestion")
{
$mid = preg_replace("#[^0-9]#", "", $id);
$sql = "SELECT safequestion,safeanswer,userid,email FROM #@__member WHERE mid = '$mid'";
$row = $db->GetOne($sql);
if(empty($safequestion)) $safequestion = '';
if(empty($safeanswer)) $safeanswer = '';
if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer)
{
sn($mid, $row['userid'], $row['email'], 'N');
exit();
}
else
{
ShowMsg("對不起,您的安全問題或答案回答錯誤","-1");
exit();
}
}
管理員帳號admin的$row['safequestion']默認是為’0’(字符串),所以$safequestion不能為空。否則不進入$row['safequestion'] == $safequestion。而$_GET[‘safequestion ’]傳過來的值為字符串,當$_GET[‘safequestion ’]為’0’時進入if(empty($safequestion))。當$_GET[‘safequestion ’]為’0.0’時不進入if(empty($safequestion)),而’0’=’0.0’進入if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer),右邊的$safeanswer本身就為空。所以不用理。
跟進函數sn:
function sn($mid,$userid,$mailto, $send = 'Y')
{
global $db;
$tptim= (60*10);
$dtime = time();
$sql = "SELECT * FROM #@__pwd_tmp WHERE mid = '$mid'";
$row = $db->GetOne($sql);
if(!is_array($row))
{
//發送新郵件;
newmail($mid,$userid,$mailto,'INSERT',$send);
}
//10分鐘后可以再次發送新驗證碼;
elseif($dtime - $tptim > $row['mailtime'])
{
newmail($mid,$userid,$mailto,'UPDATE',$send);
}
//重新發送新的驗證碼確認郵件;
else
{
return ShowMsg('對不起,請10分鐘后再重新申請', 'login.php');
}
}
這里從數據庫取出來的值應該為空$sql = "SELECT * FROM #@__pwd_tmp WHERE mid = '$mid'";于是進入
if(!is_array($row))
{
//發送新郵件;
newmail($mid,$userid,$mailto,'INSERT',$send);
}
注意一下$send為N
我們跟進newmail函數:
function newmail($mid, $userid, $mailto, $type, $send)
{
global $db,$cfg_adminemail,$cfg_webname,$cfg_basehost,$cfg_memberurl;
$mailtime = time();
$randval = random(8);
$mailtitle = $cfg_webname.":密碼修改";
$mailto = $mailto;
$headers = "From: ".$cfg_adminemail."\r\nReply-To: $cfg_adminemail";
$mailbody = "親愛的".$userid.":\r\n您好!感謝您使用".$cfg_webname."網。\r\n".$cfg_webname."應您的要求,重新設置密碼:(注:如果您沒有提出申請,請檢查您的信息是否泄漏。)\r\n本次臨時登陸密碼為:".$randval." 請于三天內登陸下面網址確認修改。\r\n".$cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid;
if($type == 'INSERT')
{
$key = md5($randval);
$sql = "INSERT INTO `#@__pwd_tmp` (`mid` ,`membername` ,`pwd` ,`mailtime`)VALUES ('$mid', '$userid', '$key', '$mailtime');";
if($db->ExecuteNoneQuery($sql))
{
if($send == 'Y')
{
sendmail($mailto,$mailtitle,$mailbody,$headers);
return ShowMsg('EMAIL修改驗證碼已經發送到原來的郵箱請查收', 'login.php','','5000');
} else if ($send == 'N')
{
return ShowMsg('稍后跳轉到修改頁', $cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid."&key=".$randval);
}
}
else
{
return ShowMsg('對不起修改失敗,請聯系管理員', 'login.php');
}
}
這里直接是對dede_pwd_tmp表插入臨時密碼,臨時密碼為$randval = random(8);是8位,但是別急。緊接著插入完成之后ShowMsg('稍后跳轉到修改頁', $cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid."&key=".$randval);也就是說在insert完成之后跳轉把$randval輸出到了頁面。
也就是這個key,這個key就是管理員的臨時密碼。
利用方法:
先注冊一個帳號并登錄,然后訪問:
http://localhost//member/resetpassword.php?dopost=safequestion&safequestion=0.0&safeanswer=&id=1
就可以發現上面那個包了
結語
不要相信用戶輸入。應多使用===來避免弱類型安全問題.
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/505/
暫無評論