路漫漫其修远兮

cmswing - Code Execution

2019.06.07

Vulnerability Report: cmswing 1.3.8 code execution

This paper describes an code execution vulnerability in cmswing project. Because the function log does not check the parameter log, malicious parameters can cause code execution in the process of user replenishment

Cmswing https://github.com/arterli/CmsWing is a powerful electronic commerce platform and CMS station building system based on ThinkJS (Node.js MVC) and MySQL (PC, mobile and Wechat Public Platform)

Test Environment

  • cmswing: 1.3.8
  • github: https://github.com/arterli/CmsWing
  • stars: 1094
  • nodejs: 11.10.0
  • mysql: 5.7.27
  • OS and hardware: Mac OS X 10_12_6

Vulnerability Location

The vulnerability lies in the log function in the cmswing/src/mode/action.js

async log(action, model, record_id, user_id, ip, url) {
    // action=action||null,model=model||null,record_id=record_id||null,user_id=user_id||null;
    // 参数检查
    if (think.isEmpty(action) || think.isEmpty(model) || think.isEmpty(record_id)) {
      return '参数不能为空';
    }

    if (think.isEmpty(user_id)) {
      const user = await think.session('userInfo');
      const id = user.id;
      user_id = id;
    }

    // 查询行为,判断是否执行

    const action_info = await this.where({name: action}).find();
    if (action_info.status != 1) {
      return '该行为被禁用';
    }

    // 插入行为日志

    const data = {
      action_id: action_info.id,
      user_id: user_id,
      action_ip: _ip2int(ip),
      model: model,
      record_id: record_id,
      create_time: new Date().valueOf()
    };
    data.remark = '';
    // 解析日志规则,生成日志备注;
    if (!think.isEmpty(action_info.log)) {
      const match = action_info.log.match(/\[(\S+?)\]/g);
      if (!think.isEmpty(match)) {
        const log = {
          user: user_id,
          record: record_id,
          model: model,
          time: new Date().valueOf(),
          data: {
            user: user_id,
            record: record_id,
            model: model,
            time: new Date().valueOf()
          }
        };

        const replace = [];
        for (let val of match) {
          val = val.replace(/(^\[)|(\]$)/g, '');
          const param = val.split('|');
          console.log(1111111,param);
          if (!think.isEmpty(param[1])) {
            if (param[0] == 'user') {
              replace.push(await call_user_func(param[1], log[param[0]]));
            } else {
              replace.push(call_user_func(param[1], log[param[0]]));
            }
          } else {
            replace.push(log[param[0]]);
          }
        }

        data.remark = str_replace(match, replace, action_info.log);
        // console.log(data.remark)
      } else {
        data.remark = action_info.log;
      }
    } else {
      // 未定义日志规则,记录操作URL
      data.remark = '操作url:' + url;
    }
    if (!think.isNumber(record_id)) {
      data.record_id = 0;
    }
    await this.model('action_log').add(data);

    if (!think.isEmpty(action_info.rule)) {
      const rules = await this.parse_action(action, user_id);
      // console.log(rules);
      const res = await this.execute_action(rules, action_info.id, user_id);
    }
  }
  
  ......
  
  global.call_user_func = function(cb, params) {
  const func = eval(cb);
  if (!think.isArray(params)) {
    params = [params];
  }
  return func.apply(cb, params);
};


The variable log is the user behavior log data transmitted by the front end. The function log implements the processing of the variable log. If the param[0]=='user', the call_user_func function is called. The variable is not checked. Malicious parameters will lead to the eval method of the call_user_fun function to implement code execution.

Local Test

Enter the background of the system, select user behavior,add our payload to the rules of conduct

avatar

Add an article to trigger the user behavior just now.

avatar

Execution Log, the code was successfully executed and the IP-related information was printed out

avatar

Summary

In this paper, code execution vulnerability in cmswing version 1.3.8 is verified by local tests. This problem can be avoided by checking the variable log

发表评论