高質量的安全文章,安全offer面試經驗分享
盡在 # 掌控安全EDU #
作者:掌控安全-手電筒
一、PHP弱類型簡介弱類型簡單來說就是數據類型可以被忽視的語言,和強類型語言的強制數據類型定義不同,弱類型可以一個變量賦不同數據類型的值
php雖然屬於弱語言,但是裡面也有一些強語言類型相關的強制定義數據類型的方法
比如php裡的 == 和 === 之間的區別
== 為鬆散比較 只比較值,不比較數據類型
而 === 為嚴格比較,不僅比較值也比較類型,可以看作是強語言的強制數據類型要相同
具體表現在比如像一些數據驗證上,兩個變量類型不匹配時進行類型轉換時可能會將傳遞的參數類型轉換,一些函數存在鬆散性的問題,調用時,給函數傳遞函數無法處理的參數類型但是沒有報錯,直接返回null,這些都有可能產生各種問題
這裡以一個ctf題,舉例:
示例代碼:
<?php
$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.:MD5(),sha1()這個函數用於對字符串進行MD5加密
繞過方法
函數格式:md5(要加密的字符串,規定的輸出格式)通過傳入數組去繞過,這兩個函數不能處理數組數據,md5還有一個加密的問題
示例代碼:
<?php
$flag ="1234";
if(isset($_GET['name'])and isset($_GET['passwd']))
{
if($_GET['name']== $_GET['passwd'])
echo '<p>error</p>';
elseif(md5($_GET['name'])=== md5($_GET['passwd']))
die('Flag: '.$flag);
else
echo '<p>Invalid passwd.</p>';
}
else
echo '<p>Login first!</p>';
?>
測試效果如下
問題在於該函數不能處理數組內容,處理數組會出錯,返回結果都為false
這裡的sha1() 也是同樣道理
sha1函數用於把字符串轉換為sha-1加密處理
函數格式:
sha1(需要處理的字符串,需要的輸出格式,二進位或16進位)
測試代碼:
<?php
$flag ="flag{mkluiop}";
if(isset($_GET['name'])and isset($_GET['passwd']))
{
if($_GET['name']== $_GET['passwd'])
echo '<p>Your password can not be your name!</p>';
elseif(sha1($_GET['name'])=== sha1($_GET['passwd']))
die('Flag: '.$flag);
else
echo '<p>Invalid passwd.</p>';
}
else
echo '<p>Login first!</p>';
?>
測試效果如下
這裡處理數組的結果都返回了false 都相等,導致繞過
2. md5加密相等問題關於md5還有個科學計數法的問題
繞過方式php在處理0e開頭,後接的字符都為數字的的字符串的時候,會將整個字符串解析為科學計數法
當有另一個0e開頭的字符串和這個進行對比時,php會都當作0來處理
示例如下
<?phpvar_dump(『0e45511255』 == 『0e1455155』);var_dump(『0e45511255』 == 『0』);?>得到結果為
md5編碼時,部分被加密的字符也會是0e開頭的
示例代碼
<?php
$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
得到結果為
3.strcmp()這個函數的作用是比較兩個字符串並且區分大小寫
當字符串1大於字符串2就返回>0,當字符串1小於字符串2就返回<0,相等則返回0繞過方式
函數格式: strcmp(第一個需要比較的字符串,第二個需要比較的字符串)通過傳入數組去繞過,該函數處理數組時會發生錯誤,strcmp會返回結果0,導致繞過
測試代碼
<?php
$pass1="ASDSADSADAD";
if(isset($_GET['pass'])){
if(strcmp($_GET['pass'],$pass1)==0){
echo "233";
}else{
echo " ";
}
}
?>
測試效果如下
4. json_decode()
這個函數用於解碼json格式的字符串
函數格式 json_decode(需要解碼的字符串)
繞過方式當有不同類型的數據時,該函數會轉換為同一類型比較,這裡會把原有的數據的數據類型轉換為和傳入數據的數據類型相同
測試代碼
<?php
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,所以相等
測試如下
5. switch函數繞過方式switch選擇的時候,處理的變量會被強轉為int類型
這個函數一般用於根據多個條件選擇執行不同動作,和if…. else相似
函數格式
switch(表達式,通常是變量)
{
case xxxx1:
當條件符合xxxx1時執行的代碼
break;
case xxxx2:
當條件符合xxxx2時執行的代碼
break;
….
}
這裡的問題在於switch選擇的時候,處理的變量會被強轉為int類型測試代碼
<?php
$a=$_GET['$a'];
switch($a){
case1:
echo "error";
break;
case2:
echo "error2";
break;
case3:
echo "error3";
break;
case4:
echo "233";
break;
}
?>
這裡當我們輸入字符串時,會被強轉為int類型的
當我們輸入字符串4abcdesdf的時候,這個$a就會被強轉為int類型,使$a的值為4
測試效果如下
6. in_array函數函數格式 in_array(需要在數組內搜索的數值,被搜索的數組,一個可選參數,設置TURE檢查數據和數組值類型是否相同)
繞過方式這個函數的作用是檢查數組中是否存在某個值,當沒有最後的檢測參數為true時,默認為鬆散比較,導致弱類型,傳入不同數據類型來繞過
關鍵就在於這個最後的檢查的參數,如果沒有這個參數的話,就會使用鬆散比較來判斷
示例代碼
<?php
$array=[1,2,3];
var_dump(in_array('aaa', $array));
var_dump(in_array('1aa', $array));
?>
測試結果如下
這裡如果沒有設置檢查參數為ture的話,會進行鬆散比較,數據類型不同的話,
會進行適當的類型轉換,這裡aaa被轉換為int類型,被轉換為0,匹配失敗,但是1aa 在轉換時被轉換為1,匹配成功
7. array_search()函數繞過方式1.傳入不同數據類型來繞過,沒有最後的檢測參數為true時,默認為鬆散比較,導致弱類型
2.當數據類型不同會先把原有數據的數據類型的進行轉換,導致弱類型的產生該函數的作用是在數組中搜索某個鍵值,並返回鍵名
函數格式 array_search(要搜索的鍵值,被搜索的數組,設置TURE檢查數據和數組值類型是否相同)
這個函數有兩個問題
第一個
測試代碼
<?php
$array=[1,2];
var_dump(array_search('aaa', $array));
var_dump(array_search('2aa', $array));
?>
測試效果如下
和前面in_array一樣,當沒有設定檢測參數為true時,會進行鬆散比較,會把數據類型進行轉換,然後執行
第二個問題
測試代碼:
<?php
if(!is_array($_GET['a'])){exit();}
$a=$_GET['a'];
for($b=0;$b<count($a);$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,所以相等
8. intval() 函數該函數用於獲取變量的整數值
函數格式 intval(要轉換的參數,指定轉換需要的進位)
繞過方法:該函數處理本身不能處理的字符串時並不會報錯,直接返回0
當函數內有其他的操作時,會把字符串這些轉為數字類型再操作,而且在處理一些特殊數據的時候會有不同的處理結果
找了網上常用的intval函數處理不同數據的結果的測試代碼,改了一下
<?php
echo intval(25);//25
echo '<br/>';
echo intval(2.5);//2
echo '<br/>';
echo intval('25');//25
echo '<br/>';
echo intval('+25');//25
echo '<br/>';
echo intval('-25');//-25
echo '<br/>';
echo intval(025);//21
echo '<br/>';
echo intval('025');//25
echo '<br/>';
echo intval(1e10);//1410065408
echo '<br/>';
echo intval('1e10');//1
echo '<br/>';
echo intval(0x1A);//26
echo '<br/>';
echo intval(25000000);//25000000
echo '<br/>';
echo intval(250000000000000000000);//2007498752
echo '<br/>';
echo intval('420000000000000000000');//2147483647
echo '<br/>';
echo intval(25,8);//25
echo '<br/>';
echo intval('0x42');//0
echo '<br/>';
echo intval(array());//0
echo '<br/>';
echo intval(array('aaa','abb'));//1
echo '<br/>';
echo intval('aaa',8);//0
echo '<br/>';
echo intval('fgh');//0
echo '<br/>';
echo intval('1e10'+8);//1410065416
echo '<br/>';
echo intval('0x2000'+8);//8200
?>
測試結果如下
這裡網上找了一個ctf題的代碼,測試一下
<?php
@$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
9. is_numeric函數
得到結果這個函數用於檢測變量是否只由數字組成,否則返回false
繞過方法
函數格式is_numeric(目標字符)當傳入數字開頭,字母在後的字符串時,參數可以繞過某些檢測,從而進行到下一步,而php處理不同字符串時又會把兩個字符串轉換到同一類型去處理
測試代碼
<?php
@$a="hehehehehe";
@$temp= $_GET['p'];
if(is_numeric($temp)){
die("hahha");
}
elseif($temp>2010){
echo $a;
}
?>
這個代碼裡需要傳入一個參數,參數要求大於2010又不能是數字
如果數字就會中途中斷從而無法輸出變量a裡的內容
這裡我們輸入一個2020a的字符串,輸入後由於不是純數字,執行到下一步,又因為php在處理數據對比時會將兩個數據轉換為同一類型的,從而達到繞過效果
結果如下
10. strpos函數strpos函數用於查找目標字符在字符串中出現的第一次的位置
函數格式:strpos(字符串,目標字符)
繞過方法strpos在處理數組時直接返回null,而沒有返回false,導致問題發生
測試代碼
<?php
if(isset ($_GET['a'])){
if(@ereg("^[1-9]+$", $_GET['a'])=== FALSE)
echo '必須輸入數字才行';
elseif(strpos ($_GET['a'],'#asdafdasdadas')!== FALSE)
die("bababab");
else
echo 'hoho';
}
?>
這裡通過數組的形式去傳入一個數字,首先繞過第一道檢測,然後在第二處strpos檢測時,通過數組去繞過,直接返回null,從而繞過
聲明:本公眾號分享的內容,僅用於網安愛好者之間的技術討論,禁止用於違法途徑,否則需自行承擔後果,本公眾號及作者不承擔相應的後果.
Xray掛機刷漏洞
POC批量驗證Python腳本編寫
實戰紀實 | SQL漏洞實戰挖掘技巧
滲透工具 | 紅隊常用的那些工具分享
代碼審計 | 這個CNVD證書拿的有點輕鬆
掃碼白嫖視頻+工具+進群+靶場等資料
掃碼白嫖!
還有免費的配套靶場、交流群哦!