[Fuzzing101] Exercise 5 - honggfuzz

Sisyphus·2024년 11월 26일

Fuzzing101

목록 보기
6/7

기존에 AFLplusplus 로는 libxml2 에서 크래시를 제대로 탐지하지 못했습니다. 그래서 honggfuzz 를 이용하여 다시 퍼징을 시도하게 되었습니다.

Install hongfuzz

sudo apt-get update
sudo apt-get install binutils-dev
sudo apt-get install libunwind-dev
git clone https://github.com/google/honggfuzz.git
cd honggfuzz
sudo make install


Build libxml2

Download

cd $HOME
mkdir Fuzzing_libxml2 && cd Fuzzing_libxml2
wget http://xmlsoft.org/download/libxml2-2.9.4.tar.gz
tar xvf libxml2-2.9.4.tar.gz && cd libxml2-2.9.4/

Build

sudo apt-get install python-dev
CC=hfuzz-clang CXX=hfuzz-clang++ CFLAGS="-fsanitize=address" CXXFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address" ./configure --prefix="$HOME/Fuzzing_libxml2/libxml2-2.9.4/install" --disable-shared --without-debug --without-ftp --without-http --without-legacy --without-python LIBS='-ldl'
make -j$(nproc)
make install

Test

./xmllint --memory ./test/wml.xml
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
  <card id="card1" title="Rubriques 75008">
        <p>
                <a href="rubmenu.asp?CP=75008&amp;RB=01">Cin&#xE9;ma</a><br/>
        </p>

</card>
</wml>


Fuzzing

Seed corpus

mkdir corpus && cd corpus
s=$(printf "%-757s" "0")
t=$(printf "%-4924s" "0")
echo '<!DOCTYPEa[<!ELEMENT a (F'"${s// /0}:${t// /0}"')><!ATTLIST a><!ELEMENT b EMPTY><!ATTLIST b s CDATA #IMPLIED>]><a/>' > bug1.xml
cd ..
  • 기존에는 Fuzzing101에서 제공하는 기본 Seed 파일을 사용하였는데, Null Pointer Exception 만 탐지될 뿐 Stack Overflow 는 탐지되지 않았습니다.

  • 그래서 Seed 파일에 해당 CVE의 크래시 파일을 추가해줬습니다.


Custom dictionary

mkdir dictionaries && cd dictionaries
wget https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/stable/dictionaries/xml.dict
cd ..

Harness

#ifdef __cplusplus
extern "C"
{
#endif

#include <inttypes.h>
#include "libxml.h"
#include "libxml/relaxng.h"
#include "libxml/xmlerror.h"
#include <stdlib.h>

#include <libhfuzz/libhfuzz.h>

    int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
    {
        xmlDocPtr doc;

        int options = XML_PARSE_NOENT | XML_PARSE_DTDLOAD | XML_PARSE_DTDATTR |
                      XML_PARSE_DTDVALID | XML_PARSE_HUGE | XML_PARSE_IGNORE_ENC |
                      XML_PARSE_XINCLUDE | XML_PARSE_NOCDATA;

        doc = xmlReadMemory((const char *)buf, len, "fuzz.xml", "UTF-8",
                            options);
        if (doc)
        {
            xmlFreeDoc(doc);
        }

        return 0;
    }

#ifdef __cplusplus
}
#endif
  • 효율적인 퍼징을 위해 하네스를 사용하였습니다.

Build harness

hfuzz-clang -fsanitize=address -I/home/ion/Fuzzing_libxml2/libxml2-2.9.4/include -L/home/ion/Fuzzing_libxml2/libxml2-2.9.4/install/lib -o fuzz_libxml2 fuzz_libxml2.c -lxml2 -lz -llzma

Fuzzing

honggfuzz -i ./corpus -o hongfuzz_out --dict ./dictionaries/xml.dict --threads 8 -- ./fuzz_libxml2 ___FILE___

  • 드디어 크래시가 나왔습니다.


Analysis

Crash

'SIGABRT.PC.4808bb.STACK.1afc1ae315.CODE.-6.ADDR.0.INSTR.lea____-0x858(%rbp),%rdx.fuzz'
'SIGABRT.PC.4808bb.STACK.eb51c7ad8.CODE.-6.ADDR.0.INSTR.lea____-0x858(%rbp),%rdx.fuzz'
  • 총 2개의 크래시가 발견되었습니다.

Reproduce

❯ ./xmllint --noent --loaddtd --dtdattr --valid --huge --noenc --xinclude --nocdata SIGABRT.PC.4808bb.STACK.eb51c7ad8.CODE.-6.ADDR.0.INSTR.lea____-0x858\(%rbp\),%rdx.fuzz
=================================================================
==49334==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcac065d28 at pc 0x00000048078b bp 0x7ffcac0642f0 sp 0x7ffcac063a98
WRITE of size 2785 at 0x7ffcac065d28 thread T0
    #0 0x48078a in strcat (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x48078a)
    #1 0x6ddc9e in xmlSnprintfElementContent (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x6ddc9e)
    #2 0x6de6a9 in xmlSnprintfElementContent (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x6de6a9)
    #3 0x70b15c in xmlValidateElementContent (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x70b15c)
    #4 0x707bd4 in xmlValidateOneElement (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x707bd4)
    #5 0xb25b00 in xmlSAX2EndElementNs (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0xb25b00)
    #6 0x5c8da9 in xmlParseElement (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x5c8da9)
    #7 0x5e4e0f in xmlParseDocument (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x5e4e0f)
    #8 0x615102 in xmlDoRead (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x615102)
    #9 0x615cf0 in xmlCtxtReadFile (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x615cf0)
    #10 0x4d4170 in parseAndPrintFile (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x4d4170)
    #11 0x4cc68e in main (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x4cc68e)
    #12 0x7fb64d801082 in __libc_start_main /build/glibc-LcI20x/glibc-2.31/csu/../csu/libc-start.c:308:16
    #13 0x41c99d in _start (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x41c99d)

Address 0x7ffcac065d28 is located in stack of thread T0 at offset 5128 in frame
    #0 0x70a00f in xmlValidateElementContent (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x70a00f)

  This frame has 3 object(s):
    [32, 82) 'fn'
    [128, 5128) 'expr'
    [5392, 10392) 'list' <== Memory access at offset 5128 partially underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/home/ion/Fuzzing_libxml2/libxml2-2.9.4/xmllint+0x48078a) in strcat
Shadow bytes around the buggy address:
  0x100015804b50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100015804b60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100015804b70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100015804b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100015804b90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100015804ba0: 00 00 00 00 00[f2]f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
  0x100015804bb0: f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
  0x100015804bc0: f2 f2 f2 f2 f2 f2 00 00 00 00 00 00 00 00 00 00
  0x100015804bd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100015804be0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100015804bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
  Shadow gap:              cc
==49334==ABORTING
  • xmlSnprintfElementContent 함수에서 Stack-Buffer-Overflow 버그를 발견하였습니다.

크래시를 발견한게 seed 의 영향인지 harness + honggfuzz 의 영향인지는 삽질을 좀 더 해봐야 알 수 있지만, Fuzzing101 은 크래시 재현이 너무 힘든거 같습니다.

0개의 댓글