[PHP] Linux PHP 寫入與刪除文件差異特性

2018, Dec 02    

有時候目標網站存在任意文件上傳漏洞,但操作執行完成後即刻刪除,導致我們的webshell無法保留在服務器上。這種情況多存在於一些有緩存文件、臨時文件的邏輯中,在實戰裡經常遇到。

Linux下,php的文件寫入與移動刪除等操作中,由於對於路徑的處理存在差異,在有上述情況存在時,我們可以通過傳入文件名為shell.php/.的文件,繞過刪除函數


常見代碼如下:

<?php
$filename = __DIR__ . '/temp/' . $_POST['filename'];
file_put_contents($filename,$_POST['data']);
// ...執行做一些操作
unlink($filename);

我們寫入的文件會立即刪除。此時,我們傳入filename=shell.php/.,即可繞過刪除函數,最後得到shell.php。

內核分析

查看php源碼,其實我們能發現,php讀取、寫入文件,都會調用php_stream_open_wrapper_ex來打開流,而判斷文件存在、重命名、刪除文件等操作則無需打開文件流。

我們跟一跟php_stream_open_wrapper_ex就會發現,其實最後會使用tsrm_realpath函數來將filename給標準化成一個絕對路徑。而文件刪除等操作則不會,這就是二者的區別。

所以,如果我們傳入的是文件名中包含一個不存在的路徑,寫入的時候因為會處理掉”../”等相對路徑,所以不會出錯;判斷、刪除的時候因為不會處理,所以就會出現"No such file or directory"的錯誤。

下面給出兩個例子:

write.php

<?php
file_put_contents("test.php/.","test");
?>

unlink.php

<?php
unlink("test.php/.");
?>

先運行write.php,發現php能夠處理test.php/. 這樣的格式,並成功生成test.php文件,再運行unlink.php,發現產生了一個warning:

Warning: unlink(test.php/.): Not a directory in /Applications/MAMP/htdocs/unlink.php on line 5

查看文件目錄,發現刪除文件失敗,由於對於同樣的路徑的處理存在差異,在php文件寫入後即刪除的情況下,可能會出現刪除繞過的情況,從而留下上傳的文件。

Linux下除了 test.php/. 這種繞過方法外,還可以使用 xxxxx/../test.php , windows下可以使用test.php:test test.ph< 進行繞過。

資料來源

https://tricking.io/card/18/content