表題の通り CVE-2017-18017 の PoC を書いてどのような影響があるのを検証・観察した
⚠️
一年以上前に修正パッチが出ている CVE です
CVE の Description
The tcpmss_mangle_packet function in net/netfilter/xt_TCPMSS.c in the Linux kernel before 4.11, and 4.9.x before 4.9.36, allows remote attackers to cause a denial of service (use-after-free and memory corruption) or possibly have unspecified other impact by leveraging the presence of xt_TCPMSS in an iptables action.
iptables で TCPMSS ターゲット ( --set-mss
または --clamp-mss-to-pmtu
) を使っているホストに、細工した TCPヘッダを投げつけると use-after-free やメモリの破壊等々が起こせる
CVSS3 の Base Score が 9.8 と高い 🔥
修正パッチ
パッチは以下の通りです
From 2638fd0f92d4397884fd991d8f4925cb3f081901 Mon Sep 17 00:00:00 2001 From: Eric Dumazet <edumazet@google.com> Date: Mon, 3 Apr 2017 10:55:11 -0700 Subject: netfilter: xt_TCPMSS: add more sanity tests on tcph->doff Denys provided an awesome KASAN report pointing to an use after free in xt_TCPMSS I have provided three patches to fix this issue, either in xt_TCPMSS or in xt_tcpudp.c. It seems xt_TCPMSS patch has the smallest possible impact. Signed-off-by: Eric Dumazet <edumazet@google.com> Reported-by: Denys Fedoryshchenko <nuclearcat@nuclearcat.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- net/netfilter/xt_TCPMSS.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 27241a767f17..c64aca611ac5 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -104,7 +104,7 @@ tcpmss_mangle_packet(struct sk_buff *skb, tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); tcp_hdrlen = tcph->doff * 4; - if (len < tcp_hdrlen) + if (len < tcp_hdrlen || tcp_hdrlen < sizeof(struct tcphdr)) return -1; if (info->mss == XT_TCPMSS_CLAMP_PMTU) { @@ -152,6 +152,10 @@ tcpmss_mangle_packet(struct sk_buff *skb, if (len > tcp_hdrlen) return 0; + /* tcph->doff has 4 bits, do not wrap it to 0 */ + if (tcp_hdrlen >= 15 * 4) + return 0; + /* * MSS Option not found ?! add it.. */ -- cgit 1.2-0.3.lf.el7
分析 🔎
tcp_hdrlen
のサイズを任意に細工したTCPセグメントを送りつけると、パッチで修正した箇所のコードを通過して不具合を再現できると推測がつく- TCP ヘッダの仕様をぜんぜん覚えてなかなったので、復習し直しながら SOCK_RAW のソケットで試した
CVE の PoC
リモート攻撃が容易に可能となる PoC なので非公開 (いつも非公開ですいません)
再現
修正パッチを読むと「 KASAN = Kernel Address Sanitizer を使って use-after-free を検知した」とあったので、v4.9.35 で CONFIG_KASAN を有効にしたカーネルで PoC を実行して、KASAN のログを出す事で再現をとったものとする
iptables の設定をあれこれすれば、VM 一台で再現が可能。細工したTCPセグメントを一つ飛ばすだけで KASAN のログがわらわらと出た
[ 60.958790] BUG: KASAN: use-after-free in tcpmss_mangle_packet+0x2aa/0x920 [xt_TCPMSS] at addr ffff880067f72002 [ 60.969337] Read of size 1 by task ****/1167 [ 60.975820] Object at ffff880067f72000, in cache vm_area_struct size: 192 👈 ( kmalloc-32 や kmalloc-128 が出ているログもあった ) [ 60.989569] Allocated: [ 60.994387] PID = 1101 [ 61.000590] Freed: [ 61.003538] PID = 1102 [ 61.005466] Memory state around the buggy address: [ 61.010213] ffff880067f71f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 61.016000] ffff880067f71f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 61.024256] >ffff880067f72000: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 61.029370] ^ [ 61.032932] ffff880067f72080: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc [ 61.040788] ffff880067f72100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 61.048892] ==================================================================
slab-out-of-bounds も同時に検知していた
Sep 28 10:37:20 localhost kernel: BUG: KASAN: slab-out-of-bounds in tcpmss_mangle_packet+0x283/0x920 [xt_TCPMSS] at addr ffff880064660e80 Sep 28 10:37:20 localhost kernel: Read of size 1 by task ****/1174 Sep 28 10:37:20 localhost kernel: CPU: 3 PID: 1174 Comm: **** Tainted: G O 4.9.35 #4 Sep 28 10:37:20 localhost kernel: Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 Sep 28 10:37:20 localhost kernel: ffff880064e0f338 ffffffff8a11dd06 ffff88006a003080 ffff880064660c80 Sep 28 10:37:20 localhost kernel: ffff880064e0f360 ffffffff89f03ce1 ffffed000c8cc1d0 ffff88006a003080 Sep 28 10:37:20 localhost kernel: 0000000000000000 ffff880064e0f3e8 ffffffff89f03f8a ffffffff8aca6e03 Sep 28 10:37:20 localhost kernel: Call Trace: Sep 28 10:37:20 localhost kernel: [<ffffffff8a11dd06>] dump_stack+0x63/0x8d Sep 28 10:37:20 localhost kernel: [<ffffffff89f03ce1>] kasan_object_err+0x21/0x70 Sep 28 10:37:20 localhost kernel: [<ffffffff89f03f8a>] kasan_report.part.1+0x20a/0x4f0 Sep 28 10:37:20 localhost kernel: [<ffffffff89e64279>] ? pm_qos_get_value.part.5+0x6/0x6 Sep 28 10:37:20 localhost kernel: [<ffffffffc08c8393>] ? tcpmss_mangle_packet+0x283/0x920 [xt_TCPMSS] 🔥 Sep 28 10:37:20 localhost kernel: [<ffffffff89f03043>] ? save_stack+0xa3/0xd0 Sep 28 10:37:20 localhost kernel: [<ffffffff89f045a6>] kasan_report+0x26/0x30 Sep 28 10:37:20 localhost kernel: [<ffffffff89f02997>] __asan_load1+0x47/0x50 Sep 28 10:37:20 localhost kernel: [<ffffffffc08c8393>] tcpmss_mangle_packet+0x283/0x920 [xt_TCPMSS] Sep 28 10:37:20 localhost kernel: [<ffffffff8a625521>] ? inet_sendmsg+0xe1/0x130 Sep 28 10:37:20 localhost kernel: [<ffffffffc08c8110>] ? tcpmss_tg4_check+0x110/0x110 [xt_TCPMSS] Sep 28 10:37:20 localhost kernel: [<ffffffff8a71e46b>] ? entry_SYSCALL64_slow_path+0x25/0x25 Sep 28 10:37:20 localhost kernel: [<ffffffff8a5ae35a>] ? tcp_mt+0x2ca/0x530 Sep 28 10:37:20 localhost kernel: [<ffffffff89c4ff02>] ? __mcheck_cpu_init_generic+0xd2/0xf0 Sep 28 10:37:20 localhost kernel: [<ffffffff8a5ae090>] ? udp_mt_check+0x40/0x40 Sep 28 10:37:20 localhost kernel: [<ffffffff8a558280>] ? dst_alloc+0x90/0xd0 Sep 28 10:37:20 localhost kernel: [<ffffffff8a5af254>] ? rt_dst_alloc+0x54/0x1b0 Sep 28 10:37:20 localhost kernel: [<ffffffff8a5b2ba4>] ? __ip_route_output_key_hash+0x684/0x1110 Sep 28 10:37:20 localhost kernel: [<ffffffff8a5b3c53>] ? ip_route_output_flow+0x23/0x60 Sep 28 10:37:20 localhost kernel: [<ffffffff8a60a8ec>] ? raw_sendmsg+0x61c/0x1180 Sep 28 10:37:20 localhost kernel: [<ffffffff8a625521>] ? inet_sendmsg+0xe1/0x130 Sep 28 10:37:20 localhost kernel: [<ffffffff8a517354>] ? sock_sendmsg+0x74/0x80 Sep 28 10:37:20 localhost kernel: [<ffffffff8a517d3f>] ? SYSC_sendto+0x22f/0x270 Sep 28 10:37:20 localhost kernel: [<ffffffff8a518ede>] ? SyS_sendto+0xe/0x10 Sep 28 10:37:20 localhost kernel: [<ffffffff89c03803>] ? do_syscall_64+0xe3/0x230 Sep 28 10:37:20 localhost kernel: [<ffffffff8a71e46b>] ? entry_SYSCALL64_slow_path+0x25/0x25 Sep 28 10:37:20 localhost kernel: [<ffffffffc08c8a9f>] tcpmss_tg4+0x6f/0x10e [xt_TCPMSS] Sep 28 10:37:20 localhost kernel: [<ffffffffc06c99ca>] ipt_do_table+0x67a/0x790 [ip_tables] Sep 28 10:37:20 localhost kernel: [<ffffffffc06c9350>] ? ip_tables_net_init+0x20/0x20 [ip_tables] Sep 28 10:37:20 localhost kernel: [<ffffffffc06c984f>] ? ipt_do_table+0x4ff/0x790 [ip_tables] Sep 28 10:37:20 localhost kernel: [<ffffffffc0798060>] ? iptable_mangle_net_exit+0x60/0x60 [iptable_mangle] Sep 28 10:37:20 localhost kernel: [<ffffffffc07980b4>] iptable_mangle_hook+0x54/0x210 [iptable_mangle] Sep 28 10:37:20 localhost kernel: [<ffffffffc0798060>] ? iptable_mangle_net_exit+0x60/0x60 [iptable_mangle] Sep 28 10:37:20 localhost kernel: [<ffffffff8a5a4840>] nf_iterate+0xb0/0xd0 Sep 28 10:37:20 localhost kernel: [<ffffffff8a5a4923>] nf_hook_slow+0xc3/0x140 Sep 28 10:37:20 localhost kernel: [<ffffffff8a5a4860>] ? nf_iterate+0xd0/0xd0 Sep 28 10:37:20 localhost kernel: [<ffffffffc0798253>] ? iptable_mangle_hook+0x1f3/0x210 [iptable_mangle] Sep 28 10:37:20 localhost kernel: [<ffffffff8a5c3215>] ip_output+0x1c5/0x1e0 Sep 28 10:37:20 localhost kernel: [<ffffffff8a5c3050>] ? ip_mc_output+0x490/0x490 Sep 28 10:37:20 localhost kernel: [<ffffffff8a5c1c10>] ? __ip_flush_pending_frames.isra.45+0x120/0x120 Sep 28 10:37:20 localhost kernel: [<ffffffff8a60b084>] raw_sendmsg+0xdb4/0x1180 Sep 28 10:37:20 localhost kernel: [<ffffffff8a60a2d0>] ? compat_raw_getsockopt+0x70/0x70 Sep 28 10:37:20 localhost kernel: [<ffffffff89ccfb0d>] ? SYSC_kill+0x15d/0x300 Sep 28 10:37:20 localhost kernel: [<ffffffff89c03803>] ? do_syscall_64+0xe3/0x230 Sep 28 10:37:20 localhost kernel: [<ffffffff8a71e46b>] ? entry_SYSCALL64_slow_path+0x25/0x25 Sep 28 10:37:20 localhost kernel: [<ffffffff89f033e5>] ? memcpy+0x45/0x50 Sep 28 10:37:20 localhost kernel: [<ffffffff8a29bb58>] ? tty_insert_flip_string_fixed_flag+0xa8/0x110 Sep 28 10:37:20 localhost kernel: [<ffffffff8a29b6f3>] ? tty_flip_buffer_push+0x63/0x70 Sep 28 10:37:20 localhost kernel: [<ffffffff89f038b9>] ? kasan_slab_free+0x89/0xc0 Sep 28 10:37:20 localhost kernel: [<ffffffff8a609010>] ? ip4_datagram_connect+0x50/0x50 Sep 28 10:37:20 localhost kernel: [<ffffffff89f1893c>] ? lock_page_memcg+0x2c/0xc0 Sep 28 10:37:20 localhost kernel: [<ffffffff89f173cb>] ? unlock_page_memcg+0x2b/0x80 Sep 28 10:37:20 localhost kernel: [<ffffffff89d2b310>] ? __wake_up_bit+0x80/0xe0 Sep 28 10:37:20 localhost kernel: [<ffffffff89d2b290>] ? init_wait_entry+0x70/0x70 Sep 28 10:37:20 localhost kernel: [<ffffffff89e66a4f>] ? unlock_page+0x3f/0x50 Sep 28 10:37:20 localhost kernel: [<ffffffff8a625521>] inet_sendmsg+0xe1/0x130 Sep 28 10:37:20 localhost kernel: [<ffffffff8a625440>] ? inet_recvmsg+0x1d0/0x1d0 Sep 28 10:37:20 localhost kernel: [<ffffffff8a517354>] sock_sendmsg+0x74/0x80 Sep 28 10:37:20 localhost kernel: [<ffffffff8a517d3f>] SYSC_sendto+0x22f/0x270 Sep 28 10:37:20 localhost kernel: [<ffffffff8a517b10>] ? SYSC_connect+0x220/0x220 Sep 28 10:37:20 localhost kernel: [<ffffffff89ebc427>] ? handle_mm_fault+0x447/0x1cb0 Sep 28 10:37:20 localhost kernel: [<ffffffff89ccf835>] ? group_send_sig_info+0x35/0x40 Sep 28 10:37:20 localhost kernel: [<ffffffff89c02510>] ? exit_to_usermode_loop+0xc0/0xc0 Sep 28 10:37:20 localhost kernel: [<ffffffff89c86be2>] ? __do_page_fault+0x552/0x610 Sep 28 10:37:20 localhost kernel: [<ffffffff8a518ed0>] ? SyS_getpeername+0x10/0x10 Sep 28 10:37:20 localhost kernel: [<ffffffff8a518ede>] SyS_sendto+0xe/0x10 Sep 28 10:37:20 localhost kernel: [<ffffffff89c03803>] do_syscall_64+0xe3/0x230 Sep 28 10:37:20 localhost kernel: [<ffffffff8a71e46b>] entry_SYSCALL64_slow_path+0x25/0x25 Sep 28 10:37:20 localhost kernel: Object at ffff880064660c80, in cache kmalloc-512 size: 512 Sep 28 10:37:20 localhost kernel: Allocated: Sep 28 10:37:20 localhost kernel: PID = 1174 Sep 28 10:37:20 localhost kernel: save_stack_trace+0x1b/0x20 Sep 28 10:37:20 localhost kernel: save_stack+0x43/0xd0 Sep 28 10:37:20 localhost kernel: kasan_kmalloc+0xad/0xe0 Sep 28 10:37:20 localhost kernel: kasan_slab_alloc+0x12/0x20 Sep 28 10:37:20 localhost kernel: __kmalloc_node_track_caller+0x153/0x260 Sep 28 10:37:20 localhost kernel: __kmalloc_reserve.isra.38+0x31/0xa0 Sep 28 10:37:20 localhost kernel: __alloc_skb+0xe0/0x330 Sep 28 10:37:20 localhost kernel: alloc_skb_with_frags+0x7a/0x2a0 Sep 28 10:37:20 localhost kernel: sock_alloc_send_pskb+0x3ce/0x410 Sep 28 10:37:20 localhost kernel: sock_alloc_send_skb+0x18/0x20 Sep 28 10:37:20 localhost kernel: raw_sendmsg+0x9b0/0x1180 Sep 28 10:37:20 localhost kernel: inet_sendmsg+0xe1/0x130 Sep 28 10:37:20 localhost kernel: sock_sendmsg+0x74/0x80 Sep 28 10:37:20 localhost kernel: SYSC_sendto+0x22f/0x270 Sep 28 10:37:20 localhost kernel: SyS_sendto+0xe/0x10 Sep 28 10:37:20 localhost kernel: do_syscall_64+0xe3/0x230 Sep 28 10:37:20 localhost kernel: return_from_SYSCALL_64+0x0/0x6a Sep 28 10:37:20 localhost kernel: Freed: Sep 28 10:37:20 localhost kernel: PID = 642 Sep 28 10:37:20 localhost kernel: save_stack_trace+0x1b/0x20 Sep 28 10:37:20 localhost kernel: save_stack+0x43/0xd0 Sep 28 10:37:20 localhost kernel: kasan_slab_free+0x73/0xc0 Sep 28 10:37:20 localhost kernel: kfree+0x93/0x1a0 Sep 28 10:37:20 localhost kernel: vt_do_kdsk_ioctl+0x1d4/0x4e0 Sep 28 10:37:20 localhost kernel: vt_ioctl+0x14e3/0x18c0 Sep 28 10:37:20 localhost kernel: tty_ioctl+0x3c1/0x11f0 Sep 28 10:37:20 localhost kernel: do_vfs_ioctl+0x144/0x970 Sep 28 10:37:20 localhost kernel: SyS_ioctl+0x79/0x90 Sep 28 10:37:20 localhost kernel: do_syscall_64+0xe3/0x230 Sep 28 10:37:20 localhost kernel: return_from_SYSCALL_64+0x0/0x6a Sep 28 10:37:20 localhost kernel: Memory state around the buggy address: Sep 28 10:37:20 localhost kernel: ffff880064660d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Sep 28 10:37:20 localhost kernel: ffff880064660e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Sep 28 10:37:20 localhost kernel: >ffff880064660e80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc Sep 28 10:37:20 localhost kernel: ^ Sep 28 10:37:20 localhost kernel: ffff880064660f00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb Sep 28 10:37:20 localhost kernel: ffff880064660f80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
やったね J( 'ー`)し kasan
感想
- リモートから攻撃されうる CVE ≒ ネットワークスタックに苦手意識があったので、修正パッチサイズが小さいものを選び出して試行錯誤していたが、非常に勉強になった。
- 具体的には、RAW ソケット や TCP や IP の理解が足りなかったのでヘッダの意味を調べたり、任意の値に改変して送信する方法を既存の実装から探ったりしていた
- KASAN の強力さも理解できた。別の use-after-free や out-of-bounds の再現をする際にも使ってみよう
TCPMSS の --set-mss や --clamp-mss-to-pmtu の経験値がゼロなのだが、Path MTU Discovery を解決するものとあるので Linux でルータを構成してたりすると使うものなのかな? ここら、詳しい人いたら助言が欲しいところ