一道ISCC題引申的PHP正則複習
iscc中的一道web題“試試看”,描述為隨意開火
起初看url,以為是一道常規的檔案包含題,後面試了很多方法都出不來
最後受到其他師傅的啟發才得到payload
這裡有兩種payload都可以
http://118.190.152.202:8006/show.php?img=php://filter/resource=1.jpg/resource=show.php
http://118.190.152.202:8006/show.php?img=php://filter/resource=show.php|jpg
對這道題目的匹配規則很感興趣,在本地搭建進行仔細分析,也是對正則以及php函式的複習
在審計程式碼之前,先複習一下php的preg_match、strpos和file_get_contents等函式
1、preg_match函式用於正則匹配,第一個引數是要匹配的正則規則,第二個引數是被匹配的字串。後面的可選引數中,$matches是一個陣列,用於返回匹配的字串結果
# preg_match
(PHP 4, PHP 5, PHP 7)
preg_match — 執行匹配正規表示式
### 說明
int **preg_match** ( string `$pattern` , string `$subject` [, array `&$matches` [, int `$flags` = 0 [, int`$offset` = 0 ]]] )
搜尋`subject`與`pattern`給定的正規表示式的一個匹配.
2、strpos函式用於字串查詢,如果找到則返回位置,位置從0開始計算。如果沒有找到則返回false
# strpos
(PHP 4, PHP 5, PHP 7)
strpos — 查詢字串首次出現的位置
### 說明
int **strpos** ( string `$haystack` , [mixed]`$needle` [, int `$offset` = 0 ] )
返回 `needle` 在 `haystack` 中首次出現的數字位置。
如果提供了引數matches,它將被填充為搜尋結果。 $matches[0]將包含完整模式匹配到的文字, $matches[1] 將包含第一個捕獲子組匹配到的文字,以此類推。
3、file_get_contents函式用於文字讀取,可以獲得檔案內容,它更強大的地方在於可以通過http協議抓取內容
# file_get_contents
(PHP 4 >= 4.3.0, PHP 5, PHP 7)
file_get_contents — 將整個檔案讀入一個字串
### 說明
string **file_get_contents** ( string `$filename` [, bool `$use_include_path` = false [, resource`$context` [, int `$offset` = -1 [, int `$maxlen` ]]]] )
和 file()一樣,只除了 **file_get_contents()** 把檔案讀入一個字串。將在引數 `offset` 所指定的位置開始讀取長度為`maxlen` 的內容。如果失敗,**file_get_contents()** 將返回 **`FALSE`**。
**file_get_contents()** 函式是用來將檔案的內容讀入到一個字串中的首選方法。如果作業系統支援還會使用記憶體對映技術來增強效能。
> **Note**:
>
> 如果要開啟有特殊字元的 URL (比如說有空格),就需要使用 [urlencode()]進行 URL 編碼。
本題中,經過註釋和改造後的主要程式碼如下
show.php
<?php
error_reporting(0);
ini_set(`display_errors`,`Off`);
include(`config.php`);
$img = $_GET[`img`];
if(isset($img) && !empty($img))
{
if(strpos($img,`jpg`) !== false)
{
// strpos拿`resource=`到$img中查詢,如果匹配到了則前者為真;注意這裡是全等
// 如果沒有匹配到`/resource=.*jpg/i`正則模式則後者為真;
if(strpos($img,`resource=`) !== false && preg_match(`/resource=.*jpg/i`,$img) === 0)
{
//滿足上述兩種情況,返回找不到檔案
die(`File not found.`);
}
// 再次進行正則匹配,如果以php://filter開頭,並且字串中存在resource=加上任意不包含|的字串
// 對$img進行左右兩邊空白或者預定符號的刪除,最後匹配結果存到$matches陣列
preg_match(`/^php://filter.*resource=([^|]*)/i`,trim($img),$matches);
// $matches[0]將包含完整模式匹配到的文字, $matches[1] 將包含第一個捕獲子組匹配到的文字,以此類推。
var_dump($matches);
if(isset($matches[1]))
{
$img = $matches[1];
}
echo "<br>";
echo $img;
header(`Content-Type: image/jpeg`);
// 關鍵函式get_contents,去獲得檔案內容
$data = get_contents($img);
echo $data;
}
else
{
die(`File not found.`);
}
}
else
{
?>
<img src="1.jpg">
<?php
}
?>
config.php
<?php
// 關鍵函式get_contents,去獲得檔案內容
function get_contents($img)
{
// 如果$img中存在`jpg`,返回$img檔案內容
if(strpos($img,`jpg`) !== false)
{
return file_get_contents($img);
}
// 否則返回$img的同時,設定返回頭為hmtl
else
{
header(`Content-Type: text/html`);
return file_get_contents($img);
}
}
?>
這裡通過實際payload在執行中的流程,對關鍵地方進行輸出,方便分析和檢視結果
0x01
首先分析show.php?img=php://filter/resource=config.php|jpg
邏輯中的第一個涉及preg_match的if語句中,只有在傳入的$img中匹配到”resource=”的同時,preg_match中$img匹配規則”/resource=.*jpg/i”匹配不到的情況下成立
在這裡不會對payload形成影響
關鍵點在接下來的正則匹配
// 再次進行正則匹配,如果以php://filter開頭,並且字串中存在resource=加上任意不包含|的字串
// 對$img進行左右兩邊空白或者預定符號的刪除,最後匹配結果存到$matches陣列
preg_match(`/^php://filter.*resource=([^|]*)/i`,trim($img),$matches);
// $matches[0]將包含完整模式匹配到的文字, $matches[1] 將包含第一個捕獲子組匹配到的文字,以此類推。
var_dump($matches);
if(isset($matches[1]))
{
$img = $matches[1];
}
echo "<br>";
echo $img;
// header(`Content-Type: image/jpeg`);
// 關鍵函式get_contents,去獲得檔案內容
$data = get_contents($img);
echo $data;
可以看到,匹配規則是要求以php://filter開頭,並且字串中存在resource=加上任意不包含|的字串
([^|]*)代表的意思就是排除|以外的字元,允許重複零次或多次,圓括號包裹則表示這是一個匹配的文字子組
匹配的結果儲存在$matches陣列中,並且$img會被覆蓋為$matches的第2個元素
這裡的關鍵在於$matches的第二個元素內容,第二個元素內容是圓括號包裹的([^|]*)子組的內容
經過正則後,$img已經被覆蓋,內容為config.php
在config.php中,將通過函式file_get_contents($img)
去獲取指定檔案內容並且返回
// 如果$img中存在`jpg`,返回$img檔案內容
if(strpos($img,`jpg`) !== false)
{
return file_get_contents($img);
}
// 否則返回$img的同時,設定返回頭為hmtl
else
{
header(`Content-Type: text/html`);
return file_get_contents($img);
}
0x02
接下來分析show.php?img=php://filter/resource=1.jpg/resource=config.php
其他流程和上面的一樣,只要字串中包含jpg就可以,關鍵在於
preg_match(`/^php://filter.*resource=([^|]*)/i`,trim($img),$matches);
payload進去之後的匹配結果將是後面一個resource=config.php,而不是resource=1.jpg,因此拿到的$matches的第二個元素也是config.php!
相關文章
- PHP 正則匹配中文PHP
- PHP 用正則分章節PHP
- 關於轉義符 在php正則中的匹配問題PHP
- PHP 正則提取字串中的美元PHP字串
- JS 正則學習JS
- 正則問題整理
- php正則匹配所有違規字元PHP字元
- Java處理正則匹配卡死(正則回溯問題)Java
- 關於PHP字串的一道面試題PHP字串面試題
- ISCC 2024 練武題 misc趣題記錄
- 正則學習小記
- Python學習之正則Python
- 深度學習——正則化深度學習
- PHP 正則獲取域名(一級域名)PHP
- 面試中會遇到的正則題面試
- 如何學正則(告別複製貼上)
- 正規表示式複習
- php 正則如何匹配手機號碼呢?PHP
- JavaScript正則學習筆記JavaScript筆記
- 學習筆記:深度學習中的正則化筆記深度學習
- js表情正則 手機正則 郵箱正則JS
- 機器學習之簡化正則化:L2 正則化機器學習
- 機器學習之稀疏性正則化:L1 正則化機器學習
- 「機器學習速成」稀疏性正則化:L1正則化機器學習
- 「機器學習速成」正則化:降低模型的複雜度以減少過擬合機器學習模型複雜度
- ISCC 2024 部分WP
- 正則
- PHP程式碼審計05之正則使用不當PHP
- 一道前端面試題引發的學習前端面試題
- 正規表示式學習筆記(1)-認識正則筆記
- Python中的正則Python
- 最常用的正則
- NOIP 複習題
- 【機器學習基礎】正則化及多分類問題總結機器學習
- 前端如何理解正則-由淺入深的學習前端
- 分享一個非常全的php正則驗證車牌格式的函式PHP函式
- 【機器學習】--魯棒性調優之L1正則,L2正則機器學習
- 從 VNCTF2024 的一道題學習QEMU EscapeVNCTF2