PHP花式繞過大全

fly夏天summer 發佈 2024-04-02T16:25:54.694000+00:00

做了這麼長的時間的ctf,現在總結一下自己做過的題,記錄一下各種可能會存在繞過的php函數,持續更新。

做了這麼長的時間的ctf,現在總結一下自己做過的題,記錄一下各種可能會存在繞過的php函數,持續更新。



1.preg_replace ($pattern , $replacement , $subject )

其中 $pattern為正則表達式

$replacement為替換字符串

$subject 為要搜索替換的目標字符串或字符串數組

這個函數存在一些奇異的地方,正則表達式$pattern以/e結尾時$replacement的值會被作為php函數執行。

例如執行 preg_replace (『/test/e』 , "phpinfo();" , "test" )

「test」會被替換為phpinfo();並執行。


2.MD5加密繞過


2.1 MD5弱比較繞過


php中有一個提供MD5加密的函數md5()通常被用來進行密碼驗證之類的功能。


在ctf中常見如下的驗證方式:


if( a == b && md5(a) == md5(b) )


方法一:


這兒md5(a)/md5(b)兩數如果滿足科學計數法的形式的話,php會將其當作科學計數法所得的數字來進行比較。例如:


md5(QNKCDZO)
0e830400451993494058024219903391


可以看見QNKCDZO的md5值是0e開頭滿足科學計數法的表示形式,而0e的值始終為0


因此,只要字符串經md5後滿足科學計數法的0e開頭,他們在==比較時就會被認定為相等。(只對==比較有效,不適用於===)


以下給出一些滿足該要求的md5數


QNKCDZO
0e830400451993494058024219903391
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675

方法二 :

md5()函數無法處理數組,如果傳入的為數組,會返回NULL,所以兩個數組經過加密後得到的都是NULL,也就是相等的。

也就是說a[]=1,2 b[]=2,3 該驗證依然可以繞過。

2.2 MD5強碰撞


if((string)$_POST['param1']!==(string)$_POST['param2'] && md5($_POST['param1'])===md5($_POST['param2'])){
        die("success!);
}


Param1=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2


2.3 雙MD5碰撞繞過


$a != $b && md5($a) == md5(md5($b)


一些例子


MD5大全:

CbDLytmyGm2xQyaLNhWn

md5(CbDLytmyGm2xQyaLNhWn) => 0ec20b7c66cafbcc7d8e8481f0653d18

md5(md5(CbDLytmyGm2xQyaLNhWn)) => 0e3a5f2a80db371d4610b8f940d296af

770hQgrBOjrcqftrlaZk

md5(770hQgrBOjrcqftrlaZk) => 0e689b4f703bdc753be7e27b45cb3625

md5(md5(770hQgrBOjrcqftrlaZk)) => 0e2756da68ef740fd8f5a5c26cc45064

7r4lGXCH2Ksu2JNT3BYM

md5(7r4lGXCH2Ksu2JNT3BYM) => 0e269ab12da27d79a6626d91f34ae849

md5(md5(7r4lGXCH2Ksu2JNT3BYM)) => 0e48d320b2a97ab295f5c4694759889f


碰撞腳本


# -*- coding: utf-8 -*-
import multiprocessing
import hashlib
import random
import string
import sys
CHARS = string.letters + string.digits
def cmp_md5(substr, stop_event, str_len,. start=0, size=20):
    global CHARS
    while not stop_event.is_set():
        rnds = ''.join(random.choice(CHARS) for _ in range(size))
        md5 = hashlib.md5(rnds)
        value = md5.hexdigest()
        if value[start: start+str_len] == substr:
            print rnds
            stop_event.set()
            '''
            #碰撞雙md5
            md5 = hashlib.md5(value)
            if md5.hexdigest()[start: start+str_len] == substr:
                print rnds+ "=>" + value+"=>"+ md5.hexdigest()  + "\n"
                stop_event.set()
            '''

if __name__ == '__main__':
    substr = sys.argv[1].strip()
    start_pos = int(sys.argv[2]) if len(sys.argv) > 1 else 0
    str_len = len(substr)
    cpus = multiprocessing.cpu_count()
    stop_event = multiprocessing.Event()
    processes = [multiprocessing.Process(target=cmp_md5, args=(substr,
                                         stop_event, str_len, start_pos))
                 for i in range(cpus)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()


上面腳本注釋部分是雙MD5碰撞,取消注釋然後注釋掉16行即可。


使用方法:python md5Crack.py "你要碰撞的字符串" 字符串的起始位置


例如:python md5Crack.py 「0e" 0


將產生MD5值為0e開頭的字符串。


註:這個腳本我本地嘗試好像有問題,具體問題有時間研究一下再補上。


3.MD4 繞過(來自強網杯2020)


$_GET["hash1"] != hash("md4", $_GET["hash1"])


例子 0e251288019


md4計算後為
0e874956163641961271069404332409


參考網上的例子改了一個簡易的python爆破腳本,就是效率真的低到離譜


y1ng神還有高級腳本,感興趣的可以自己去看看2020第四屆「強網杯」全國網絡安全挑戰賽初賽Writeup – 穎奇L'Amore
https://www.gem-love.com/ctf/2576.HTML#Funhash


沒研究透的我就不貼了。


import hashlib
for i in range(0,10**40):
    i='0e'+str(i)
    md4=hashlib.new('md4', i.encode()).hexdigest()
    if md4[:2]=='0e' and md4[2:].isdigit():
        print('num:{},md4:{} '.format(i,md4))
        break
#需要在python3環境下運行,不然無法執行 


4.strip_tags()


這個函數用於去除字符串中的 html 標籤,正常來說確實沒啥問題。


但是卻在ctf中一些繞過中存在。(出自roarctf2019 simple_upload)


thinkphp原生代碼中的upload()上傳功能,會對上傳的文件名執行該函數。


利用該方法可以進行前端繞過。


當php進行上傳文件後綴驗證,過濾.php時。


一般情況下諸如 1.php是無法上傳上去的,但是此處可以通過 構造文件名為 1.<a>php繞過該驗證。


文件上傳後不滿足.php繞過過濾,但是在tp的原生上傳函數被調用是<a>被去除,文件就會被以php格式上傳。


註:此處的html可以為任意html標籤


5.assert()


這個函數是php的斷言函數,用來判斷一個表達式是否成立。返回true or false。


註:assert執行的字符串包含的php語句如果有多條,只會執行第一條。


該表達式會被當做php函數來執行,相當於eval()


在ctf中該函數也有一定的可利用性,如xctf中的一題


assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");


$file為用戶傳入的字符串,這裡構造file=').phpinfo();//


此時語句變成了assert("strpos('').phpinfo();// ===false" ) or die (" ")


相當於 assert("strpos('').phpinfo();" )


phpinfo()就被注入進去並執行了。


註:這裡用到了php的一個特性,那就是 .連接符 ,


讀者可以自行嘗試assert("ehco(123);phpinfo();")和assert("ehco(123).phpinfo();")運行起來的區別。


6.反序列化相關知識點


1.__toString()


觸發條件時對象被當作字符串調用時就會執行。


需要指出的是在 PHP 5.2.0 之前,__toString() 方法只有在直接使用於 echo 或 print 時才能生效。PHP 5.2.0 之後,則可以在任何字符串環境生效(例如通過 printf(),使用 %s 修飾符),但不能用於非字符串環境(如使用 %d 修飾符)。自 PHP 5.2.0 起,如果將一個未定義 __toString() 方法的對象轉換為字符串,會產生 E_RECOVERABLE_ERROR 級別的錯誤。


比如stristr函數。(來自強網杯的怨念)


2.__wakeup繞過


該函數會在反序列化時執行。當成員屬性數目大於實際數目時可繞過wakeup方法(CVE-2016-7124)


例如:一個對象序列化結果如下


O:6:"jungle":1:{s:4:"name";s:1:"1";}


如果想要繞過類中的__wakeup函數,只需要將jungle數量對應的1改成2既可。


註:這裡的字符串數字比如O:6,寫成O:+6也是可以,利用這個可以繞過一些過濾。


3.S和s的區別


依然已上文的序列化字符串舉例


O:6:"jungle":1:{s:4:"name";s:1:"1";}


這裡的s表示的是屬性的內容是字符串,因為這裡的變量屬性是public,如果是protected,則需要在屬性名前加chr(0)*chr(0)


也就是s:7:"chr(0)*chr(0)name",這個是無法打出來的。


通常情況下我們可以這樣表示:s:7:"%00*%00name",用%00來代替這個chr(0)字符


如果用S的話,就可以這樣寫:S:7:"\00*\00name" ,簡單來說就是在S的模式下,\+字符的ascii碼的16進位表示就可以被識別為字符,這裡的s:7:"%00*%00name" 甚至可以直接表示成 S:7:"\00*\00\6e\61\6d\65" ,通過這種方法可以繞過很多過濾(來自強網杯的怨念),具體原理可以參考
https://www.neatstudio.com/show-161-1.shtml


4.反序列化逃逸


這個好複雜啊,不想寫懶狗選擇放棄,大家可以百度安恆月賽反序列化逃逸來找例子參考。


https://www.cnblogs.com/BOHB-yunying/p/12774297.html


這個師傅就寫的很好,可以參考一下。


7.弱比較問題


7.1 數字與字符串的比較


字符串與數字比較的時候,會自動提取字符串中的數字。


例如


1=="1" 可以通過


1=="1a" 可以通過


註:這裡從字符串中提取數字的操作是從首位開始,如果首位不是數字就不會提取數字,1=="aa1" 不可以通過。


8.PHP標籤的幾種寫法


1. <?php ?>
常規寫法
2. <? ?>


註:


  • 利用短標籤寫法可以繞過一些對php字符的過濾
  • Windows環境中短標籤默認是打開的,Linux下 默認是關閉的。
  • 控制參數: php支持短標籤,需要我們把short_open_tag 設置為On.


3. <% %>


註:需要配置php.ini文件。在配置文件中找到asp_tags=off ,將off改為on。改動配置文件後需要重啟apache。
4. <script language=」php」> </script>


9.php中的命令執行函數總結


10.disabled_function繞過


11.PHP下的模板注入TWIG


如果目標網站沒有對模板進行過濾,即可通過一下方法執行命令。


{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("shellcode")}};


12.PHP偽協議


1.filter協議 ,利用該協議可以讀取文件


php://filter/resource=1.php  //該情況下php代碼會被執行
php://filter/read=convert.base64-encode/resource=1.php //通過轉義可以避免被執行,直接讀取源碼
php://filter/read=string.rot13/resource=1.php


有幾種常見的編碼轉換參數


  1. string.rot13
  2. string.toupper
  3. string.tolower
  4. string.strip_tags //去除 HTML 、 PHP 標記 、空字符,php標籤里所有東西都會被去除,html只有標籤會被去除,裡面的文字不會刪除。
  5. convert.base64-encode
  6. convert.base64-decode
  7. zlib.deflate //壓縮
  8. zlib.inflate //解壓

註:該協議可以嵌套使用,php://filter/resource=test/../1.php或者php://filter/resource=test/1.php,test文件夾不存在的情況下這兩種寫法下仍然可以讀取1.php文件內容。


2.file協議,該文件也是利用來直接讀取文件

file:/etc/passwd


13.PHP變量覆蓋漏洞

PHP<5.4.0版本下,可能存在該漏洞。

參見大佬的文章,寫的很好

PHP變量覆蓋漏洞小結 [ Mi1k7ea ]
https://www.mi1k7ea.com/2019/06/20/PHP%E5%8F%98%E9%87%8F%E8%A6%86%E7%9B%96%E6%BC%8F%E6%B4%9E/


暫時就寫到這兒如果後續還有其他說話,會繼續更下來,以後如果有時間會寫一個php一些偽協議的總結。

關鍵字: