在Moctf中看到一道題目:php
<?php show_source(__FILE__); $c="<?php exit;?>"; @$c.=$_POST['c']; @$filename=$_POST['file']; if(!isset($filename)) { file_put_contents('tmp.php', ''); } @file_put_contents($filename, $c); include('tmp.php'); ?>
這裏簡單分析下題目,並記錄下解題過程。html
咱們來看第二行的<?php exit;?>,這句話在開頭增長了exit過程,致使即便咱們成功寫入一句話,也執行不了(這個過程在實戰中十分常見,一般出如今緩存、配置文件等等地方,不容許用戶直接訪問的文件,都會被加上if(!defined(xxx))exit;之類的限制)。在往下看,咱們要post一個c與file兩個變量,而c不用說就是用來繞過exit並執行命令的。而下面的file_put_contents函數的含義爲能夠將一個字符串寫入文件。因此咱們簡單分析獲得,咱們應該輸入一個c用來繞過exit,並讓c中的內容寫入filename所表明的變量內容裏。緩存
又由於這裏文件包含了tmp.php,因此咱們很容易想到filename應該與tmp.php相關。函數
也就是說,這道題目的關鍵點在於咱們如何繞過這句話。post
這裏引入一篇blog編碼
https://www.leavesongs.com/PENETRATION/php-filter-magic.htmlspa
這裏講述了能夠利用php僞協議進行繞過,簡單來講,咱們若是使用 file=php://filter/write=convert.base64-decode 來進行對file變量的處理,既以base64的編碼來讀。而咱們爲何要使用base64呢?由於<?php exit;?>中"<、?、;、>"等符號解碼時都會被忽略,因此命令就變成了--> 「phpexit」。也就達到了咱們繞過了這個函數。以後咱們要想執行咱們所想的代碼,能夠在phpexit這七個字符後任意加一個字母(由於base64是4個字符一組進行解碼的),因此咱們能夠寫成code
file=php://filter/write=convert.base64-decode/resource=tmp.php
也就是說以base64爲編碼對tmp.php讀取。而寫入tmp.php的內容是什麼呢?htm
這裏咱們能夠嵌入php命令來寫入tmp.php中blog
將命令用base64編碼,獲得PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==,而後在原有的(phpexit)基礎上添加上述base64代碼,(****這裏咱們爲了讓其成爲八位,因此任意在後面加一個a)獲得
phpexitaPD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
而傳過去的值爲t=aPD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
也就獲得flag了,,233333