最新消息:图 床

PHP trick(代碼審計關注點)

COOL IAM 373浏览 0评论

作者:Fortune_C00kie
作者博客:https://hacksec.xyz/2018/03/23/php-trick/

隨着代碼安全的普及,越來越多的開發人員知道了如何防禦sqli、xss等與語言無關的漏洞,但是對於和開發語言本身相關的一些漏洞和缺陷卻知之甚少,於是這些點也就是我們在Code audit的時候的重點關注點。本文旨在總結一些在PHP代碼中經常造成問題的點,也是我們在審計的時候的關注重點。(PS:本文也只是簡單的列出問題,至於造成問題的底層原因未做詳細解釋,有興趣的看官可以自行GOOGLE或者看看底層C代碼。知其然,且知其所以然)

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

TODO: 繼續豐富並增加各個點的實際漏洞事例

file_put_contents、copy、file_get_contents等讀取寫入操作與unlink、file_exists等刪除判斷文件函數之間對於路徑處理的差異導致的刪除繞過

例如如下代碼

<?php
$filename = __DIR__ . '/tmp/' . $user['name'];
$data = $user['info'];

file_put_contents($filename, $data);
if (file_exists($filename)) {
    unlink($filename);
}
?>

這裡引用小密圈中P牛的解讀

查看php源碼,其實我們能發現,php讀取、寫入文件,都會調用php_stream_open_wrapper_ex來打開流,而判斷文件存在、重命名、刪除文件等操作則無需打開文件流。

我們跟一跟php_stream_open_wrapper_ex就會發現,其實最後會使用tsrm_realpath函數來將filename給標準化成一個絕對路徑。而文件刪除等操作則不會,這就是二者的區別。

所以,如果我們傳入的是文件名中包含一個不存在的路徑,寫入的時候因為會處理掉“../”等相對路徑,所以不會出錯;判斷、刪除的時候因為不會處理,所以就會出現“No such file or directory”的錯誤。

於是乎linux可以通過xxxxx/../test.phptest.php/.windows可以通過test.php:test test.ph<來繞過文件刪除

此外發現還可以使用偽協議php://filter/resource=1.php在file_ge_contents、copy等中讀取文件內容,卻可以繞過文件刪除

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

extract函數從數組導入變量(如$_GET、 $_POST),將數組的鍵名作為變量的值。而parse_str函數則是從類似name=Bill&age=60的格式字符串解析變量.如果在使用第一個函數沒有設置EXTR_SKIP或者EXTR_PREFIX_SAME等處理變量衝突的參數時、第二個函數沒有使用數組接受變量時將會導致變量覆蓋的問題

intval()整數溢出、向下取整和整形判斷的問題
  • 32位系統最大的帶符號範圍為-2147483648 到 2147483647,64位最大的是 9223372036854775807,因此,在32位系統上 intval(‘1000000000000’) 會返回 2147483647

  • 此外intval(10.99999)會返回10,intval和int等取整都是’截斷’取整,並不是四捨五入

  • intval函數進去取整時,是直到遇上數字或者正負號才開始進行轉換,之後在遇到非數字或者結束符號(/0)時結束轉換

浮點數精度問題導致的大小比較問題

當小數小於10^-16后,PHP對於小數就大小不分了

var_dump(1.000000000000000 == 1) >> TRUE

var_dump(1.0000000000000001 == 1) >> TRUE

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

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

strcmp()數組比較繞過

int strcmp ( string str2 )

參數 str1第一個字符串。str2第二個字符串。如果 str1 小於 str2 返回 < 0;

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

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

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

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

弱類型==比較繞過

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

md5(‘240610708’); // 0e462097431906509019562988736854

md5(‘QNKCDZO’); // 0e830400451993494058024219903391

md5(‘240610708’) == md5(‘QNKCDZO’)

md5(‘aabg7XSs’) == md5(‘aabC9RqS’)

sha1(‘aaroZmOk’) == sha1(‘aaK1STfY’)

sha1(‘aaO8zKZF’) == sha1(‘aa3OFF9m’)
‘0010e2’ == ‘1e3’

‘0x1234Ab’ == ‘1193131‘

‘0xABCdef’ == ‘ 0xABCdef’
當轉換為boolean時,以下只被認為是FALSE:FALSE、0、0.0、“”、“0”、array()、NULL
PHP 7 以前的版本里,如果向八進制數傳遞了一個非法數字(即 8 或 9),則後面其餘數字會被忽略。var_dump(0123)=var_dump(01239)=83

PHP 7 以後,會產生 Parse Error。
字符串轉換為數值時,若字符串開頭有數字,則轉為數字並省略後面的非數字字符。若一開頭沒有數字則轉換為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

‘abc’ == 0

‘123a’ == 123

‘0x01’ == 1

‘0e123456789’ == ‘0e987654321’

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

NULL == false == 0» true == 1
eregi()匹配繞過

eregi()默認接收字符串參數,如果傳入數組,函數會報錯並返回NULL。同時還可以%00 截斷進行繞過

PHP變量名不能帶有點[.] 和空格,否則在會被轉化為下劃線[_]
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()函數默認進行鬆散比較(進行類型轉換)
in_arrary(“1asd”,arrart(1,2,3,4))    => true
in_arrary(“1asd”,arrart(1,2,3,4),TRUE)    => false   //(需要設置strict參數為true才會進行嚴格比較,進行類型檢測)
htmlspecialchars()函數默認只轉義雙引號不轉義單引號,如果都轉義的話需要添加上參數ENT_QUOTES
php4、php<5.2.1中,變量的key值不受magic_quotes_gpc影響
sprintf()格式化漏洞(可以吃掉轉義后的單引號)

printf()和sprintf()函數中可以通過使用%接一個字符來進行padding功能

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

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

转载请注明:IAMCOOL » PHP trick(代碼審計關注點)

0 0 vote
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x