Exercise 3: TCPdump

  任务是 fuzz TCPdump 4.9.2,获得 CVE-2017-13028 漏洞。这是一个越界读取 bug。

0x01 环境准备

  在这里找到:TCPdump 4.9.2 版本:

Index of /release

  按照 AFL 文档关于使用 ASan 的指引,我们在 32bit 模式下编译。考虑到在一个现有的 debian 系统上添加 i386 架构会面临依赖问题,我们在 docker 中编译 tcpdump:

» docker run --rm -it -v /work:/work afl:20221001 /bin/bash

[afl++ d82435966df4] /work/src/libpcap-1.8.1> export CC=afl-clang-lto
[afl++ d82435966df4] /work/src/libpcap-1.8.1> export CFLAGS="-m32"
[afl++ d82435966df4] /work/src/libpcap-1.8.1> export LDFLAGS="-m32"
[afl++ d82435966df4] /work/src/libpcap-1.8.1> export AFL_USE_ASAN=1
[afl++ d82435966df4] /work/src/libpcap-1.8.1> ./configure
[afl++ d82435966df4] /work/src/libpcap-1.8.1> make
# [+] Instrumented 40265 locations (636 selects) without collisions  (10182 collisions have been avoided) (non-hardened, ASAN mode).


[afl++ d82435966df4] /work/src/tcpdump-4.9.2> ./configure 
[afl++ d82435966df4] /work/src/tcpdump-4.9.2> make 
# [+] Instrumented 117445 locations (3453 selects) without collisions (62828 collisions have been avoided) (non-hardened, ASAN mode).


[afl++ d82435966df4] /work/src/tcpdump-4.9.2> file tcpdump
tcpdump: ELF 32-bit LSB pie executable, Intel 80386, 
version 1 (SYSV), dynamically linked, 
interpreter /lib/ld-linux.so.2, 
for GNU/Linux 3.2.0, 
BuildID[xxHash]=50fa5ecc3b933075, 
with debug_info, not stripped

[afl++ d82435966df4] /work/src/tcpdump-4.9.2> ldd ./tcpdump
	linux-gate.so.1 (0xf7f9b000)
	libm.so.6 => /lib32/libm.so.6 (0xf68f8000)
	libgcc_s.so.1 => /lib32/libgcc_s.so.1 (0xf7f68000)
	libc.so.6 => /lib32/libc.so.6 (0xf66c7000)
	/lib/ld-linux.so.2 (0xf7f9d000)


» ./tcpdump -h
tcpdump version 4.9.2
libpcap version 1.8.1
Compiled with AddressSanitizer/CLang.
Usage: tcpdump [-aAbdDefhHIJKlLnNOpqStuUvxX#] [ -B size ] [ -c count ]
		[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]
		[ -i interface ] [ -j tstamptype ] [ -M secret ] [ --number ]
		[ -Q in|out|inout ]
		[ -r file ] [ -s snaplen ] [ --time-stamp-precision precision ]
		[ --immediate-mode ] [ -T type ] [ --version ] [ -V file ]
		[ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z postrotate-command ]
		[ -Z user ] [ expression ]

  编译完成。

0x02 fuzz

  首先,我们很难以去 fuzz TCPdump “从网卡上抓包”这个功能。注意到 TCPdump 可以从 pcap 文件中读取报文,我们考虑由此入手进行 fuzz。

  从 exercise 1 的经验,我们应当准备一个足够多样的 seed corpus。可以考虑 TCPdump 自身的测试用例(371 个),以及 wireshark 的测试用例(52 个)。

tcpdump/tests at master · the-tcpdump-group/tcpdump
the TCPdump network dissector. Contribute to the-tcpdump-group/tcpdump development by creating an account on GitHub.
wireshark/test/captures at master · wireshark/wireshark
Read-only mirror of Wireshark's Git repository at https://gitlab.com/wireshark/wireshark. GitHub won't let us disable pull requests. ☞ THEY WILL BE IGNORED HERE ☜ Please upload them at GitL...

  tests 中 pcap 文件的例子:

  很多测试用例需要比较长的时间(>1s)执行,产生报错。我们可以通过 -t 选项指定超时时间。此外,AFL 报告称 seed corpus 太大了

» AFL_TMPDIR=/tmp /afl/afl-fuzz -s 123 -i /work/corpus -o /work/output -t 200  -- ./tcpdump -r @@
▲ 若超时设置为 1000ms,fuzz 效率很低
▲ 超时设置为 20ms,效率可以接受

   我们将超时时间设为 200ms,然后 fuzz 一晚上。

  笑死,一晚上啥也没跑出来。疑似是出问题了。查阅 solution,发现:

  1. 官方题解采用的是 libpcap 1.8.0 而非我们使用的 1.8.1,还要求选手使用的版本与其一致。
    然而,tcpdump 4.9.2 发布于 2017 年 9 月 3 日,与之最接近的 libpcap release 是 2016 年 10 月 25 日的 libpcap 1.8.1;何以舍弃更近的 1.8.1 而选择连 release note 都没有的 1.8.0,笔者蒙在鼓里。
  2. 官方题解直接在 64bit 系统上编译运行了 64bit 的程序,没有额外的内存限制措施。按照 AFL++ 文档的话,这样做有 Out Of Memory 的风险。
  3. 官方题解采用的 tcpdump 参数是 -vvvvXX -ee -nn -r,也就是尽量输出更多的内容。思考之后认为很有道理,因为越多的输出可以经过越多的基本块;此外,可能有某些分析逻辑只有在输出更多内容时才会启用。

  笔者选择先执行第三条,采用 -vvv -XX -en 来运行。

  仍然没有什么希望。笔者选择将 libpcap 从 1.8.1 降到 1.8.0,但仍然在 32bit 编译。

  再次尝试 fuzz。1h 出结果。

  跑了一晚上,78 个 unique crash:

0x03 分析

  在 PC 上先编译。指令:

export CFLAGS="-fsanitize=address -O0 -g"
export CC=clang-14
./configure
make

  复现第一个 crash:

	................
	subtype GET_IP_MASK_REQUEST, index 3
	version 1.0, type VENDOR, length 12062, xid 0x00000020, vendor 0x005c16c7 (Big Switch Networks)
=================================================================
==9758==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61100000013f at pc 0x5567c7c178a7 bp 0x7ffd8849a6b0 sp 0x7ffd8849a6a8
READ of size 1 at 0x61100000013f thread T0
    #0 0x5567c7c178a6 in fn_printn /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./util-print.c:185:7
    #1 0x5567c7b55904 in of10_bsn_message_print /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print-openflow-1.0.c:899:7
    #2 0x5567c7b4f35a in of10_vendor_message_print /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print-openflow-1.0.c:1081:9
    #3 0x5567c7b4b235 in of10_header_body_print /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print-openflow-1.0.c:2488:10
    #4 0x5567c7b5f5a1 in of_header_body_print /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print-openflow.c:116:10
    #5 0x5567c7b5f0bd in openflow_print /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print-openflow.c:141:8
    #6 0x5567c7bfa381 in tcp_print /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print-tcp.c:705:17
    #7 0x5567c7abc5e1 in ip_print_demux /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print-ip.c:396:3
    #8 0x5567c7abfbb4 in ip_print /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print-ip.c:673:3
    #9 0x5567c7a8ae35 in ethertype_print /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print-ether.c:333:10
    #10 0x5567c7a8a648 in ether_print /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print-ether.c:236:7
    #11 0x5567c7a8b34c in ether_if_print /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print-ether.c:261:10
    #12 0x5567c7a0421f in pretty_print_packet /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./print.c:332:18
    #13 0x5567c79efcd8 in print_packet /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./tcpdump.c:2497:2
    #14 0x5567c7c72fd3 in pcap_offline_read /home/blue/Desktop/workspace/current/src/libpcap-1.8.0/./savefile.c:523:4
    #15 0x5567c7c3121e in pcap_loop /home/blue/Desktop/workspace/current/src/libpcap-1.8.0/./pcap.c:904:8
    #16 0x5567c79eb85a in main /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./tcpdump.c:2000:12
    #17 0x7f8c52921d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #18 0x7f8c52921e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #19 0x5567c7929824 in _start (/home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/tcpdump+0x1ee824) (BuildId: 24bd888f8773a09fab384a6b0a20e4199112db1f)

0x61100000013f is located 0 bytes to the right of 255-byte region [0x611000000040,0x61100000013f)
allocated by thread T0 here:
    #0 0x5567c79ac66e in malloc (/home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/tcpdump+0x27166e) (BuildId: 24bd888f8773a09fab384a6b0a20e4199112db1f)
    #1 0x5567c7c756de in pcap_check_header /home/blue/Desktop/workspace/current/src/libpcap-1.8.0/./sf-pcap.c:401:14
    #2 0x5567c7c7262b in pcap_fopen_offline_with_tstamp_precision /home/blue/Desktop/workspace/current/src/libpcap-1.8.0/./savefile.c:396:7
    #3 0x5567c7c722c1 in pcap_open_offline_with_tstamp_precision /home/blue/Desktop/workspace/current/src/libpcap-1.8.0/./savefile.c:303:6
    #4 0x5567c79ea64b in main /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./tcpdump.c:1612:8
    #5 0x7f8c52921d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/blue/Desktop/workspace/current/src/tcpdump-4.9.2/./util-print.c:185:7 in fn_printn
Shadow bytes around the buggy address:
  0x0c227fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c227fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c227fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c227fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c227fff8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c227fff8020: 00 00 00 00 00 00 00[07]fa fa fa fa fa fa fa fa
  0x0c227fff8030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c227fff8040: 00 00 00 00 00 00 00 00 00 00 00 fa fa fa fa fa
  0x0c227fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c227fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c227fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==9758==ABORTING

  有趣的是,如果不带 -v 执行这个用例,那么不会产生 crash。