mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 18:08:53 +00:00
parent
b63b60e967
commit
602f413950
@ -8,21 +8,19 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma comment(lib, "netapi32.lib")
|
||||
|
||||
#define _WIN32_DCOM
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
// clang-format off
|
||||
#include <LM.h>
|
||||
// clang-format on
|
||||
#include <Shlobj.h>
|
||||
|
||||
#include <osquery/core.h>
|
||||
#include <osquery/tables.h>
|
||||
#include <osquery/logger.h>
|
||||
|
||||
#include "osquery/core/windows/wmi.h"
|
||||
#include "osquery/core/conversions.h"
|
||||
|
||||
namespace osquery {
|
||||
namespace tables {
|
||||
@ -30,89 +28,76 @@ namespace tables {
|
||||
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);
|
||||
}
|
||||
WmiRequest req("select * from Win32_UserProfile");
|
||||
if (!req.getStatus().ok()) {
|
||||
return results;
|
||||
}
|
||||
|
||||
for (DWORD i = 0; i < dwEntriesRead; i++) {
|
||||
auto& wmiResults = req.results();
|
||||
for (const auto& res : wmiResults) {
|
||||
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;
|
||||
std::string sidString;
|
||||
res.GetString("LocalPath", r["directory"]);
|
||||
res.GetString("SID", sidString);
|
||||
r["uuid"] = sidString;
|
||||
|
||||
PSID sid;
|
||||
auto ret = ConvertStringSidToSidA(sidString.c_str(), &sid);
|
||||
if (ret == 0) {
|
||||
TLOG << "Convert SID to string failed with: " << GetLastError();
|
||||
}
|
||||
|
||||
wchar_t accntName[UNLEN] = {0};
|
||||
wchar_t domName[DNLEN] = {0};
|
||||
unsigned long accntNameLen = UNLEN;
|
||||
unsigned long domNameLen = DNLEN;
|
||||
SID_NAME_USE eUse;
|
||||
|
||||
/// MSDN guaruntees the string values returned is null terminated.
|
||||
ret = LookupAccountSidW(
|
||||
nullptr, sid, accntName, &accntNameLen, domName, &domNameLen, &eUse);
|
||||
if (ret != 0) {
|
||||
r["username"] = wstringToString(accntName);
|
||||
} else {
|
||||
TLOG << "Lookup Account by SID failed with: " << GetLastError();
|
||||
}
|
||||
|
||||
/// USER_INFO_3 contains detailed info, like the uid
|
||||
unsigned long dwDetailedUserLevel = 3;
|
||||
LPUSER_INFO_3 pUserInfoBuffer = nullptr;
|
||||
|
||||
NET_API_STATUS nStatus;
|
||||
nStatus = NetUserGetInfo(nullptr,
|
||||
pUserIterationBuffer->usri3_name,
|
||||
accntName,
|
||||
dwDetailedUserLevel,
|
||||
(LPBYTE*)&pSidUserBuffer);
|
||||
if (nStatus != NERR_Success) {
|
||||
if (pSidUserBuffer != nullptr) {
|
||||
NetApiBufferFree(pSidUserBuffer);
|
||||
pSidUserBuffer = nullptr;
|
||||
reinterpret_cast<LPBYTE*>(&pUserInfoBuffer));
|
||||
|
||||
if (nStatus == NERR_Success) {
|
||||
r["uid"] = INTEGER(pUserInfoBuffer->usri3_user_id);
|
||||
r["uid_signed"] = INTEGER(pUserInfoBuffer->usri3_user_id);
|
||||
r["gid"] = INTEGER(pUserInfoBuffer->usri3_primary_group_id);
|
||||
r["gid_signed"] = INTEGER(pUserInfoBuffer->usri3_primary_group_id);
|
||||
r["description"] =
|
||||
SQL_TEXT(wstringToString(pUserInfoBuffer->usri3_comment));
|
||||
} else {
|
||||
/// If NetUserGetInfo fails parse the uid manually
|
||||
auto sidTokens = osquery::split(sidString, "-");
|
||||
if (sidTokens.size() == 8) {
|
||||
r["uid"] = INTEGER(sidTokens.back());
|
||||
r["uid_signed"] = INTEGER(sidTokens.back());
|
||||
}
|
||||
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);
|
||||
|
||||
/// Note: there may be a way to get the users prefered shell
|
||||
r["shell"] = "C:\\Windows\\system32\\cmd.exe";
|
||||
results.push_back(r);
|
||||
pUserIterationBuffer++;
|
||||
}
|
||||
NetApiBufferFree(pUserBuffer);
|
||||
|
||||
if (nEnumStatus == ERROR_MORE_DATA) {
|
||||
LOG(WARNING)
|
||||
<< "NetUserEnum contains more data: users table may be incomplete";
|
||||
if (pUserInfoBuffer != nullptr) {
|
||||
NetApiBufferFree(pUserInfoBuffer);
|
||||
pUserInfoBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user