prey/prey-node-client

View on GitHub
lib/agent/providers/hardware/windows.js

Summary

Maintainability
D
1 day
Test Coverage
const { exec } = require('child_process');
const { join } = require('path');
const wmic = require('wmic');
const si = require('systeminformation');
const system = require('../../../system/windows');
const common = require('../../common');

const logger = common.logger.prefix('wmic');
const gte = common.helpers.is_greater_or_equal;
const { isBoolean } = require('../../utils/utilsprey');

const ramFormFactors = [
  'Unknown',
  'Other',
  'SIP',
  'DIP',
  'ZIP',
  'SOJ',
  'Proprietary',
  'SIMM',
  'DIMM',
  'TSOP',
  'PGA',
  'RIMM',
  'SODIMM',
  'SRIMM',
  'SMD',
  'SSMP',
  'QFP',
  'TQFP',
  'SOIC',
  'LCC',
  'PLCC',
  'BGA',
  'FPBGA',
  'LGA',
];

const ramTypes = [
  'Unknown',
  'Other',
  'DRAM',
  'Synchronous DRAM',
  'Cache DRAM',
  'EDO',
  'EDRAM',
  'VRAM',
  'SRAM',
  'RAM',
  'ROM',
  'Flash',
  'EEPROM',
  'FEPROM',
  'EPROM',
  'CDRAM',
  '3DRAM',
  'SDRAM',
  'SGRAM',
  'RDRAM',
  'DDR',
  'DDR2',
];

const firmwareKeys = {
  uuid: ['path win32_computersystemproduct', 'uuid'],
  serial_number: ['bios', 'serialnumber'],
  bios_vendor: ['bios', 'Manufacturer'],
  bios_version: ['bios', 'SMBIOSBIOSVersion'],
  mb_vendor: ['baseboard', 'manufacturer'],
  mb_serial: ['baseboard', 'serialnumber'],
  mb_model: ['baseboard', 'product'],
  mb_version: ['baseboard', 'version'],
  device_type: ['path Win32_Battery', 'Availability'],
  model_name: ['computersystem', 'Model'],
  vendor_name: ['computersystem', 'Manufacturer'],
};

let count = Object.keys(firmwareKeys).length;
// eslint-disable-next-line consistent-return

const finishedfirmwareKeysInfo = (data, callback) => {
  count -= 1;
  if (count <= 0) {
    callback(null, data);
  }
};

const hasBattery = (type, dataFirmware, key, callback) => {
  let res = type;
  const data = dataFirmware;
  try {
    exec('powershell @(Get-CimInstance -ClassName Win32_Battery).Count -gt 0', (errorhasBattery, hasBatteryPresent) => {
      if (errorhasBattery) logger.info(`Error on getting Chassistype: ${errorhasBattery}`);
      // eslint-disable-next-line no-extra-boolean-cast
      if (isBoolean(hasBatteryPresent)) res = 'Laptop';
      if (res) data[key] = res;
      finishedfirmwareKeysInfo(data, callback);
    });
  } catch (exception) {
    finishedfirmwareKeysInfo(null, callback);
  }
};

exports.get_firmware_info = (callback) => {
  let data = {};
  const fetch = (key, section, value) => {
    wmic.get_value(section, value, null, (err, resp) => {
      let res = resp;
      if (key === 'device_type') {
        res = err ? 'Desktop' : 'Laptop';
        if (res === 'Laptop') {
          if (!err && res) data[key] = res;
          finishedfirmwareKeysInfo(data, callback);
        } else {
          try {
            exec('wmic systemenclosure get ChassisTypes', (_errorChassisTypes, Chassistypes) => {
              const laptopTypes = [9, 10, 14];
              const typeNumber = Number(Chassistypes.match(/\d+/g));
              if (laptopTypes.includes(typeNumber)) {
                res = 'Laptop';
                logger.info(`Chassistypes: ${typeNumber}, type: ${res}`);
                if (res) data[key] = res;
                finishedfirmwareKeysInfo(data, callback);
              } else {
                hasBattery(res, data, key, callback);
              }
            });
          } catch (error) {
            if (error) logger.info(`Error on getting Chassistype: ${error}`);
            hasBattery(res, data, key, callback);
          }
        }
      } else {
        data[key] = res;
        finishedfirmwareKeysInfo(data, callback);
      }
    });
  };

  wmic.get_value('path win32_computersystemproduct', 'uuid', null, (err) => {
    if (err) {
      data = {
        uuid: '',
        serial_number: '',
        bios_vendor: '',
        bios_version: '',
        mb_vendor: '',
        mb_serial: '',
        mb_model: '',
        mb_version: '',
        device_type: '',
        model_name: '',
        vendor_name: '',
      };

      si.system((stdoutsiSys) => {
        if (!stdoutsiSys || !stdoutsiSys.uuid || stdoutsiSys.uuid.toString().trim() === '') {
          callback(new Error('No Info found.'));
        } else {
          data.uuid = stdoutsiSys.uuid.toUpperCase();
          data.serial_number = stdoutsiSys.serial;
          data.model_name = stdoutsiSys.model;
          data.vendor_name = stdoutsiSys.manufacturer;

          si.bios((stdoutsiBios) => {
            if (!stdoutsiBios || !stdoutsiBios.vendor || stdoutsiBios.vendor.toString().trim() === '') {
              callback(null, data);
            } else {
              logger.info(`bios : ${JSON.stringify(stdoutsiBios)}`);
              data.bios_vendor = stdoutsiBios.vendor;
              data.bios_version = stdoutsiBios.version;
              si.baseboard((stdoutsiBaseBoard) => {
                if (!stdoutsiBaseBoard || !stdoutsiBaseBoard.manufacturer || stdoutsiBaseBoard.manufacturer.toString().trim() === '') {
                  callback(null, data);
                } else {
                  data.mb_vendor = stdoutsiBaseBoard.manufacturer;
                  data.mb_serial = (stdoutsiBaseBoard.serial) ? (stdoutsiBaseBoard.serial) : null;
                  data.mb_model = stdoutsiBaseBoard.model;
                  data.mb_version = stdoutsiBaseBoard.version;
                  si.battery((stdoutsiBattery) => {
                    if (!stdoutsiBattery || !stdoutsiBattery.hasBattery) {
                      data.device_type = 'Desktop';
                      callback(null, data);
                    } else {
                      data.device_type = 'Laptop';
                      callback(null, data);
                    }
                  });
                }
              });
            }
          });
        }
      });
    }
    Object.keys(firmwareKeys).forEach((key) => {
      const values = firmwareKeys[key];
      fetch(key, values[0], values[1]);
    });
  });
};

exports.get_ram_module_list = (cb) => {
  const list = [];
  const file = join(__dirname, 'ramcheck.vbs');

  // eslint-disable-next-line consistent-return
  exec(`cscript ${file} /B`, (err, stdout) => {
    if (err) return cb(err);

    stdout.toString().split('---').forEach((block) => {
      const data = {};

      block.split('\n').forEach((line) => {
        const split = line.split(':');
        const key = split[0].replace(/ /g, '-');
        const val = (split[1] || '').trim();

        if (val && val !== '') data[key] = val;
      });

      if (!data.Name) return;

      list.push({
        name: data.Name,
        bank: data['Bank-Label'],
        location: data['Device-Locator'],
        size: parseInt(data.Capacity, 10) / 1048576,
        form_factor: ramFormFactors[parseInt(data['Form-Factor'], 10)] || 'Unknown',
        memory_type: ramTypes[parseInt(data['Memory-Type'], 10)] || 'Unknown',
        speed: parseInt(data.Speed, 10),
        data_width: parseInt(data['Data-Width'], 10),
      });
    });

    cb(null, list);
  });
};

exports.get_tpm_module = (cb) => {
  system.get_as_admin('tpmModule', (err, infoData) => {
    exports.resolveTpmModuleInfo(err, infoData, cb);
  });
};

exports.resolveTpmModuleInfo = (err, infoData, cb) => {
  const info = infoData;
  if (err) return cb(err);
  if (typeof info === 'string') {
    try {
      JSON.parse(info);
    } catch (e) {
      return cb(new Error(`Error getting tpm module info: ${e.message}`));
    }
  }
  try {
    info.manufacturer_version = info.manufacturerVersion;
    delete info.manufacturerVersion;
  } catch (e) {
    return cb(new Error(`Error getting tpm module info: ${e.message}`));
  }

  return cb(null, info);
};

// eslint-disable-next-line consistent-return
exports.get_recovery_partition_status = (cb) => {
  if (gte(system.os_release, '10.0.0')) {
    const json = {};
    json.available = false;
    system.get_as_admin('recoveryPartition', (err, info) => {
      if (err) return cb(err);
      try {
        json.available = info.enabled;
        logger.info(`info from recovery partition:${JSON.stringify(info)}`);
      } catch (e) {
        return cb(new Error(`Error recoveryPartition info: ${e.message}`));
      }
      return cb(null, json);
    });
  } else {
    return cb(new Error('Only for version '));
  }
};

exports.get_killswitch_compatible = (cb) => {
  const data = {
    key: 'device-key',
    token: 'token',
    logged: false,
    dirs: [],
  };
  const nodeBin = join(system.paths.current, 'bin', 'node');
  const action = 'check-full-wipe';
  
  // eslint-disable-next-line consistent-return
  system.spawn_as_admin_user(nodeBin, data, (errFirst, childWinsvcCb) => {
    if (errFirst) {
      return cb(errFirst, undefined, 'killswitch_compatible');
    }
    if (typeof childWinsvcCb === 'function') {
      // eslint-disable-next-line consistent-return
      childWinsvcCb(action, data, (errCheckFullWipeCb, checkFullWipeCb) => {
        if (errCheckFullWipeCb) {
          return cb(errFirst, undefined, 'killswitch_compatible');
        }
        if (checkFullWipeCb.error) {
          return cb(new Error(checkFullWipeCb.message), false, 'killswitch_compatible');
        }
        cb(null, true, 'killswitch_compatible');
      });
    } else {
      cb(null, undefined, 'killswitch_compatible');
    }
  });
};
exports.get_osquery_running = (cb) => {
  exec('sc query preyosqueryd', (err, stdout, stderr) => {
    if (err) return cb(null, false, 'osquery_running');
    if (stderr) return cb(null, false, 'osquery_running');
    if (stdout.includes('RUNNING')) { 
      return cb(null, true, 'osquery_running'); 
    } else {
      return cb(null, false, 'osquery_running');
    }
  });
}

exports.get_os_edition = system.get_os_edition;
exports.get_winsvc_version = system.get_winsvc_version;