轉(zhuǎn)自:PHP代碼安全【PHP弱口令帝际、加密函數(shù)蔓同、繞過(guò)函數(shù)】/CTF代碼審計(jì)題 - Sp4rkW的博客 - CSDN博客
注:結(jié)合現(xiàn)在所學(xué),把以前的一些很散的博客給匯總起來(lái)方便利用【刪了黑歷史蹲诀,哈哈哈】
1斑粱、判等類型
1.1、”==”與”===”比較漏洞/switch
如果你認(rèn)為“==”和"==="最大的區(qū)別在于脯爪,“==”是判斷數(shù)值是否相等珊佣,“===”則是判斷數(shù)值和類型是否相等,那就錯(cuò)了披粟,這并沒(méi)有說(shuō)到最核心的一個(gè)關(guān)鍵點(diǎn)咒锻,要知道“==”最可怕的一點(diǎn)是,如果類型不同的進(jìn)行比較守屉,其會(huì)將類型轉(zhuǎn)換成相同的再進(jìn)行比較
<?php?
var_dump("admin" ==0);
var_dump("1admin" ==1);
var_dump("2admin" ==2);
var_dump("admin1" ==1);
var_dump("admin1" ==0);
var_dump("0e123456" =="0e4456789");
?>
#bool(true)
bool(true)
bool(true)
bool(false)
bool(true)
bool(true)
[Finished in 2.9s]123456789101112131415
"0e123456"=="0e456789"相互比較的時(shí)候惑艇,會(huì)將0e這類字符串識(shí)別為科學(xué)技術(shù)法的數(shù)字,0乘以10的無(wú)論多少次方都是零,所以相等
當(dāng)一個(gè)字符串欸當(dāng)作一個(gè)數(shù)值來(lái)取值滨巴,其結(jié)果和類型如下:
如果該字符串沒(méi)有包含'.'思灌,'e','E'并且其數(shù)值值在整形的范圍之內(nèi)恭取,該字符串被當(dāng)作int來(lái)取值泰偿,其他所有情況下都被作為float來(lái)取值,該字符串的開始部分決定了它的值
如果該字符串以合法的數(shù)值開始蜈垮,則使用該數(shù)值耗跛,否則其值為0
<?php?
var_dump(1+"admin1");
var_dump(1+"1admin");
var_dump(1+"2e2");
var_dump(1+"-2e2");
var_dump(1+"hh-2e2");
var_dump(1+"1hh-2e2");
?>
#int(1)
int(2)
float(201)
float(-199)
int(1)
int(2)
[Finished in 0.3s]123456789101112131415
switch同等原理的利用,這里不再做解釋:
<?php?
$a = "2admin";
switch ($a) {
? ? case '1':
? ? ? ? echo "1";
? ? ? ? break;
? ? case '2':
? ? ? ? echo "2";
? ? ? ? break;
? ? default:
? ? ? ? echo "3";
? ? ? ? break;
}
?>
#3[Finished in 0.4s]123456789101112131415
1.2攒发、bool類型的true比較
bool類型的true跟任意字符串可以弱類型相等
<?php?
if(true == "GETF"){
? ? echo "OK";
}
?>
#OK[Finished in 0.3s]123456
1.3调塌、strcmp比較漏洞
注意VERSION>5.3的官方文檔
Note a difference between 5.2 and 5.3 versions?
echo (int)strcmp('pending',array());?
will output -1 in PHP 5.2.16 (probably in all versions prior 5.3)?
but will output 0 in PHP 5.3.3?
Of course, you never need to use array as a parameter in string comparisions. 1234567
所以說(shuō)5.3版本后對(duì)輸入?yún)?shù)錯(cuò)誤(數(shù)組)會(huì)返回0,從正常返回邏輯來(lái)說(shuō)惠猿,也可以解釋為相等
1.4羔砾、sha1加密比較
$_GET['name'] == $_GET['password']
sha1($_GET['name']) === sha1($_GET['password'])
#要求滿足上述條件123
其實(shí)最簡(jiǎn)單的是報(bào)錯(cuò),false偶妖,至于為什么姜凄,其實(shí)仔細(xì)研究SHA1加密你就發(fā)現(xiàn),其要求參數(shù)不能為數(shù)組趾访,那我將傳入的參數(shù)改成數(shù)組态秧,兩邊return的結(jié)果不就都為false,從而腹缩,滿足不等與相等了么。實(shí)現(xiàn)步驟更簡(jiǎn)單空扎,bp中將傳參變量name藏鹊,password加個(gè)[]即可
1.5、MD5加密比較
類型1
$_GET['name'] != $_GET['password']
MD5($_GET['name']) == MD5($_GET['password'])
#要求滿足上述條件123
特殊子串舉例如下:
240610708转锈、QNKCDZO盘寡、aabg7XSs、aabC9RqS
其實(shí)就是利用了==的那個(gè)原理:"0e123456"=="0e456789"相互比較的時(shí)候撮慨,會(huì)將0e這類字符串識(shí)別為科學(xué)技術(shù)法的數(shù)字竿痰,0乘以10的無(wú)論多少次方都是零,所以相等
這類特殊子串加密的結(jié)果都是0e開頭的
類型2
if($_POST['param1']!==$_POST['param2'] && md5($_POST['param1'])===md5($_POST['param2'])){
? ? die("success!");
}123
使用了強(qiáng)等于砌溺,那么使用數(shù)組繞過(guò)影涉,利用 error === error
param1[]=1¶m2[]=21
類型3
if((string)$_POST['param1']!==(string)$_POST['param2'] && md5($_POST['param1'])===md5($_POST['param2'])){
? ? ? ? die("success!);
}123
Param1=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
Param2=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a212
MD5值相同使用谷歌可以搜到相當(dāng)多被巧妙構(gòu)造出的二進(jìn)制文件,其MD5相同规伐,注意一點(diǎn)蟹倾,post時(shí)一定要urlencode!!鲜棠!
2肌厨、變量覆蓋漏洞
2.1、遍歷初始化變量
如以下的示例代碼豁陆,使用foreach來(lái)遍歷數(shù)組中的值柑爸,然后再將獲取到的數(shù)組鍵名作為變量,數(shù)組中的鍵值作為變量的值盒音。因此就產(chǎn)生了變量覆蓋漏洞表鳍。若提交參數(shù)chs,則可覆蓋變量"$chs"的值里逆。
注意:在代碼審計(jì)時(shí)需要注意類似“$$k”的變量賦值方式有可能覆蓋已有的變量进胯,從而導(dǎo)致一些不可控制的結(jié)果。
? ? <??
? ? $chs = '';?
? ? if($_POST && $charset != 'utf-8'){?
? ? ? ? $chs = new Chinese('UTF-8', $charset);?
? ? ? ? foreach($_POST as $key => $value){?
? ? ? ? ? ? $$key = $chs->Convert($value);?
? ? ? ? }?
? ? ? ? unset($chs);?
? ? }?
? ? ?>? 12345678910
2.2原押、parse_str()變量覆蓋
//var.php?var=new?
$var='init';?
parse_str($_SERVER['QUERY_STRING']);? #parse_str — 將字符串解析成多個(gè)變量胁镐,如果參數(shù)str是URL傳遞入的查詢字符串(query string),則將它解析為變量并設(shè)置到當(dāng)前作用域诸衔。
print $var; 1234
$_SERVER['QUERY_STRING']的具體詳細(xì)解釋可以參考這里
2.3盯漂、import_request_variables變量覆蓋
<?php?
$auth = '0';?
import_request_variables('G');? #import_request_variables — 將 GET/POST/Cookie 變量導(dǎo)入到全局作用域中。如果你禁止了 register_globals笨农,但又想用到一些全局變量就缆,那么此函數(shù)就很有用。
if($auth == 1){?
? echo "private!";?
}else{?
? echo "public!";?
}?
?> 12345678910
當(dāng)用戶訪問(wèn)鏈接為www.xxx.com/test.php?auth=aaa時(shí)就會(huì)出現(xiàn)變量覆蓋問(wèn)題
2.4谒亦、extract()變量覆蓋
<?php?
$auth = '0';?
extract($_GET)竭宰;?
if($auth==1){?
echo "private!";?
}else{?
echo "public!";?
}?
?>
extract(array,extract_rules,prefix)# 函數(shù)從數(shù)組中將變量導(dǎo)入到當(dāng)前的符號(hào)表,該函數(shù)使用數(shù)組鍵名作為變量名,使用數(shù)組鍵值作為變量值份招。
123456789101112
當(dāng)用戶訪問(wèn)鏈接為www.xxx.com/test.php?auth=aaa時(shí)就會(huì)出現(xiàn)變量覆蓋問(wèn)題切揭,安全的做法是確定register_globals=OFF后,在調(diào)用extract()時(shí)使用EXTR_SKIP保證已有變量不會(huì)被覆蓋锁摔。
3廓旬、想不到怎么分類的一批
3.1、ereg正則%00截?cái)?/p>
ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE#如果在 string 中找到 pattern 模式的匹配則返回 所匹配字符串的長(zhǎng)度谐腰,如果沒(méi)有找到匹配或出錯(cuò)則返回 FALSE孕豹。如果沒(méi)有傳遞入可選參數(shù) regs 或者所匹配的字符串長(zhǎng)度為 0,則本函數(shù)返回 1十气。
12
ereg()函數(shù)用指定的模式搜索一個(gè)字符串中指定的字符串,如果匹配成功返回true,否則,則返回false励背。搜索字母的字符是大小寫敏感的。
Eregi匹配可以用%00截?cái)?/p>
Eregi匹配可用數(shù)組繞過(guò)
ereg是處理字符串砸西,傳入數(shù)組之后椅野,ereg是返回NULL
注意:This function was DEPRECATED in PHP 5.3.0, and REMOVED in PHP 7.0.0. 即,PHP7中已經(jīng)被移除
3.2、in_array()強(qiáng)轉(zhuǎn)類型
$array=[0,1,2,'3'];?
var_dump(in_array('abc', $array)); //true?
var_dump(in_array('1bc', $array)); //true 123
注意:在所有php認(rèn)為是int的地方輸入string竟闪,都會(huì)被強(qiáng)制轉(zhuǎn)換
安全代碼的一個(gè)要點(diǎn):永遠(yuǎn)不要相信用戶的輸入离福!