「學習筆記」PHP 函數安全
PHP 函數安全
is_numeric
檢測變量是否為數字或者數字字符串。
當前 PHP 最新版本的 is_numeric 會忽略 %0a 等字符,但 %00 不會被忽略。
PHP 精度
PHP 為雙精度格式,IEEE 754。
簡單說,IEEE 754 是一個規定了計算機如何表示和處理“浮點數”的技術標準,在 IEEE 754 標準出現之前,各家電腦公司用自己的方法表示小數,結果同一段計算程序在不同電腦上算出來的結果可能不一樣。IEEE 754 就像是為計算機世界統一了“小數的語法”,確保了計算的一致性和可靠性。
IEEE 754 表示方法:
IEEE754 一般分為半精度浮點數、單精度浮點數、雙精度浮點數
這雙精度浮點數為例,在這個長度下會使用 1 位符號,11 位指數,52 位尾數。
- 符號:\(0\) 為正,\(1\) 為負。
- 指數:偏移量,單精度為 \(127\),雙精度為 \(1023\),存儲的指數 = 真實的指數 + 偏移量。
- 尾數:只存儲的小數部分。(因為整數部分永遠是 \(1\))。
$flag = 'flag{test}';
extract($_GET);
if (strstr($num,'1')) {
die('Out!');
}
if($num==1){
var_dump($flag);
}
這個例子大致一個情況就是,如果 num=1 則輸出 flag,但是由于使用了 strstr 函數,如果我們輸入 1 的話自然會返回 Out!,為此可以使用精度漏洞繞過去
?num=0.999999999999999999999999
比較和類型轉換漏洞
PHP 包括松散比較 == 和嚴格比較 ===。
字符串轉化成數字后會是 \(0\)。如果一個字符串要轉化成數值類型,首先對字符串進行一個判斷,如果字符串里面包括 e, ., E, 則會作為 float 來取值,否則作為 int 來取值。如果字符串起始部分為 數值 ,則采用 起始的數值 ,否則一律為 \(0\)。
PHP 弱類型比較
strcmp
strcmp(str1, str2)
如果 str1 小于 str2 返回 <0,如果 str1 大于 str2 返回 >0,如果 str1 等于 str2,則返回 0,如果 strcmp 比較出錯后,會返回 null,null 則為 \(0\)。
為了使 strcmp 比較出錯,可以傳入一個數組:?str[]。
is_numeric
is_numeric 用于檢測參數是否為數值,如果遇到這個函數,可以用上述轉換類型的特性(< PHP 8.0.0),如果傳入的是字符串,會先將字符串轉換為數值。
is_switch
方法與類型轉換差不多。
$a = "233a"; # 字符串轉換為 223
$flag = "flag{Give you FLAG}";
switch ($a) {
case 1:
echo "No Flag";
break;
case 2:
echo "No Flag";
break;
case 233:
echo $flag;
break;
default:
$a = 233;
echo "Haha...";
}
MD5()
MD5(Message-Digest Algorithm 5)是一種廣泛使用的密碼散列函數,可以生成一個128位(16字節)的哈希值,通常表示為32個字符的十六進制數。
MD5 就像一個“數字指紋生成器”——它能把任意長度的數據(文件、密碼、文字等)轉換成一個固定長度的、唯一的“指紋字符串”。
特點:
- 固定長度輸出:無論輸入多大,輸出永遠是 \(32\) 位十六進制數(\(128\) 位二進制)。
- 確定性:相同的輸入永遠產生相同的輸出。
- 快速計算:計算 MD5 哈希值非常快速。
- 雪崩效應:輸入微小變化,輸出截然不同。
函數 md5()
md5(string, var2)
計算 字符串 的 MD5 散列值,如果 var2 為真的話將返回 16 字符長度的原始二進制格式。
md5 在處理哈希字符串的時候,如果 md5 編碼后的哈希值時 \(0e\) (科學計數法)開頭的,都一律解釋為 \(0\),所以當兩個不同的值經過哈希編碼后他們的值都是以 \(0e\) 開頭的,則每個值都是 \(0\)。
常見的 MD5 以 0e 開頭的值。
數值型:
240610708 0e462097431906509019562988736854 返回:0
314282422 0e990995504821699494520356953734 返回:0
571579406 0e972379832854295224118025748221 返回:0
903251147 0e174510503823932942361353209384 返回:0
$md5 md5($md5)
0e00275209979 0e551387587965716321018342879905
0e00506035745 0e224441551631909369101555335043
0e00540451811 0e057099852684304412663796608095
0e00678205148 0e934049274119262631743072394111
0e00741250258 0e899567782965109269932883593603
0e00928251504 0e148856674729228041723861799600
0e01350016114 0e769018222125751782256460324867
0e01352028862 0e388419153010508575572061606161
0e01392313004 0e793314107039222217518920037885
0e01875552079 0e780449305367629893512581736357
0e01975903983 0e317084484960342086618161584202
0e02042356163 0e335912055437180460060141819624
0e02218562930 0e151492820470888772364059321579
0e02451355147 0e866503534356013079241759641492
0e02739970294 0e894318228115677783240047043017
0e02760920150 0e413159393756646578537635311046
0e02784726287 0e433955189140949269100965859496
0e03298616350 0e851613188370453906408258609284
0e03393034171 0e077847024281996293485700020358
字符型:
QLTHNDT 0e405967825401955372549139051580 返回:0
QNKCDZO 0e830400451993494058024219903391 返回:0
EEIZDOI 0e782601363539291779881938479162 返回:0
TUFEPMC 0e839407194569345277863905212547 返回:0
===(數組比較)
如果 MD5 比較用的 ===,這個時候就得使用數組來繞過。如果傳入一個數組的值,就會報錯,報錯后就相當于繞過 === 這個條件了。
在 PHP8.0.0 這個方法行不通了!
MD5 碰撞
目前看不太懂,在慢慢啃…………
sha1
一種哈希函數,算法強度比 MD5 強,但是仍不太安全。
sha1 的參數不能為數組,傳入數組會返回 NULL,所以先傳一個數組使得 sha1 函數報錯,接著再左右兩邊傳入不一樣的內容,兩邊條件自然 =1,相等即可繞過。
$flag = "flag{Chain!}";
$get = $_GET['get'];
$teg = $_GET['teg'];
if ($get != $teg && sha1($get) === sha1($teg)) {
#if ($get != $teg && sha1($get) == sha1($teg)) {
echo $flag;
}else{
echo 'Out!';
}
?get[]=&teg[]=1。
變量覆蓋漏洞
變量如果未被初始化,且能夠被用戶所控制,那么很可能會導致安全問題,如果傳入一個參數,并且這個參數把原有的變量值給覆蓋掉了則叫做變量覆蓋漏洞。
$$
$$: 可變變量,簡單概括就是一個可變變量獲得了一個普通變量的值,舉個例子。
$a = "A";
$$a = "B";
代碼含義:給變量 \(a\) 賦值 "A",而 $$a 就相當于 $"A",即 $"A" = "B"。
$flag = "flag{Chain!}";
foreach ($_GET as $key => $value) {
$$key = $value;
}
if ($id === "admin") {
echo $flag;
}else{
echo "Out!";
}
?id=admin, 將 id 付給 $key, admin 賦給 $value, $$key 即為 $id, 所以 $id === "admin"。
extract()
extract(array, flags, prefix)
本函數用來將變量從數組中導入到當前的符號表中。
檢查每個鍵名看是否可以作為一個合法的變量名,同時也檢查和符號表中已有的變量名的沖突。
array: 數組flags:
EXTR_OVERWRITE- 如果有沖突,覆蓋已有的變量。(默認)
EXTR_SKIP- 如果有沖突,不覆蓋已有的變量。
EXTR_PREFIX_SAME- 如果有沖突,在變量名前加上前綴 prefix。(需要 prefix 參數)prefix: 該參數規定了前綴。前綴和數組鍵名之間會自動加上一個下劃線。
parse_str()
parse_str(string $string, array &$result): void
如果 string 是通過 URL 傳入的查詢字符串,則將其解析,并將 key 設置到指定 result 數組中。如果未提供 result 數組,則會將值設置為當前作用域中的變量。
register_globals
register_globals 設置為 on 的時候,傳遞的參數會自動注冊為全局變量。
ini_set("register_globals", "On");
偽協議
后面慢慢啃……

浙公網安備 33010602011771號