Status processRequest(Row& r) { try { osquery::http::Client client_; osquery::http::Response response_; osquery::http::Request request_(r["url"]); // Change the user-agent for the request to be osquery request_ << osquery::http::Request::Header("User-Agent", r["user_agent"]); // Measure the rtt using the system clock std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now(); response_ = client_.get(request_); std::chrono::time_point<std::chrono::system_clock> end = std::chrono::system_clock::now(); r["response_code"] = INTEGER(static_cast<int>(response_.status())); r["round_trip_time"] = BIGINT( std::chrono::duration_cast<std::chrono::microseconds>(end - start) .count()); r["result"] = response_.body(); r["bytes"] = BIGINT(r["result"].size()); } catch (const std::exception& e) { return Status(1, e.what()); } return Status(); }
QueryData genProcesses(QueryContext& context) { QueryData results; proc_t* proc_info; PROCTAB* proc = openproc(PROC_SELECTS); // Populate proc struc for each process. while ((proc_info = readproc(proc, NULL))) { Row r; r["pid"] = INTEGER(proc_info->tid); r["uid"] = BIGINT((unsigned int)proc_info->ruid); r["gid"] = BIGINT((unsigned int)proc_info->rgid); r["euid"] = BIGINT((unsigned int)proc_info->euid); r["egid"] = BIGINT((unsigned int)proc_info->egid); r["name"] = proc_name(proc_info); r["cmdline"] = proc_cmdline(proc_info); r["path"] = proc_link(proc_info); r["on_disk"] = osquery::pathExists(r["path"]).toString(); r["resident_size"] = INTEGER(proc_info->vm_rss); r["phys_footprint"] = INTEGER(proc_info->vm_size); r["user_time"] = INTEGER(proc_info->utime); r["system_time"] = INTEGER(proc_info->stime); r["start_time"] = INTEGER(proc_info->start_time); r["parent"] = INTEGER(proc_info->ppid); results.push_back(r); standard_freeproc(proc_info); } closeproc(proc); return results; }
/** * @brief Entry point for docker_images table. */ QueryData genImages(QueryContext& context) { QueryData results; pt::ptree tree; Status s = dockerApi("/images/json", tree); if (!s.ok()) { VLOG(1) << "Error getting docker images: " << s.what(); return results; } for (const auto& entry : tree) { try { const pt::ptree& node = entry.second; Row r; r["id"] = node.get<std::string>("Id", ""); if (r["id"].find("sha256:") == 0) { r["id"].erase(0, 7); } r["created"] = BIGINT(node.get<uint64_t>("Created", 0)); r["size_bytes"] = BIGINT(node.get<uint64_t>("Size", 0)); std::string tags; for (const auto& tag : node.get_child("RepoTags")) { if (!tags.empty()) { tags.append(","); } tags.append(tag.second.data()); } r["tags"] = tags; results.push_back(r); } catch (const pt::ptree_error& e) { VLOG(1) << "Error getting docker image details: " << e.what(); } } return results; }
void getModelSpecificRegisterData(QueryData &results, int cpu_number) { auto msr_filename = std::string("/dev/cpu/") + std::to_string(cpu_number) + "/msr"; int fd = open(msr_filename.c_str(), O_RDONLY); if (fd < 0) { int err = errno; TLOG << "Could not open msr file " << msr_filename << " check the msr kernel module is enabled."; if (err == EACCES) { TLOG << "Could not access msr device. Run osquery as root."; } return; } Row r; r["processor_number"] = BIGINT(cpu_number); for (const msr_record_t &field : fields) { uint64_t output; ssize_t size = pread(fd, &output, sizeof(uint64_t), field.offset); if (size != sizeof(uint64_t)) { // Processor does not have a record of this type. continue; } if (field.is_flag) { r[field.name] = BIGINT((output & field.mask) ? 1 : 0); } else { r[field.name] = BIGINT(output & field.mask); } } results.push_back(r); close(fd); return; }
void genSocketDescriptor(int pid, int descriptor, QueryData& results) { struct socket_fdinfo si; if (proc_pidfdinfo(pid, descriptor, PROC_PIDFDSOCKETINFO, &si, PROC_PIDFDSOCKETINFO_SIZE) <= 0) { return; } if (si.psi.soi_family == AF_INET || si.psi.soi_family == AF_INET6) { Row r; r["pid"] = INTEGER(pid); r["fd"] = BIGINT(descriptor); r["socket"] = BIGINT(si.psi.soi_so); r["path"] = ""; // Darwin/OSX SOCKINFO_TCP is not IPPROTO_TCP if (si.psi.soi_kind == SOCKINFO_TCP) { r["protocol"] = INTEGER(6); } else { r["protocol"] = INTEGER(17); } // Darwin/OSX AF_INET6 == 30 if (si.psi.soi_family == AF_INET) { r["family"] = INTEGER(2); } else { r["family"] = INTEGER(10); } parseNetworkSocket(si, r); results.push_back(r); } else if (si.psi.soi_family == AF_UNIX) { Row r; r["pid"] = INTEGER(pid); r["socket"] = INTEGER(descriptor); r["family"] = "0"; r["protocol"] = "0"; r["local_address"] = ""; r["local_port"] = "0"; r["remote_address"] = ""; r["remote_port"] = "0"; if ((char*)si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path != nullptr) { r["path"] = si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path; } else { r["path"] = ""; } results.push_back(r); } else if (si.psi.soi_family == AF_APPLETALK) { // AF_APPLETALK = 17 } else if (si.psi.soi_family == AF_NATM) { // AF_NATM = 32 } else { // Unsupported socket type. } }
void genUser(const struct passwd* pwd, QueryData& results) { Row r; r["uid"] = BIGINT(pwd->pw_uid); r["gid"] = BIGINT(pwd->pw_gid); r["uid_signed"] = BIGINT((int32_t)pwd->pw_uid); r["gid_signed"] = BIGINT((int32_t)pwd->pw_gid); r["username"] = TEXT(pwd->pw_name); r["description"] = TEXT(pwd->pw_gecos); r["directory"] = TEXT(pwd->pw_dir); r["shell"] = TEXT(pwd->pw_shell); results.push_back(r); }
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"); }
void genFileInfo(const fs::path& path, const fs::path& parent, const std::string& pattern, QueryData& results) { #ifndef WIN32 // Must provide the path, filename, directory separate from boost path->string // helpers to match any explicit (query-parsed) predicate constraints. struct stat file_stat, link_stat; if (lstat(path.string().c_str(), &link_stat) < 0 || stat(path.string().c_str(), &file_stat)) { // Path was not real, had too may links, or could not be accessed. return; } Row r; r["path"] = path.string(); r["filename"] = path.filename().string(); r["directory"] = parent.string(); r["inode"] = BIGINT(file_stat.st_ino); r["uid"] = BIGINT(file_stat.st_uid); r["gid"] = BIGINT(file_stat.st_gid); r["mode"] = lsperms(file_stat.st_mode); r["device"] = BIGINT(file_stat.st_rdev); r["size"] = BIGINT(file_stat.st_size); r["block_size"] = INTEGER(file_stat.st_blksize); r["hard_links"] = INTEGER(file_stat.st_nlink); // Times r["atime"] = BIGINT(file_stat.st_atime); r["mtime"] = BIGINT(file_stat.st_mtime); r["ctime"] = BIGINT(file_stat.st_ctime); #if defined(__linux__) // No 'birth' or create time in Linux. r["btime"] = "0"; #else r["btime"] = BIGINT(file_stat.st_birthtimespec.tv_sec); #endif // Type booleans boost::system::error_code ec; auto status = fs::status(path, ec); if (kTypeNames.count(status.type())) { r["type"] = kTypeNames.at(status.type()); } else { r["type"] = "unknown"; } r["is_file"] = (!S_ISDIR(file_stat.st_mode)) ? "1" : "0"; r["is_dir"] = (S_ISDIR(file_stat.st_mode)) ? "1" : "0"; r["is_link"] = (S_ISLNK(link_stat.st_mode)) ? "1" : "0"; r["is_char"] = (S_ISCHR(file_stat.st_mode)) ? "1" : "0"; r["is_block"] = (S_ISBLK(file_stat.st_mode)) ? "1" : "0"; results.push_back(r); #endif }
QueryData genKextstat(QueryContext &context) { QueryData results; // Populate dict of kernel extensions. CFDictionaryRef dict = OSKextCopyLoadedKextInfo(NULL, NULL); CFIndex count = CFDictionaryGetCount(dict); // Allocate memory for each extension parse. auto values = (void **)malloc(sizeof(void *) * count); CFDictionaryGetKeysAndValues(dict, nullptr, (const void **)values); for (CFIndex j = 0; j < count; j++) { // name auto name = getKextString(values[j], CFSTR("CFBundleIdentifier")); auto kextTag = getKextInt(values[j], CFSTR("OSBundleLoadTag")); // Possibly limit expensive lookups. if (!context.constraints["name"].matches(name)) { continue; } if (!context.constraints["idx"].matches<int>(kextTag)) { continue; } auto references = getKextInt(values[j], CFSTR("OSBundleRetainCount")); // size auto load_size = getKextBigInt(values[j], CFSTR("OSBundleLoadSize")); auto wired_size = getKextBigInt(values[j], CFSTR("OSBundleWiredSize")); auto version = getKextString(values[j], CFSTR("CFBundleVersion")); // linked_against auto linked = getKextLinked(values[j], CFSTR("OSBundleDependencies")); Row r; r["idx"] = INTEGER(kextTag); r["refs"] = INTEGER(references); r["size"] = BIGINT(load_size); r["wired"] = BIGINT(wired_size); r["name"] = name; r["version"] = version; r["linked_against"] = linked; results.push_back(r); } CFRelease(dict); free(values); return results; }
void Create() { // 灵活性与高效性并存 const std::string strSql( "CREATE TABLE `AM_TAP_XDR` ( \ `ID` BIGINT(10) AUTO_INCREMENT, \ `XDR_FILE` VARCHAR(256) NOT NULL, \ `TOTAL_CDR_COUNT` BIGINT(10) NOT NULL, \ `CREATE_TIME` DATETIME NOT NULL, \ PRIMARY KEY (`ID`) \ )" ); m_pConn->Execute(strSql); }
/** * @brief Entry point for docker_containers table. */ QueryData genContainers(QueryContext& context) { QueryData results; std::set<std::string> ids; pt::ptree containers; Status s = getContainers(context, ids, containers); if (!s.ok()) { return results; } for (const auto& entry : containers) { const pt::ptree& container = entry.second; Row r; r["id"] = getValue(container, ids, "Id"); if (container.count("Names") > 0) { for (const auto& name : container.get_child("Names")) { r["name"] = name.second.data(); break; } } r["image_id"] = container.get<std::string>("ImageID", ""); if (r["image_id"].find("sha256:") == 0) { r["image_id"].erase(0, 7); } r["image"] = container.get<std::string>("Image", ""); r["command"] = container.get<std::string>("Command", ""); r["created"] = BIGINT(container.get<uint64_t>("Created", 0)); r["state"] = container.get<std::string>("State", ""); r["status"] = container.get<std::string>("Status", ""); results.push_back(r); } return results; }
/** * @brief Utility method to get cumulative value for specified "key" from * child node in provided "tree". * * @param tree Tree to iterate. * @param key Key to look for in the child nodes. * @return Cumulative value for "key". */ std::string getNetworkBytes(const pt::ptree& tree, const std::string& key) { uint64_t value = 0; for (const auto& node : tree) { value += node.second.get<uint64_t>(key, 0); } return BIGINT(value); }
QueryData genOsquerySchedule(QueryContext& context) { QueryData results; Config::getInstance().scheduledQueries( [&results](const std::string& name, const ScheduledQuery& query) { Row r; r["name"] = TEXT(name); r["query"] = TEXT(query.query); r["interval"] = INTEGER(query.interval); // Set default (0) values for each query if it has not yet executed. r["executions"] = "0"; r["output_size"] = "0"; r["wall_time"] = "0"; r["user_time"] = "0"; r["system_time"] = "0"; r["average_memory"] = "0"; r["last_executed"] = "0"; // Report optional performance information. Config::getInstance().getPerformanceStats( name, [&r](const QueryPerformance& perf) { r["executions"] = BIGINT(perf.executions); r["last_executed"] = BIGINT(perf.last_executed); r["output_size"] = BIGINT(perf.output_size); r["wall_time"] = BIGINT(perf.wall_time); r["user_time"] = BIGINT(perf.user_time); r["system_time"] = BIGINT(perf.system_time); r["average_memory"] = BIGINT(perf.average_memory); }); results.push_back(r); }); return results; }
QueryData genSharedMemory(QueryContext &context) { QueryData results; // Use shared memory control (shmctl) to get the max SHMID. struct shm_info shm_info; int maxid = shmctl(0, SHM_INFO, (struct shmid_ds *)(void *)&shm_info); if (maxid < 0) { VLOG(1) << "Linux kernel not configured for shared memory"; return {}; } // Use a static pointer to access IPC permissions structure. struct shmid_ds shmseg; struct ipc_perm *ipcp = &shmseg.shm_perm; // Then iterate each shared memory ID up to the max. for (int id = 0; id <= maxid; id++) { int shmid = shmctl(id, SHM_STAT, &shmseg); if (shmid < 0) { continue; } Row r; r["shmid"] = INTEGER(shmid); struct passwd *pw = getpwuid(shmseg.shm_perm.uid); if (pw != nullptr) { r["owner_uid"] = BIGINT(pw->pw_uid); } pw = getpwuid(shmseg.shm_perm.cuid); if (pw != nullptr) { r["creator_uid"] = BIGINT(pw->pw_uid); } // Accessor, creator pids. r["pid"] = BIGINT(shmseg.shm_lpid); r["creator_pid"] = BIGINT(shmseg.shm_cpid); // Access, detached, creator times r["atime"] = BIGINT(shmseg.shm_atime); r["dtime"] = BIGINT(shmseg.shm_dtime); r["ctime"] = BIGINT(shmseg.shm_ctime); r["permissions"] = lsperms(ipcp->mode); r["size"] = BIGINT(shmseg.shm_segsz); r["attached"] = INTEGER(shmseg.shm_nattch); r["status"] = (ipcp->mode & SHM_DEST) ? "dest" : ""; r["locked"] = (ipcp->mode & SHM_LOCKED) ? "1" : "0"; results.push_back(r); } return results; }
QueryData genSystemInfo(QueryContext &context) { Row r; r["hostname"] = osquery::getHostname(); r["computer_name"] = r["hostname"]; std::string uuid; r["uuid"] = (osquery::getHostUUID(uuid)) ? uuid : ""; auto qd = SQL::selectAllFrom("cpuid"); for (const auto& row : qd) { if (row.at("feature") == "product_name") { r["cpu_brand"] = row.at("value"); } } // Can parse /proc/cpuinfo or /proc/meminfo for this data. static long cores = sysconf(_SC_NPROCESSORS_CONF); if (cores > 0) { r["cpu_logical_cores"] = INTEGER(cores); r["cpu_physical_cores"] = INTEGER(cores); } else { r["cpu_logical_cores"] = "-1"; r["cpu_physical_cores"] = "-1"; } static long pages = sysconf(_SC_PHYS_PAGES); static long pagesize = sysconf(_SC_PAGESIZE); if (pages > 0 && pagesize > 0) { r["physical_memory"] = BIGINT((long long)pages * (long long)pagesize); } else { r["physical_memory"] = "-1"; } r["cpu_type"] = "0"; r["cpu_subtype"] = "0"; // Read the types from CPU info within proc. std::string content; if (readFile("/proc/cpuinfo", content)) { for (const auto& line : osquery::split(content, "\n")) { // Iterate each line and look for labels (there is also a model type). if (line.find("cpu family") == 0 || line.find("model\t") == 0) { auto details = osquery::split(line, ":"); if (details.size() == 2) { // Not the most elegant but prevents us from splitting each line. r[(line[0] == 'c') ? "cpu_type" : "cpu_subtype"] = details[1]; } } } } // Will require parsing DMI/SMBIOS data. r["hardware_model"] = ""; r["hardware_serial"] = ""; return {r}; }
/** * @brief Utility method to get cumulative value for specified "op" from * child node in provided "tree". * * @param tree Tree to iterate. * @param op IO operation to look for in the child nodes. * @return Cumulative value for type "op". */ std::string getIOBytes(const pt::ptree& tree, const std::string& op) { uint64_t value = 0; for (const auto& entry : tree) { const pt::ptree& node = entry.second; if (node.get<std::string>("op", "") == op) { value += node.get<uint64_t>("value", 0); } } return BIGINT(value); }
QueryData genMounts(QueryContext& context) { QueryData results; struct statfs *mnt; int mnts = 0; int i; char real_path[PATH_MAX]; mnts = getmntinfo(&mnt, MNT_WAIT); if (mnts == 0) { // Failed to get mount informaton. return results; } for (i = 0; i < mnts; i++) { Row r; r["path"] = TEXT(mnt[i].f_mntonname); r["device"] = TEXT(mnt[i].f_mntfromname); r["device_alias"] = std::string(realpath(mnt[i].f_mntfromname, real_path) ? real_path : mnt[i].f_mntfromname); r["type"] = TEXT(mnt[i].f_fstypename); r["flags"] = INTEGER(mnt[i].f_flags); r["blocks"] = BIGINT(mnt[i].f_blocks); r["blocks_free"] = BIGINT(mnt[i].f_bfree); r["blocks_available"] = BIGINT(mnt[i].f_bavail); r["blocks_size"] = BIGINT(mnt[i].f_bsize); r["inodes"] = BIGINT(mnt[i].f_files); r["inodes_free"] = BIGINT(mnt[i].f_ffree); r["owner"] = INTEGER(mnt[i].f_owner); results.push_back(r); } return results; }
QueryData genMounts(QueryContext &context) { QueryData results; FILE *mounts; struct mntent *ent; char real_path[PATH_MAX]; struct statfs st; if ((mounts = setmntent("/proc/mounts", "r"))) { while ((ent = getmntent(mounts))) { Row r; r["device"] = std::string(ent->mnt_fsname); r["device_alias"] = std::string( realpath(ent->mnt_fsname, real_path) ? real_path : ent->mnt_fsname); r["path"] = std::string(ent->mnt_dir); r["type"] = std::string(ent->mnt_type); r["flags"] = std::string(ent->mnt_opts); if (!statfs(ent->mnt_dir, &st)) { r["blocks_size"] = BIGINT(st.f_bsize); r["blocks"] = BIGINT(st.f_blocks); r["blocks_free"] = BIGINT(st.f_bfree); r["blocks_available"] = BIGINT(st.f_bavail); r["inodes"] = BIGINT(st.f_files); r["inodes_free"] = BIGINT(st.f_ffree); } results.push_back(r); } endmntent(mounts); } return results; }
QueryData genCpuTime(QueryContext& context) { QueryData results; natural_t processor_count; processor_cpu_load_info_data_t* processor_times; mach_port_t host = mach_host_self(); mach_msg_type_number_t processor_msg_count; kern_return_t ret = host_processor_info(host, PROCESSOR_CPU_LOAD_INFO, &processor_count, reinterpret_cast<processor_info_t*>(&processor_times), &processor_msg_count); if (ret == KERN_SUCCESS) { // Loop through the cores and add rows for each core. for (unsigned int core = 0; core < processor_count; core++) { Row r; r["core"] = INTEGER(core); r["user"] = BIGINT( ticks_to_usecs(processor_times[core].cpu_ticks[CPU_STATE_USER])); r["idle"] = BIGINT( ticks_to_usecs(processor_times[core].cpu_ticks[CPU_STATE_IDLE])); r["system"] = BIGINT( ticks_to_usecs(processor_times[core].cpu_ticks[CPU_STATE_SYSTEM])); r["nice"] = BIGINT( ticks_to_usecs(processor_times[core].cpu_ticks[CPU_STATE_NICE])); results.push_back(r); } vm_deallocate( mach_task_self(), reinterpret_cast<vm_address_t>(processor_times), static_cast<vm_size_t>(processor_count * sizeof(*processor_times))); } return results; }
void genProcessMap(const std::string& pid, QueryData& results) { auto map = getProcAttr("maps", pid); std::string content; readFile(map, content); for (auto& line : osquery::split(content, "\n")) { auto fields = osquery::split(line, " "); // If can't read address, not sure. if (fields.size() < 5) { continue; } Row r; r["pid"] = pid; if (!fields[0].empty()) { auto addresses = osquery::split(fields[0], "-"); if (addresses.size() >= 2) { r["start"] = "0x" + addresses[0]; r["end"] = "0x" + addresses[1]; } else { // Problem with the address format. continue; } } r["permissions"] = fields[1]; try { auto offset = std::stoll(fields[2], nullptr, 16); r["offset"] = (offset != 0) ? BIGINT(offset) : r["start"]; } catch (const std::exception& e) { // Value was out of range or could not be interpreted as a hex long long. r["offset"] = "-1"; } r["device"] = fields[3]; r["inode"] = fields[4]; // Path name must be trimmed. if (fields.size() > 5) { boost::trim(fields[5]); r["path"] = fields[5]; } // BSS with name in pathname. r["pseudo"] = (fields[4] == "0" && !r["path"].empty()) ? "1" : "0"; results.push_back(std::move(r)); } }
QueryData genUptime(QueryContext& context) { Row r; QueryData results; long uptime_in_seconds = getUptime(); if (uptime_in_seconds >= 0) { r["days"] = INTEGER(uptime_in_seconds / 60 / 60 / 24); r["hours"] = INTEGER((uptime_in_seconds / 60 / 60) % 24); r["minutes"] = INTEGER((uptime_in_seconds / 60) % 60); r["seconds"] = INTEGER(uptime_in_seconds % 60); r["total_seconds"] = BIGINT(uptime_in_seconds); results.push_back(r); } return results; }
void genFileInfo(const std::string& path, const std::string& filename, const std::string& dir, const std::string& pattern, QueryData& results) { // Must provide the path, filename, directory separate from boost path->string // helpers to match any explicit (query-parsed) predicate constraints. struct stat file_stat, link_stat; if (lstat(path.c_str(), &link_stat) < 0 || stat(path.c_str(), &file_stat)) { // Path was not real, had too may links, or could not be accessed. return; } Row r; r["path"] = path; r["filename"] = filename; r["directory"] = dir; r["inode"] = BIGINT(file_stat.st_ino); r["uid"] = BIGINT(file_stat.st_uid); r["gid"] = BIGINT(file_stat.st_gid); r["mode"] = lsperms(file_stat.st_mode); r["device"] = BIGINT(file_stat.st_rdev); r["size"] = BIGINT(file_stat.st_size); r["block_size"] = INTEGER(file_stat.st_blksize); r["hard_links"] = INTEGER(file_stat.st_nlink); // Times r["atime"] = BIGINT(file_stat.st_atime); r["mtime"] = BIGINT(file_stat.st_mtime); r["ctime"] = BIGINT(file_stat.st_ctime); // Type booleans r["is_file"] = (!S_ISDIR(file_stat.st_mode)) ? "1" : "0"; r["is_dir"] = (S_ISDIR(file_stat.st_mode)) ? "1" : "0"; r["is_link"] = (S_ISLNK(link_stat.st_mode)) ? "1" : "0"; r["is_char"] = (S_ISCHR(file_stat.st_mode)) ? "1" : "0"; r["is_block"] = (S_ISBLK(file_stat.st_mode)) ? "1" : "0"; // pattern r["pattern"] = pattern; results.push_back(r); }
void genFDEStatusForBSDName(const std::string& bsd_name, const std::string& uuid, QueryData& results) { auto matching_dict = IOBSDNameMatching(kIOMasterPortDefault, kNilOptions, bsd_name.c_str()); if (matching_dict == nullptr) { return; } auto service = IOServiceGetMatchingService(kIOMasterPortDefault, matching_dict); if (!service) { return; } CFMutableDictionaryRef properties; if (IORegistryEntryCreateCFProperties( service, &properties, kCFAllocatorDefault, kNilOptions) != KERN_SUCCESS) { IOObjectRelease(service); return; } Row r; r["name"] = kDeviceNamePrefix + bsd_name; r["uuid"] = uuid; auto encrypted = getIOKitProperty(properties, kCoreStorageIsEncryptedKey_); if (encrypted.empty()) { r["encrypted"] = "0"; } else { r["encrypted"] = encrypted; id_t uid; uuid_string_t uuid_string = {0}; if (genUid(uid, uuid_string).ok()) { r["uid"] = BIGINT(uid); r["user_uuid"] = TEXT(uuid_string); } } r["type"] = (r.at("encrypted") == "1") ? kEncryptionType : std::string(); results.push_back(r); CFRelease(properties); IOObjectRelease(service); }
void genSMBIOSTables(const uint8_t* tables, size_t length, QueryData& results) { // Keep a pointer to the end of the SMBIOS data for comparison. auto tables_end = tables + length; auto table = tables; // Iterate through table structures within SMBIOS data range. size_t index = 0; while (table + sizeof(SMBStructHeader) <= tables_end) { auto header = (const SMBStructHeader*)table; if (table + header->length > tables_end) { // Invalid header, length must be within SMBIOS data range. break; } Row r; // The index is a supliment that keeps track of table order. r["number"] = INTEGER(index++); r["type"] = INTEGER((unsigned short)header->type); if (kSMBIOSTypeDescriptions.count(header->type) > 0) { r["description"] = kSMBIOSTypeDescriptions.at(header->type); } r["handle"] = BIGINT((unsigned long long)header->handle); r["header_size"] = INTEGER((unsigned short)header->length); // The SMBIOS structure may have unformatted, double-NULL delimited trailing // data, which are usually strings. auto next_table = table + header->length; for (; next_table + sizeof(SMBStructHeader) <= tables_end; next_table++) { if (next_table[0] == 0 && next_table[1] == 0) { next_table += 2; break; } } auto table_length = next_table - table; r["size"] = INTEGER(table_length); r["md5"] = hashFromBuffer(HASH_TYPE_MD5, table, table_length); table = next_table; results.push_back(r); } }
void genSMBIOSTable(size_t index, const SMBStructHeader* hdr, uint8_t* address, size_t size, QueryData& results) { Row r; // The index is a supliment that keeps track of table order. r["number"] = INTEGER(index++); r["type"] = INTEGER((unsigned short)hdr->type); if (kSMBIOSTypeDescriptions.count(hdr->type) > 0) { r["description"] = kSMBIOSTypeDescriptions.at(hdr->type); } else { r["description"] = "Unknown"; } r["handle"] = BIGINT((unsigned long long)hdr->handle); r["header_size"] = INTEGER((unsigned short)hdr->length); r["size"] = INTEGER(size); r["md5"] = hashFromBuffer(HASH_TYPE_MD5, address, size); results.push_back(r); }
/** * @brief Return a string representation of the RPM tag type. * * @param header A librpm header. * @param tag A librpm rpmTag_t name. * @param td A librpm rpmtd. * * Given a librpm iterator header and a requested tag name: * 1. Determine the type of the tag (the class of value). * 2. Request a const pointer or cast of numerate to that class. * 3. Lexical-cast the value for SQL. * * @return The string representation of the tag type. */ static std::string getRpmAttribute(const Header& header, rpmTag tag, const rpmtd& td) { std::string result; if (headerGet(header, tag, td, HEADERGET_DEFAULT) == 0) { // Intentional check for a 0 = failure. TLOG << "Could not get RPM header flag."; return result; } if (rpmTagGetClass(tag) == RPM_NUMERIC_CLASS) { long long int attr = rpmtdGetNumber(td); result = BIGINT(attr); } else if (rpmTagGetClass(tag) == RPM_STRING_CLASS) { const char* attr = rpmtdGetString(td); if (attr != nullptr) { result = TEXT(attr); } } return result; }
/** * @brief Entry point for docker_networks table. */ QueryData genNetworks(QueryContext& context) { std::string query; std::set<std::string> ids; getQuery(context, "id", query, ids, false); QueryData results; pt::ptree tree; Status s = dockerApi("/networks" + query, tree); if (!s.ok()) { VLOG(1) << "Error getting docker networks: " << s.what(); return results; } for (const auto& entry : tree) { try { const pt::ptree& node = entry.second; Row r; r["id"] = getValue(node, ids, "Id"); r["name"] = node.get<std::string>("Name", ""); r["driver"] = node.get<std::string>("Driver", ""); r["created"] = BIGINT(getUnixTime(node.get<std::string>("Created", ""), true)); r["enable_ipv6"] = (node.get<bool>("EnableIPv6", false) ? INTEGER(1) : INTEGER(0)); for (const auto& config : node.get_child("IPAM.Config")) { const pt::ptree& details = config.second; r["subnet"] = details.get<std::string>("Subnet", ""); r["gateway"] = details.get<std::string>("Gateway", ""); break; } results.push_back(r); } catch (const pt::ptree_error& e) { VLOG(1) << "Error getting docker network details: " << e.what(); } } return results; }
void genProcessMap(const std::string& pid, QueryData& results) { auto map = getProcAttr("maps", pid); std::string content; readFile(map, content); for (auto& line : osquery::split(content, "\n")) { auto fields = osquery::split(line, " "); Row r; r["pid"] = pid; // If can't read address, not sure. if (fields.size() < 5) { continue; } if (fields[0].size() > 0) { auto addresses = osquery::split(fields[0], "-"); r["start"] = "0x" + addresses[0]; r["end"] = "0x" + addresses[1]; } r["permissions"] = fields[1]; r["offset"] = BIGINT(std::stoll(fields[2], nullptr, 16)); r["device"] = fields[3]; r["inode"] = fields[4]; // Path name must be trimmed. if (fields.size() > 5) { boost::trim(fields[5]); r["path"] = fields[5]; } // BSS with name in pathname. r["pseudo"] = (fields[4] == "0" && r["path"].size() > 0) ? "1" : "0"; results.push_back(r); } }
void genIOKitDevice(const io_service_t& device, const io_service_t& parent, const io_name_t plane, int depth, QueryData& results) { Row r; io_name_t name, device_class; auto kr = IORegistryEntryGetName(device, name); if (kr == KERN_SUCCESS) { r["name"] = std::string(name); } // Get the device class. kr = IOObjectGetClass(device, device_class); if (kr == KERN_SUCCESS) { r["class"] = std::string(device_class); } // The entry into the registry is the ID, and is used for children as parent. uint64_t device_id, parent_id; kr = IORegistryEntryGetRegistryEntryID(device, &device_id); if (kr == KERN_SUCCESS) { r["id"] = BIGINT(device_id); } else { r["id"] = "-1"; } kr = IORegistryEntryGetRegistryEntryID(parent, &parent_id); if (kr == KERN_SUCCESS) { r["parent"] = BIGINT(parent_id); } else { r["parent"] = "-1"; } r["depth"] = INTEGER(depth); if (IORegistryEntryInPlane(device, kIODeviceTreePlane)) { io_string_t device_path; kr = IORegistryEntryGetPath(device, kIODeviceTreePlane, device_path); if (kr == KERN_SUCCESS) { // Remove the "IODeviceTree:" from the device tree path. r["device_path"] = std::string(device_path).substr(13); } } // Fill in service bits and busy/latency time. if (IOObjectConformsTo(device, "IOService")) { r["service"] = "1"; } else { r["service"] = "0"; } uint32_t busy_state; kr = IOServiceGetBusyState(device, &busy_state); if (kr == KERN_SUCCESS) { r["busy_state"] = INTEGER(busy_state); } else { r["busy_state"] = "0"; } auto retain_count = IOObjectGetKernelRetainCount(device); r["retain_count"] = INTEGER(retain_count); results.push_back(r); }
QueryData genUsers(QueryContext& context) { QueryData results; // USER_INFO_3 conains generic user information LPUSER_INFO_3 pUserBuffer = nullptr; DWORD dwGenericUserLevel = 3; DWORD dwPreferredMaxLength = MAX_PREFERRED_LENGTH; DWORD dwEntriesRead = 0; DWORD dwTotalEntries = 0; DWORD dwResumeHandle = 0; NET_API_STATUS nEnumStatus; nEnumStatus = NetUserEnum(nullptr, dwGenericUserLevel, FILTER_NORMAL_ACCOUNT, (LPBYTE*)&pUserBuffer, dwPreferredMaxLength, &dwEntriesRead, &dwTotalEntries, &dwResumeHandle); // We save the original pointer to the USER_INFO_3 buff for mem management LPUSER_INFO_3 pUserIterationBuffer = pUserBuffer; if (pUserIterationBuffer == nullptr || nEnumStatus != NERR_Success) { if (pUserBuffer != nullptr) { NetApiBufferFree(pUserBuffer); } return results; } for (DWORD i = 0; i < dwEntriesRead; i++) { Row r; r["username"] = wstringToString(pUserIterationBuffer->usri3_name); r["description"] = wstringToString(pUserIterationBuffer->usri3_comment); r["uid"] = BIGINT(pUserIterationBuffer->usri3_user_id); r["gid"] = BIGINT(pUserIterationBuffer->usri3_primary_group_id); r["uid_signed"] = r["uid"]; r["gid_signed"] = r["gid"]; r["shell"] = "C:\\Windows\\system32\\cmd.exe"; // USER_INFO_23 contains detailed info, like the user Sid DWORD dwDetailedUserLevel = 23; LPUSER_INFO_23 pSidUserBuffer = nullptr; NET_API_STATUS nStatus; nStatus = NetUserGetInfo(nullptr, pUserIterationBuffer->usri3_name, dwDetailedUserLevel, (LPBYTE*)&pSidUserBuffer); if (nStatus != NERR_Success) { if (pSidUserBuffer != nullptr) { NetApiBufferFree(pSidUserBuffer); pSidUserBuffer = nullptr; } continue; } LPTSTR sStringSid = nullptr; auto ret = ConvertSidToStringSid(pSidUserBuffer->usri23_user_sid, &sStringSid); if (ret == 0) { if (pSidUserBuffer != nullptr) { NetApiBufferFree(pSidUserBuffer); } continue; } r["uuid"] = sStringSid; std::string query = "SELECT LocalPath FROM Win32_UserProfile where SID=\"" + std::string(sStringSid) + "\""; WmiRequest wmiRequest(query); std::vector<WmiResultItem>& wmiResults = wmiRequest.results(); if (wmiResults.size() != 0) { wmiResults[0].GetString("LocalPath", r["directory"]); } LocalFree(sStringSid); NetApiBufferFree(pSidUserBuffer); results.push_back(r); pUserIterationBuffer++; } NetApiBufferFree(pUserBuffer); if (nEnumStatus == ERROR_MORE_DATA) { LOG(WARNING) << "NetUserEnum contains more data: users table may be incomplete"; } return results; }