74cms 最新 getshell 漏洞

74cms 最新 getshell 漏洞

1398133550745333 神农Sec 2025-02-28 01:01

扫码加圈子

获内部资料

网络安全领域各种资源,EDUSRC证书站挖掘、红蓝攻防、渗透测试等优质文章,以及工具分享、前沿信息分享、POC、EXP分享。
不定期分享各种好玩的项目及好用的工具,欢迎关注。
加内部圈子,文末有彩蛋
(知识星球
优惠卷)。

原文链接:https://xz.aliyun.com/news/16959

作者:1398133550745333


0x1 前言

文章中涉及的敏感信息均已做打码处理,文章仅做经验分享用途,切勿当真,未授权的攻击属于非法行为!文章中敏感信息均已做多层打码处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任,一旦造成后果请自行承担。


0x2 环境搭建

首先下载源码,直接官网下就好了

https://www.74cms.com/download/detail/161.html

使用 phpstudy 搭建

然后配置数据库地址和管理员的密码

安装成功后

参考
http://doc.74cms.com/#/se/quickstart?id=%e5%ae%89%e8%a3%85%e7%a8%8b%e5%ba%8f


0x3 漏洞复现

首先需要我们自己先注册一个企业账号

访问/member/reg/company

自己先注册一个

然后登录

然后就是我们的企业 logo

可是这里我们内容可以是 base64 来决定,而且文件类型也是可以的

然后发送这个 POC 会得到一个路径

{"code":200,"message":"生成成功","data":{"file_id":"5","file_url":"*****\/upload\/company_logo/******.php"}}

访问即可


0x4 漏洞分析

首先看到我们的漏洞源头代码

application/v1_0/controller/company/Index.php

public function sendCompanyLogo(){
$imgBase64 = input('post.imgBase64/s','','trim');
$company_id = 100;

if (preg_match('/^(data:\s*image\/(\w+);base64,)/',$imgBase64,$res)) {
    //获取图片类型
    $type = $res[2];
    //图片保存路径
    $new_file = "upload/company_logo/".$company_id.'/';
    if (!file_exists($new_file)) {
        mkdir($new_file,0755,true);
    }
    //图片名字
    $new_file = $new_file.time().'.'.$type;
    if (file_put_contents($new_file,base64_decode(str_replace($res[1],'', $imgBase64)))) {
        $id = model('Uploadfile')->insertGetId([
            'save_path' => substr($new_file,6),
            'platform' => 'default',
            'addtime' => time()
        ]);
        $arr = [
            'file_id' => $id,
            'file_url' => config('global_config.sitedomain').'/'.$new_file
        ];
        $this->ajaxReturn(200,'生成成功',$arr);
    } else {
        $this->ajaxReturn(500,'生成失败');
    }
}

而当我们传入 imgBase64=data:image/php;base64,PD9waHAgcGhwaW5mbygpOw==的时候

生成的是一个 php 文件

<?php phpinfo(); ?>

会直接写入

不过生成文件名有 time 随机的,还好信息中会返回路径

但是调用这个方法需要初始化

public function _initialize()
{
    parent::_initialize();
    $this->checkLogin(1);
}

跟进 checkLogin 方法

public function checkLogin($need_utype = 0)
{
    if ($need_utype == 0) {
        $code = 50009;
        $tip = '请先登录';
    } else {
        $tip =
            '当前操作需要登录' .
            ($need_utype == 1 ? '企业' : '个人') .
            '会员';
        $code = $need_utype==1?50011:50010;
    }

    if (
        $this->userinfo === null ||
        ($need_utype > 0 && $this->userinfo->utype != $need_utype)
    ) {

        $this->ajaxReturn($code, $tip);
    }
    if($this->userinfo !== null){
        $member = model('Member')
            ->field(true)
            ->where('uid', $this->userinfo->uid)
            ->find();
        if($member===null){
            $this->ajaxReturn(50002, '请先登录');
        }else{
            /**
             * 【ID1000788】【bug】后台登录简历日志会记录很多条
             * cy 2023-12-23
             * 通过缓存进行控制,由于前端同时多条接口请求产生了并发所以导致记录了多次
             */
            $cacheKey = 'member_login_key_' . $member['uid'];
            $loginCache = cache($cacheKey);
            if (empty($loginCache) && ($member['last_login_time'] == 0 || strtotime(date('Y-m-d', $member['last_login_time'])) != strtotime('today'))) {
                $expire = strtotime('tomorrow') - time();
                cache($cacheKey, $member['uid'], [
                    'expire' => $expire
                ]);
                $this->writeMemberActionLog($member['uid'], '登录成功', true);
            }
        }
    }
}

这里就需要我们注册一个企业的账号了,也就是我们刚刚那个地方


0x5 漏洞修复

这里没有看原作者怎么修复的,我直接因为很明显的问题就是类型

严格限制文件类型
防止文件扩展名伪装

public function sendCompanyLogo() {
    $imgBase64 = input('post.imgBase64/s', '', 'trim');
    $company_id = 100;

    // 正则检查是否是 Base64 编码的图像数据
    if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $imgBase64, $res)) {
        // 获取图片类型
        $type = $res[2];

        // 图片类型检查:仅允许特定类型的图像(JPEG, PNG, GIF等)
        $allowedTypes = ['jpeg', 'jpg', 'png', 'gif'];
        if (!in_array(strtolower($type), $allowedTypes)) {
            $this->ajaxReturn(400, '只允许上传图像文件');
            return;
        }

        // 图片保存路径
        $new_file = "upload/company_logo/" . $company_id . '/';
        if (!file_exists($new_file)) {
            mkdir($new_file, 0755, true);
        }

        // 图片名字
        $new_file = $new_file . time() . '.' . $type;

        // 解码 Base64 并保存图片
        $decodedImage = base64_decode(str_replace($res[1], '', $imgBase64));

        // 通过 getimagesize() 函数确认文件是有效图像
        $imageInfo = getimagesizefromstring($decodedImage);
        if ($imageInfo === false) {
            $this->ajaxReturn(400, '无效的图像文件');
            return;
        }

        // 保存文件
        if (file_put_contents($new_file, $decodedImage)) {
            $id = model('Uploadfile')->insertGetId([
                'save_path' => substr($new_file, 6),
                'platform' => 'default',
                'addtime' => time()
            ]);

            $arr = [
                'file_id' => $id,
                'file_url' => config('global_config.sitedomain') . '/' . $new_file
            ];

            $this->ajaxReturn(200, '生成成功', $arr);
        } else {
            $this->ajaxReturn(500, '生成失败');
        }
    } else {
        $this->ajaxReturn(400, '无效的文件格式');
    }
}

这里强行要求是图片格式了,php 就不可以了

参考
https://github.com/wy876/POC/blob/main/74CMS


0x6 内部圈子详情介绍

我们是
神农安全
,点赞 + 在看
 铁铁们点起来,最后祝大家都能心想事成、发大财、行大运。

内部圈子介绍

圈子专注于更新src/红蓝攻防相关:

1、维护更新src专项漏洞知识库,包含原理、挖掘技巧、实战案例
2、知识星球专属微信“小圈子交流群”
3、微信小群一起挖洞
4、内部团队专属EDUSRC证书站漏洞报告
5、分享src优质视频课程(企业src/EDUSRC/红蓝队攻防)
6、分享src挖掘技巧tips
7、不定期有众测、渗透测试项目(一起挣钱)
8、不定期有工作招聘内推(工作/护网内推)
9、送全国职业技能大赛环境+WP解析(比赛拿奖)

内部圈子
专栏介绍

知识星球内部共享资料截屏详情如下

(只要没有特殊情况,每天都保持更新)

知识星球——
神农安全

神农安全团队创建的知识星球一直从未涨价,永久价格40

(新人优惠卷20,扫码或者私信我即可领取)

欢迎加入星球一起交流,券后价仅40元!!! 即将满350人涨价

长期更新,更多的0day/1day漏洞POC/EXP



神农安全公开交流群

有需要的师傅们直接扫描文章二维码加入,然后要是后面群聊二维码扫描加入不了的师傅们,直接扫描文章开头的二维码加我(备注加群)