Exemplo n.º 1
0
Status WindowsEventSubscriber::Callback(const ECRef& ec, const SCRef& sc) {
  Row r;
  FILETIME cTime;
  GetSystemTimeAsFileTime(&cTime);
  r["time"] = BIGINT(filetimeToUnixtime(cTime));
  r["datetime"] =
      ec->eventRecord.get("Event.System.TimeCreated.<xmlattr>.SystemTime", "");
  r["source"] = ec->eventRecord.get("Event.System.Channel", "");
  r["provider_name"] =
      ec->eventRecord.get("Event.System.Provider.<xmlattr>.Name", "");
  r["provider_guid"] =
      ec->eventRecord.get("Event.System.Provider.<xmlattr>.Guid", "");
  r["eventid"] = INTEGER(ec->eventRecord.get("Event.System.EventID", -1));
  r["task"] = INTEGER(ec->eventRecord.get("Event.System.Task", -1));
  r["level"] = INTEGER(ec->eventRecord.get("Event.System.Level", -1));
  r["keywords"] = BIGINT(ec->eventRecord.get("Event.System.Keywords", -1));

  /*
   * From the MSDN definition of the Event Schema, each event will have
   * an XML choice element containing the event data, if any. The first
   * iteration enumerates this choice, and the second iteration enumerates
   * all data elements belonging to the choice.
   */
  pt::ptree jsonOut;
  std::map<std::string, std::string> results;
  std::string eventDataType;

  for (const auto& node : ec->eventRecord.get_child("Event", pt::ptree())) {
    /// We have already processed the System event data above
    if (node.first == "System" || node.first == "<xmlattr>") {
      continue;
    }
    eventDataType = node.first;
    parseTree(node.second, results);
  }
  for (const auto& val : results) {
    /// Reconstruct the event format as much as possible
    jsonOut.put(eventDataType + "." + val.first, val.second);
  }

  std::stringstream ss;
  boost::property_tree::write_json(ss, jsonOut, false);

  auto s = ss.str();
  if (s.at(s.size() - 1) == '\n') {
    s.erase(s.end());
  }
  r["data"] = s;

  add(r);
  return Status(0, "OK");
}
Exemplo n.º 2
0
/// Microsoft helper function for getting the contents of a registry key
void queryKey(const std::string& hive,
              const std::string& key,
              QueryData& results) {
  if (kRegistryHives.count(hive) != 1) {
    return;
  }

  HKEY hRegistryHandle;
  auto ret = RegOpenKeyEx(kRegistryHives.at(hive),
                          TEXT(key.c_str()),
                          0,
                          KEY_READ,
                          &hRegistryHandle);

  if (ret != ERROR_SUCCESS) {
    return;
  }

  const DWORD maxKeyLength = 255;
  const DWORD maxValueName = 16383;
  TCHAR achClass[MAX_PATH] = TEXT("");
  DWORD cchClassName = MAX_PATH;
  DWORD cSubKeys = 0;
  DWORD cbMaxSubKey;
  DWORD cchMaxClass;
  DWORD cValues;
  DWORD cchMaxValueName;
  DWORD cbMaxValueData;
  DWORD cbSecurityDescriptor;
  DWORD retCode;
  FILETIME ftLastWriteTime;
  retCode = RegQueryInfoKey(hRegistryHandle,
                            achClass,
                            &cchClassName,
                            nullptr,
                            &cSubKeys,
                            &cbMaxSubKey,
                            &cchMaxClass,
                            &cValues,
                            &cchMaxValueName,
                            &cbMaxValueData,
                            &cbSecurityDescriptor,
                            &ftLastWriteTime);

  TCHAR achKey[maxKeyLength];
  DWORD cbName;

  // Process registry subkeys
  if (cSubKeys > 0) {
    for (DWORD i = 0; i < cSubKeys; i++) {
      cbName = maxKeyLength;
      retCode = RegEnumKeyEx(hRegistryHandle,
                             i,
                             achKey,
                             &cbName,
                             nullptr,
                             nullptr,
                             nullptr,
                             &ftLastWriteTime);
      if (retCode != ERROR_SUCCESS) {
        continue;
      }
      Row r;
      fs::path keyPath(key);
      r["hive"] = hive;
      r["key"] = keyPath.string();
      r["subkey"] = (keyPath / achKey).string();
      r["name"] = "(Default)";
      r["type"] = "REG_SZ";
      r["data"] = "(value not set)";
      r["mtime"] = std::to_string(filetimeToUnixtime(ftLastWriteTime));
      results.push_back(r);
    }
  }

  if (cValues <= 0) {
    return;
  }

  BYTE* bpDataBuff = new BYTE[cbMaxValueData];
  DWORD cchValue = maxKeyLength;
  TCHAR achValue[maxValueName];

  // Process registry values
  for (size_t i = 0, retCode = ERROR_SUCCESS; i < cValues; i++) {
    size_t cnt = 0;
    ZeroMemory(bpDataBuff, cbMaxValueData);
    cchValue = maxValueName;
    achValue[0] = '\0';

    retCode = RegEnumValue(hRegistryHandle,
                           static_cast<DWORD>(i),
                           achValue,
                           &cchValue,
                           nullptr,
                           nullptr,
                           nullptr,
                           nullptr);

    if (retCode != ERROR_SUCCESS) {
      continue;
    }

    DWORD lpData = cbMaxValueData;
    DWORD lpType;
    retCode = RegQueryValueEx(
        hRegistryHandle, achValue, 0, &lpType, bpDataBuff, &lpData);

    if (retCode != ERROR_SUCCESS) {
      continue;
    }

    Row r;
    fs::path keyPath(key);
    r["hive"] = hive;
    r["key"] = keyPath.string();
    r["subkey"] = keyPath.string();
    r["name"] = achValue;
    if (kRegistryTypes.count(lpType) > 0) {
      r["type"] = kRegistryTypes.at(lpType);
    } else {
      r["type"] = "UNKNOWN";
    }
    r["mtime"] = std::to_string(filetimeToUnixtime(ftLastWriteTime));

    bpDataBuff[cbMaxValueData - 1] = 0x00;

    /// REG_LINK is a Unicode string, which in Windows is wchar_t
    char* regLinkStr = nullptr;
    if (lpType == REG_LINK) {
      regLinkStr = new char[cbMaxValueData];
      const size_t newSize = cbMaxValueData;
      size_t convertedChars = 0;
      wcstombs_s(&convertedChars,
                 regLinkStr,
                 newSize,
                 (wchar_t*)bpDataBuff,
                 _TRUNCATE);
    }

    BYTE* bpDataBuffTmp = bpDataBuff;
    std::vector<std::string> multiSzStrs;
    std::vector<char> regBinary;
    std::string data;

    switch (lpType) {
    case REG_FULL_RESOURCE_DESCRIPTOR:
    case REG_RESOURCE_LIST:
    case REG_BINARY:
      for (unsigned int i = 0; i < cbMaxValueData; i++) {
        regBinary.push_back((char)bpDataBuff[i]);
      }
      boost::algorithm::hex(
          regBinary.begin(), regBinary.end(), std::back_inserter(data));
      r["data"] = data;
      break;
    case REG_DWORD:
      r["data"] = std::to_string(*((int*)bpDataBuff));
      break;
    case REG_DWORD_BIG_ENDIAN:
      r["data"] = std::to_string(_byteswap_ulong(*((int*)bpDataBuff)));
      break;
    case REG_EXPAND_SZ:
      r["data"] = std::string((char*)bpDataBuff);
      break;
    case REG_LINK:
      r["data"] = std::string(regLinkStr);
      break;
    case REG_MULTI_SZ:
      while (*bpDataBuffTmp != 0x00) {
        std::string s((char*)bpDataBuffTmp);
        bpDataBuffTmp += s.size() + 1;
        multiSzStrs.push_back(s);
      }
      r["data"] = boost::algorithm::join(multiSzStrs, ",");
      break;
    case REG_NONE:
      r["data"] = std::string((char*)bpDataBuff);
      break;
    case REG_QWORD:
      r["data"] = std::to_string(*((unsigned long long*)bpDataBuff));
      break;
    case REG_SZ:
      r["data"] = std::string((char*)bpDataBuff);
      break;
    default:
      r["data"] = "";
      break;
    }
    results.push_back(r);
    if (regLinkStr != nullptr) {
      delete (regLinkStr);
    }
  }
  delete (bpDataBuff);
  RegCloseKey(hRegistryHandle);
};
Exemplo n.º 3
0
void enumerateTasksForFolder(std::string path, QueryData& results) {
  void* vpService = nullptr;
  auto ret = CoCreateInstance(CLSID_TaskScheduler,
                              nullptr,
                              CLSCTX_INPROC_SERVER,
                              IID_ITaskService,
                              &vpService);
  if (FAILED(ret)) {
    VLOG(1) << "Failed to create COM instance " << ret;
    return;
  }

  auto pService = static_cast<ITaskService*>(vpService);
  ret =
      pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
  if (FAILED(ret)) {
    VLOG(1) << "Failed to connect to TaskService " << ret;
    pService->Release();
    return;
  }

  ITaskFolder* pRootFolder = nullptr;
  auto widePath = stringToWstring(path);
  ret = pService->GetFolder(BSTR(widePath.c_str()), &pRootFolder);
  pService->Release();
  if (FAILED(ret)) {
    VLOG(1) << "Failed to get root task folder " << ret;
    return;
  }

  IRegisteredTaskCollection* pTaskCollection = nullptr;
  ret = pRootFolder->GetTasks(TASK_ENUM_HIDDEN, &pTaskCollection);
  pRootFolder->Release();
  if (FAILED(ret)) {
    VLOG(1) << "Failed to get task collection for root folder " << ret;
    return;
  }

  long numTasks = 0;
  pTaskCollection->get_Count(&numTasks);
  for (size_t i = 0; i < numTasks; i++) {
    IRegisteredTask* pRegisteredTask = nullptr;
    // Collections are 1-based lists
    ret = pTaskCollection->get_Item(_variant_t(i + 1), &pRegisteredTask);
    if (FAILED(ret)) {
      VLOG(1) << "Failed to process task";
      continue;
    }

    Row r;
    BSTR taskName;
    ret = pRegisteredTask->get_Name(&taskName);
    std::wstring wTaskName(taskName, SysStringLen(taskName));
    r["name"] = ret == S_OK ? SQL_TEXT(wstringToString(wTaskName.c_str())) : "";

    VARIANT_BOOL enabled = false;
    pRegisteredTask->get_Enabled(&enabled);
    r["enabled"] = enabled ? INTEGER(1) : INTEGER(0);

    TASK_STATE taskState;
    pRegisteredTask->get_State(&taskState);
    r["state"] = kStateMap.count(taskState) > 0
                     ? kStateMap.at(taskState)
                     : kStateMap.at(TASK_STATE_UNKNOWN);

    BSTR taskPath;
    ret = pRegisteredTask->get_Path(&taskPath);
    std::wstring wTaskPath(taskPath, SysStringLen(taskPath));
    r["path"] = ret == S_OK ? wstringToString(wTaskPath.c_str()) : "";

    VARIANT_BOOL hidden = false;
    pRegisteredTask->get_Enabled(&hidden);
    r["hidden"] = hidden ? INTEGER(1) : INTEGER(0);

    HRESULT lastTaskRun = E_FAIL;
    pRegisteredTask->get_LastTaskResult(&lastTaskRun);
    _com_error err(lastTaskRun);
    r["last_run_message"] = err.ErrorMessage();
    r["last_run_code"] = INTEGER(lastTaskRun);

    // We conver the COM Date type to a unix epoch timestamp
    DATE dRunTime;
    SYSTEMTIME st;
    FILETIME ft;
    FILETIME locFt;

    pRegisteredTask->get_LastRunTime(&dRunTime);
    VariantTimeToSystemTime(dRunTime, &st);
    SystemTimeToFileTime(&st, &ft);
    LocalFileTimeToFileTime(&ft, &locFt);
    r["last_run_time"] = INTEGER(filetimeToUnixtime(locFt));

    pRegisteredTask->get_NextRunTime(&dRunTime);
    VariantTimeToSystemTime(dRunTime, &st);
    SystemTimeToFileTime(&st, &ft);
    LocalFileTimeToFileTime(&ft, &locFt);
    r["next_run_time"] = INTEGER(filetimeToUnixtime(locFt));

    ITaskDefinition* taskDef = nullptr;
    IActionCollection* tActionCollection = nullptr;
    pRegisteredTask->get_Definition(&taskDef);
    if (taskDef != nullptr) {
      taskDef->get_Actions(&tActionCollection);
    }

    long actionCount = 0;
    if (tActionCollection != nullptr) {
      tActionCollection->get_Count(&actionCount);
    }
    std::vector<std::string> actions;

    // Task collections are 1-indexed
    for (auto j = 1; j <= actionCount; j++) {
      IAction* act = nullptr;
      IExecAction* execAction = nullptr;
      tActionCollection->get_Item(j, &act);
      if (act == nullptr) {
        continue;
      }
      act->QueryInterface(IID_IExecAction,
                          reinterpret_cast<void**>(&execAction));
      if (execAction == nullptr) {
        continue;
      }

      BSTR taskExecPath;
      execAction->get_Path(&taskExecPath);
      std::wstring wTaskExecPath(taskExecPath, SysStringLen(taskExecPath));

      BSTR taskExecArgs;
      execAction->get_Arguments(&taskExecArgs);
      std::wstring wTaskExecArgs(taskExecArgs, SysStringLen(taskExecArgs));

      BSTR taskExecRoot;
      execAction->get_WorkingDirectory(&taskExecRoot);
      std::wstring wTaskExecRoot(taskExecRoot, SysStringLen(taskExecRoot));

      auto full = wTaskExecRoot + L" " + wTaskExecPath + L" " + wTaskExecArgs;
      actions.push_back(wstringToString(full.c_str()));
      act->Release();
    }
    if (tActionCollection != nullptr) {
      tActionCollection->Release();
    }
    if (taskDef != nullptr) {
      taskDef->Release();
    }
    r["action"] = !actions.empty() ? osquery::join(actions, ",") : "";

    results.push_back(r);
    pRegisteredTask->Release();
  }
  pTaskCollection->Release();
}
Exemplo n.º 4
0
void enumerateTasksForFolder(std::string path, QueryData& results) {
  void* vpService = nullptr;
  auto ret = CoCreateInstance(CLSID_TaskScheduler,
                              nullptr,
                              CLSCTX_INPROC_SERVER,
                              IID_ITaskService,
                              &vpService);
  if (FAILED(ret)) {
    VLOG(1) << "Failed to create COM instance " << ret;
    return;
  }

  auto pService = static_cast<ITaskService*>(vpService);
  ret =
      pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
  if (FAILED(ret)) {
    VLOG(1) << "Failed to connect to TaskService " << ret;
    pService->Release();
    return;
  }

  ITaskFolder* pRootFolder = nullptr;
  auto widePath = stringToWstring(path.c_str());
  ret = pService->GetFolder(BSTR(widePath.c_str()), &pRootFolder);
  pService->Release();
  if (FAILED(ret)) {
    VLOG(1) << "Failed to get root task folder " << ret;
    return;
  }

  IRegisteredTaskCollection* pTaskCollection = nullptr;
  ret = pRootFolder->GetTasks(TASK_ENUM_HIDDEN, &pTaskCollection);
  pRootFolder->Release();
  if (FAILED(ret)) {
    VLOG(1) << "Failed to get task collection for root folder " << ret;
    return;
  }

  long numTasks = 0;
  pTaskCollection->get_Count(&numTasks);
  for (size_t i = 0; i < numTasks; i++) {
    IRegisteredTask* pRegisteredTask = nullptr;
    // Collections are 1-based lists
    ret = pTaskCollection->get_Item(_variant_t(i + 1), &pRegisteredTask);
    if (FAILED(ret)) {
      VLOG(1) << "Failed to process task";
      continue;
    }

    Row r;
    BSTR taskName;
    ret = pRegisteredTask->get_Name(&taskName);
    std::wstring wTaskName(taskName, SysStringLen(taskName));
    r["name"] = ret == S_OK ? SQL_TEXT(wstringToString(wTaskName.c_str())) : "";

    VARIANT_BOOL enabled = false;
    pRegisteredTask->get_Enabled(&enabled);
    r["enabled"] = enabled ? INTEGER(1) : INTEGER(0);

    TASK_STATE taskState;
    pRegisteredTask->get_State(&taskState);
    r["state"] = kStateMap.count(taskState) > 0
                     ? kStateMap.at(taskState)
                     : kStateMap.at(TASK_STATE_UNKNOWN);

    BSTR taskPath;
    ret = pRegisteredTask->get_Path(&taskPath);
    std::wstring wTaskPath(taskPath, SysStringLen(taskPath));
    r["path"] = ret == S_OK ? SQL_TEXT(wstringToString(wTaskPath.c_str())) : "";

    VARIANT_BOOL hidden = false;
    pRegisteredTask->get_Enabled(&hidden);
    r["hidden"] = hidden ? INTEGER(1) : INTEGER(0);

    HRESULT lastTaskRun = E_FAIL;
    pRegisteredTask->get_LastTaskResult(&lastTaskRun);
    _com_error err(lastTaskRun);
    r["last_run_message"] = err.ErrorMessage();
    r["last_run_code"] = INTEGER(lastTaskRun);

    // We conver the COM Date type to a unix epoch timestamp
    DATE dRunTime;
    SYSTEMTIME st;
    FILETIME ft;
    FILETIME locFt;

    pRegisteredTask->get_LastRunTime(&dRunTime);
    VariantTimeToSystemTime(dRunTime, &st);
    SystemTimeToFileTime(&st, &ft);
    LocalFileTimeToFileTime(&ft, &locFt);
    r["last_run_time"] = INTEGER(filetimeToUnixtime(locFt));

    pRegisteredTask->get_NextRunTime(&dRunTime);
    VariantTimeToSystemTime(dRunTime, &st);
    SystemTimeToFileTime(&st, &ft);
    LocalFileTimeToFileTime(&ft, &locFt);
    r["next_run_time"] = INTEGER(filetimeToUnixtime(locFt));

    results.push_back(r);
    pRegisteredTask->Release();
  }
  pTaskCollection->Release();
}
Exemplo n.º 5
0
Status PowershellEventSubscriber::Callback(const ECRef& ec, const SCRef& sc) {
  // For script block logging we only care about events with script blocks
  auto eid = ec->eventRecord.get("Event.System.EventID", -1);
  if (eid != kScriptBlockLoggingEid) {
    return Status();
  }

  Row results;
  for (const auto& node : ec->eventRecord.get_child("Event", pt::ptree())) {
    if (node.first == "System" || node.first == "<xmlattr>") {
      continue;
    }
    // #4357: This should make use of RapidJSON
    parseTree(node.second, results);
  }

  FILETIME etime;
  GetSystemTimeAsFileTime(&etime);
  results["time"] = BIGINT(filetimeToUnixtime(etime));
  results["datetime"] =
      ec->eventRecord.get("Event.System.TimeCreated.<xmlattr>.SystemTime", "");

  // If there's only one script block no reassembly is needed
  if (results["MessageTotal"] == "1") {
    addScriptResult(results);
    return Status();
  }

  // Add the script content to the DB for later reassembly
  auto s = setDatabaseValue(kEvents,
                            kScriptBlockPrefix + results["ScriptBlockId"] +
                                "." + results["MessageNumber"],
                            results["ScriptBlockText"]);
  if (!s.ok()) {
    LOG(WARNING) << "Failed to add new Powershell block to database for script "
                 << results["ScriptBlockId"];
  }

  // If we expect more blocks bail out early
  if (results["MessageNumber"] != results["MessageTotal"]) {
    return Status();
  }

  // Otherwise all script blocks should be accounted for so reconstruct
  std::vector<std::string> keys;
  s = scanDatabaseKeys(
      kEvents, keys, kScriptBlockPrefix + results["ScriptBlockId"]);
  if (!s.ok()) {
    LOG(WARNING) << "Failed to look up powershell script blocks for "
                 << results["ScriptBlockId"];
    return Status(1);
  }

  std::string powershell_script{""};
  for (const auto& key : keys) {
    std::string val{""};
    s = getDatabaseValue(kEvents, key, val);
    if (!s.ok()) {
      LOG(WARNING) << "Failed to retrieve script block " << key;
      continue;
    }

    powershell_script += val;

    s = deleteDatabaseValue(kEvents, key);
    if (!s.ok()) {
      LOG(WARNING) << "Failed to delete script block key from db " << key;
    }
  }

  results["ScriptBlockText"] = powershell_script;
  addScriptResult(results);

  return Status();
}