PHP代碼安全雜談鵬越·學霸專區
當然PHP是世界上最好的語言之一,但是也有一些因為弱類型語言的安全性問題出現。WordPress歷史上就出現過由於PHP本身的缺陷而造成的一些安全性問題,如CVE-2014-0166 中的cookie偽造就是利用了PHP Hash比較的缺陷。 當然一般這種情況實戰中用到的不是很多,但是在CTF競賽中卻是一個值得去考察的一個知識點,特此記錄總結之。
一
精度繞過缺陷
理論
在用PHP進行浮點數的運算中,經常會出現一些和預期結果不一樣的值,這是由於浮點數的精度有限。儘管取決於系統,PHP 通常使用 雙精度格式,則由於取整而導致的最大相對誤差為 。非基本數學運算可能會給出更大誤差,並且要考慮到進行複合運算時的誤差傳遞。下面看一個有趣的例子:
以十進位能夠精確表示的有理數如 或 ,無論有多少尾數都不能被內部所使用的二進位精確表示,因此不能在不丟失一點點精度的情況下轉換為二進位的格式。這就會造成混亂的結果:例如, 通常會返回 而不是預期中的 ,因為該結果內部的表示其實是類似 。
實踐
問鼎杯2017 老眼昏花網上很多write-up感覺就像是看著答案寫write-up,個人感覺真正的write-up中應該體現自己的思考在裡面。
題目描述
題目言簡意賅,讓我們把這個值傳遞給伺服器。
考察點
PHP浮點精確度
write-up
所以第一反應是直接給參數賦值為:
然而結果如下:
有提示了,說明這個參數是對的,但是中不可以出現,這裡如果不了解php精度的話,肯定是對進行各種編碼繞過,但是這裡對編碼也進行過濾了:
所以最後一種可能就是利用PHP精度來繞過:
二
類型轉換的缺陷
理論
PHP提供了函數,用來變數判斷是否為數字。PHP弱類型語言的一個特性,當一個整形和一個其他類型行比較的時候,會先把其他類型intval數字化再比。
實踐
用於判斷是否是數字,通常配合數值判斷。
案例代碼
考察點
PHP類型轉換缺陷
write-up
分析下代碼:首先對GET方式提交的參數的值進行檢驗。通過函數來判斷是否為數字,如果為數字的話,GG。如果不是數字的話,和進行比較,的值大於的時候輸出。
乍看上去又好像不可能這裡,但是如果知道。這個特性的話就可以很好的繞過。
三
鬆散比較符的缺陷
理論
php比較相等性的運算符有兩種,一種是嚴格比較,另一種是鬆散比較。
如果比較一個數字和字元串或者比較涉及到數字內容的字元串,則字元串會被轉換成數值並且比較按照數值來進行
嚴格比較符嚴格比較符,會先判斷兩種字元串的類型是否相等,再比較。
鬆散比較符鬆散比較符,會先將字元串類型轉換成相同,再比較。
PHP 會根據變數的值,自動把變數轉換為正確的數據類型。這一點和C 和 C++ 以及 Java 之類的語言明顯不同。雖然這樣PHP方便了程序員,但是隨之而來卻會帶來一些安全性的問題。
一個簡單的例子
由於php對變數自動轉換的特性,這裡面的
所以頁面輸出的結果為:
一個深入的例子
下面結合PHP 相等性比較缺陷再解釋下會好懂一點:
與進行鬆散性質的不嚴格比較,會將轉換為數值,強制轉換,由於是字元串,轉化的結果是,所以 輸出
與進行嚴格 性質的嚴格比較,這裡的是字元串類型,和int類型的不相等,所以輸出
與進行鬆散性質的不嚴格比較,會將轉換為數值,強制轉換,由於是字元串,轉化的結果是,不等於,所以輸出
與進行鬆散性質的不嚴格比較,這裡被強制轉換為int類型的時候會從字元串的第一位開始做判斷進行轉換,這裡的第一位是,所以這裡被轉換為,所以輸出
與進行嚴格 性質的嚴格比較,字元串的第一位不是數字,所以它被強制轉換為,所以輸出
這裡比較特殊,字元串中出現了,PHP手冊介紹如下:
與相互不嚴格性質比較的時候,會將這類字元串識為科學技術法的數字,0的無論多少次方都是零,所以相等,輸出
與相互進行不嚴格性質比較的時候,本應該將這類字元串識為科學技術法的數字,但是這裡的後面跟著的是,數學中科學計數的指數不可以包含字母。所以這裡字元串中雖然是開頭,但是後面的卻不符合科學技法的規範,所以輸出是
實踐
md5繞過(Hash比較缺陷)南京郵電大學網路攻防訓練平台中一道比較經典的題,關於這道題目的WriteUp網上很多,但是真正深入分析的少之又少~~
題目描述
md5 collision源碼
考察點
簡單的PHP代碼審計
PHP弱類型的Hash比較缺陷
write-up
從源碼中可以得輸入一個a的參數的變數,a首先不等於並且a得md5值必須等於加密後的md5值。 乍一看好像不可能存在這樣的值,但是這裡加密後的md5值為 這裡是開頭的,在進行等於比較的時候,PHP把它當作科學計數法,0的無論多少次方都是零。 所以這裡利用上面的弱類型的比較的缺陷來進行解題:
字元串加密後為0exxxx的字元串(x必須是10進位數字)列表
四
sha1()md5()加密函數漏洞缺陷
理論
和對一個數組進行加密將返回 NULL
實踐
Boston Key Party CTF 2015: Prudential
題目描述
I dont think sha1 isbroken.Prove me wrong.
題目給了一個登陸框:
考察點
sha1()函數漏洞缺陷
write-up
源代碼給出如下:
分析一下核心登錄代碼如下:
類型提交了兩個欄位和,獲得flag要求的條件是:
name != password
sha1(name) == sha1(password)
這個乍看起來這是不可能的,但是這裡利用函數在處理數組的時候由於無法處理將返回可以繞過if語句的驗證,if條件成立將獲得。 構造語句如下:
?name[]=a&password[]=b
這裡符合了2個拿到flag的條件:
a不等於b
name和password由於是數組,經過sha1()函數嫁給後都返回
拿到flag:
拓展總結
經過驗證,不僅函數無法處理數組,這裡函數也有同樣的問題,在處理數組的時候,都將返回
測試代碼如下:
這裡面的核心代碼如下:
同樣利用函數無法處理數組的這個漏洞,構造get請求拿到flag:
?username[]=a&password[]=b
五
字元串處理函數漏洞缺陷
理論
函數:比較兩個字元串(區分大小寫).
用法如下:
具體的用法解釋如下:
這個函數接受到了不符合的類型,例如類型,函數將發生錯誤。但是在之前的php中,顯示了報錯的警告信息後,將 !!!! 也就是雖然報了錯,但卻判定其相等了。
函數:字元串正則匹配。
函數:查找字元串在另一字元串中第一次出現的位置,對大小寫敏感。
這2個函數都是用來處理字元串的,但是在傳入數組參數後都將返回。
實踐
Boston Key Party CTF 2015: Northeastern Univ
題目描述
Of course, a timing attack might be the answer, but Im quite sure that you can do better than that. 題目給了一個登陸框:
考察點
字元串處理函數漏洞缺陷
write-up
給出源代碼如下:
分析一下核心登錄代碼如下:
這裡使用了鬆散比較了和通過GET方式提交的的值,如果想等的話,拿到flag。這裡用的是鬆散性質的比較,再利用字元串處理數組時將會報錯,在之前的php中,顯示了報錯的警告信息後,將。所有這裡將參數指定為數組,利用函數漏洞拿到:
拓展總結
除了函數外,和函數在處理數組的時候也會異常,返回。測試代碼如下:
將參數password賦值一個數組傳遞進去:
是處理字元串的,傳入數組後返回,和 ,是不恆等(===)的,滿足第一個條件;而也是處理字元串的,傳入數組後返回L,,滿足條件,拿到flag:
理論
函數的作用就是解析字元串並註冊成變數,在註冊變數之前不會驗證當前變數是否存在,所以直接覆蓋掉已有變數。
str 輸入的字元串。
arr 如果設置了第二個變數 arr,變數將會以數組元素的形式存入到這個數組,作為替代。
實踐
測試代碼:
考察點
parse_str變數覆蓋缺陷
write-up
找到核心代碼:
因為這裡用到了函數來傳遞,if的語句的條件是拿來比較的,有因為這裡的變數a的值已經三是固定的了:
這裡其實是我博客的地址~~ 不過不重要。 整體代碼乍看起來又不可能,但是利用變數覆蓋函數的缺陷這裡可以對的變數進行重新賦值,後面的的if語句再利用本文前面提到的比較缺陷進行繞過:
參考文獻
PHP 比較運算符
PHP Float 浮點型
PHP 類型比較表
PHP 弱類型總結
PHP Hash比較存在缺陷,影響大量Web網站登錄認證、忘記密碼等關鍵業務
PHP代碼審計片段講解(入門代碼審計、CTF必備)
淺談PHP弱類型安全
NJCTF2017 線上賽 web 題解
CTF之PHP黑魔法總結
Some features of PHP in CTF
PHP浮點數運算精度的問題
php strcmp()漏洞
危險的is_numeric——PHPYun 2015-06-26 二次注入漏洞分析
【代碼審計】變數覆蓋漏洞詳解
(轉載來源:FreeBuf.COM,作者:國光)
現在關注「鵬越網路空間安全研究院」微信公眾號,在對話框中輸入「工控」、「培訓」、「CTF」 、「物聯網」、 「人工智慧」、「招聘」等關鍵字,系統自動推送相應內容。今後我們還會推出更多方便搜索和閱讀的服務,敬請期待!
長按下方二維碼關注我