溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

PHP代碼審計(jì)要點(diǎn)是什么

發(fā)布時(shí)間:2021-07-07 16:34:20 來源:億速云 閱讀:208 作者:chen 欄目:編程語言

本篇內(nèi)容主要講解“PHP代碼審計(jì)要點(diǎn)是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“PHP代碼審計(jì)要點(diǎn)是什么”吧!

前言

隨著代碼安全的普及,越來越多的開發(fā)人員知道了如何防御sqli、xss等與語言無關(guān)的漏洞,但是對于和開發(fā)語言本身相關(guān)的一些漏洞和缺陷卻知之甚少,于是這些點(diǎn)也就是我們在Code audit的時(shí)候的重點(diǎn)關(guān)注點(diǎn)。本文旨在總結(jié)一些在PHP代碼中經(jīng)常造成問題的點(diǎn),也是我們在審計(jì)的時(shí)候的關(guān)注重點(diǎn)。(PS:本文也只是簡單的列出問題,至于造成問題的底層原因未做詳細(xì)解釋)

本文若有寫錯的地方,還請各位大佬斧正:

1、代碼審計(jì)定義

代碼審計(jì) 是指對源代碼進(jìn)行檢查,尋找代碼中的bug,這里主要尋到可導(dǎo)致安全問題的bug。
這是一項(xiàng)需要多方面技能的技術(shù),包括對編程的掌握(能看懂代碼的邏輯)、漏洞形成原理的理解、系統(tǒng)和中間件等的熟悉。

2、代碼審計(jì)思路

1)逆向追蹤
檢查敏感函數(shù)的參數(shù),然后回溯變量,判斷變量是否可控并且沒有經(jīng)過嚴(yán)格過濾。
2)正向追蹤
先找出哪些文件在接受外部傳輸?shù)暮瘮?shù),然后跟蹤變量傳遞的過程,觀察是否有變量傳入到高危函數(shù)里邊,或者傳遞過程中是否有代碼邏輯漏洞。這種正向追蹤的方式,比逆向追蹤挖掘得更全。
3)經(jīng)驗(yàn)判斷直接挖掘功能點(diǎn)漏洞
根據(jù)自身的經(jīng)驗(yàn)判斷該類應(yīng)用通常在哪些功能中會出現(xiàn)漏洞,直接全篇閱讀該功能代碼。

3、PHP代碼審計(jì)需要掌握好以下(其他語言類似)

1)PHP編程語言的特性和基礎(chǔ)
2)Web前端編程基礎(chǔ)
3)漏洞形成原理
4)代碼審計(jì)思路
5)不同系統(tǒng)、中間件之間的特性差異。

漏洞實(shí)例

TODO: 繼續(xù)豐富并增加各個(gè)點(diǎn)的實(shí)際漏洞事例
file_put_contents、copy、file_get_contents等讀取寫入操作與unlink、file_exists等刪除判斷文件函數(shù)之間對于路徑處理的差異導(dǎo)致的刪除繞過

extract()、parse_str() 等變量覆蓋

extract函數(shù)從數(shù)組導(dǎo)入變量(如$_GET、 $_POST),將數(shù)組的鍵名作為變量的值。而parse_str函數(shù)則是從類似name=Bill&age=60的格式字符串解析變量.如果在使用第一個(gè)函數(shù)沒有設(shè)置EXTR_SKIP或者EXTR_PREFIX_SAME等處理變量沖突的參數(shù)時(shí)、第二個(gè)函數(shù)沒有使用數(shù)組接受變量時(shí)將會導(dǎo)致變量覆蓋的問題
intval()整數(shù)溢出、向下取整和整形判斷的問題

32位系統(tǒng)最大的帶符號范圍為-2147483648 到 2147483647,64位最大的是 9223372036854775807,因此,在32位系統(tǒng)上 intval(‘1000000000000’) 會返回 2147483647此外intval(10.99999)會返回10,intval和int等取整都是’截?cái)唷≌⒉皇撬纳嵛迦雐ntval函數(shù)進(jìn)去取整時(shí),是直到遇上數(shù)字或者正負(fù)號才開始進(jìn)行轉(zhuǎn)換,之后在遇到非數(shù)字或者結(jié)束符號(\0)時(shí)結(jié)束轉(zhuǎn)換

浮點(diǎn)數(shù)精度問題導(dǎo)致的大小比較問題

當(dāng)小數(shù)小于10^-16后,PHP對于小數(shù)就大小不分了

var_dump(1.000000000000000 == 1) >> TRUE

var_dump(1.0000000000000001 == 1) >> TRUE
is_numeric()與intval()特性差異

is_numeric函數(shù)在判斷是否是數(shù)字時(shí)會忽略字符串開頭的’ ‘、’\t’、’\n’、’\r’、’\v’、’\f’。而’.’可以出現(xiàn)在任意位置,E、e能出現(xiàn)在參數(shù)中間,仍可以被判斷為數(shù)字。也就是說is_numeric(“\r\n\t 0.1e2”) >> TRUE

intval()函數(shù)會忽略’’ ‘\n’、’\r’、’\t’、’\v’、’\0’ ,也就是說intval(“\r\n\t 12”) >> 12

strcmp()數(shù)組比較繞過

int strcmp ( string $ str1 , string $str2 )

參數(shù) str1第一個(gè)字符串。str2第二個(gè)字符串。如果 str1 小于 str2 返回 < 0;

如果 str1 大于 str2 返回 > 0;如果兩者相等,返回 0。

但是如果傳入的兩個(gè)變量是數(shù)組的話,函數(shù)會報(bào)錯返回NULL,如果只是用strcmp()==0來判斷的話就可以繞過

sha1()、md5() 函數(shù)傳入數(shù)組比較繞過

sha1() MD5()函數(shù)默認(rèn)接收的參數(shù)是字符串類型,但是如果如果傳入的參數(shù)是數(shù)組的話,函數(shù)就會報(bào)錯返回NULL。類似sha1($_GET[‘name’]) === sha1($_GET[‘password’])的比較就可以繞過
弱類型==比較繞過

這方面問題普及的很多,不作過多的解釋

md5(‘240610708’); // 0e462097431906509019562988736854md5(‘QNKCDZO’); // 0e830400451993494058024219903391md5(‘240610708’) == md5(‘QNKCDZO’)md5(‘a(chǎn)abg7XSs’) == md5(‘a(chǎn)abC9RqS’)sha1(‘a(chǎn)aroZmOk’) == sha1(‘a(chǎn)aK1STfY’)sha1(‘a(chǎn)aO8zKZF’) == sha1(‘a(chǎn)a3OFF9m’)‘0010e2’ == ‘1e3’

‘0x1234Ab’ == ‘1193131‘

‘0xABCdef’ == ‘ 0xABCdef’

當(dāng)轉(zhuǎn)換為boolean時(shí),以下只被認(rèn)為是FALSE:FALSE、0、0.0、“”、“0”、array()、NULL

PHP 7 以前的版本里,如果向八進(jìn)制數(shù)傳遞了一個(gè)非法數(shù)字(即 8 或 9),則后面其余數(shù)字會被忽略。var_dump(0123)=var_dump(01239)=83

PHP 7 以后,會產(chǎn)生 Parse Error。

字符串轉(zhuǎn)換為數(shù)值時(shí),若字符串開頭有數(shù)字,則轉(zhuǎn)為數(shù)字并省略后面的非數(shù)字字符。若一開頭沒有數(shù)字則轉(zhuǎn)換為0

\$foo = 1 + “bob-1.3e3”; // $foo is integer (1)

\$foo = 1 + “bob3”; // $foo is integer (1)

\$foo = 1 + “10 Small Pigs”; // $foo is integer (11)

‘’ == 0 == false‘123’ == 123

‘a(chǎn)bc’ == 0

‘123a’ == 123

‘0x01’ == 1

‘0e123456789’ == ‘0e987654321’

[false] == [0] == [NULL] == [‘’]

NULL == false == 0? true ==1

eregi()匹配繞過

eregi()默認(rèn)接收字符串參數(shù),如果傳入數(shù)組,函數(shù)會報(bào)錯并返回NULL。同時(shí)還可以%00 截?cái)噙M(jìn)行繞過
PHP變量名不能帶有點(diǎn)[.] 和空格,否則在會被轉(zhuǎn)化為下劃線[_]

parse_str("na.me=admin&pass wd=123",$test);
var_dump($test); 

array(2) {
  ["na_me"]=>  string(5) "admin"
  ["pass_wd"]=>  string(3) "123"

in_arrary()函數(shù)默認(rèn)進(jìn)行松散比較(進(jìn)行類型轉(zhuǎn)換)

in_arrary(“1asd”,arrart(1,2,3,4))    => truein_arrary(“1asd”,arrart(1,2,3,4),TRUE)    => false   \\(需要設(shè)置strict參數(shù)為true才會進(jìn)行嚴(yán)格比較,進(jìn)行類型檢測)htmlspecialchars()函數(shù)默認(rèn)只轉(zhuǎn)義雙引號不轉(zhuǎn)義單引號,如果都轉(zhuǎn)義的話需要添加上參數(shù)ENT_QUOTES
在php4、php<5.2.1中,變量的key值不受magic_quotes_gpc影響sprintf()格式化漏洞(可以吃掉轉(zhuǎn)義后的單引號)

printf()和sprintf()函數(shù)中可以通過使用%接一個(gè)字符來進(jìn)行padding功能

例如%10s 字符串會默認(rèn)在左側(cè)填充空格至長度為10,還可以 %010s 會使用字符0進(jìn)行填充,但是如果我們想要使用別的字符進(jìn)行填充,需要使用 ‘ 單引號進(jìn)行標(biāo)識,例如 %’#10s 這個(gè)就是使用#進(jìn)行填充(百分號不僅會吃掉’單引號,還會吃掉\ 斜杠)

同時(shí)sprintf()可以使用指定參數(shù)位置的寫法

%后面的數(shù)字代表第幾個(gè)參數(shù),$后代表格式化類型

于是當(dāng)我們輸入的特殊字符被放到引號中進(jìn)行轉(zhuǎn)義時(shí),但是又使用了sprintf函數(shù)進(jìn)行拼接時(shí)

例如%1$’%s’ 中的 ‘%被當(dāng)成使用%進(jìn)行padding,導(dǎo)致后一個(gè)’逃逸了

還有一種情況就是’被轉(zhuǎn)義成了\’,例如輸入%’ and 1=1#進(jìn)入,存在SQL過濾,’被轉(zhuǎn)成了\’

于是sql語句變成了 select * from user where username = ‘%\’ and 1=1#’;

如果這個(gè)語句被使用sprintf函數(shù)進(jìn)行了拼接,%后的\被吃掉了,導(dǎo)致了’逃逸

<?php$sql = "select * from user where username = '%\' and 1=1#';";$args = "admin";echo sprintf( $sql, $args ) ;//result: select * from user where username = '' and 1=1#'?>

不過這樣容易遇到 PHP Warning: sprintf(): Too few arguments的報(bào)錯

這個(gè)時(shí)候我們可以使用%1$來吃掉轉(zhuǎn)移添加的\

<?php$sql = "select * from user where username = '%1$\' and 1=1#' and password='%s';";$args = "admin";echo sprintf( $sql, $args) ;//result: select * from user where username = '' and 1=1#' and password='admin';?>

php中 = 賦值運(yùn)算的優(yōu)先級高于and

$c = is_numeric($a) and is_numeric($b) 程序本意是要a、b都為數(shù)字才會繼續(xù),但是當(dāng)$a為數(shù)字時(shí),會先賦值給$c,所以可能導(dǎo)致$b繞過檢測
parse_url與libcurl對與url的解析差異可能導(dǎo)致ssrf

當(dāng)url中有多個(gè)@符號時(shí),parse_url中獲取的host是最后一個(gè)@符號后面的host,而libcurl則是獲取的第一個(gè)@符號之后的。因此當(dāng)代碼對http://user@eval.com:80@baidu.com 進(jìn)行解析時(shí),PHP獲取的host是baidu.com是允許訪問的域名,而最后調(diào)用libcurl進(jìn)行請求時(shí)則是請求的eval.com域名,可以造成ssrf繞過
此外對于https://evil@baidu.com這樣的域名進(jìn)行解析時(shí),php獲取的host是evil@baidu.com,但是libcurl獲取的host卻是evil.com

url標(biāo)準(zhǔn)的靈活性導(dǎo)致繞過filter_var與parse_url進(jìn)行ssrf

filter_var()函數(shù)對于http://evil.com;google.com 會返回false也就是認(rèn)為url格式錯誤,但是對于0://evil.com:80;google.com:80/ 、0://evil.com:80,google.com:80/、0://evil.com:80\google.com:80/卻返回true。
通過file_get_contents獲取網(wǎng)頁內(nèi)容并返回到客戶端有可能造成xss

到此,相信大家對“PHP代碼審計(jì)要點(diǎn)是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI