Disclaimer for the week: nothing is ever simple and you can expect that mostly every step of trying to do something will be filled with errors that you'll have to spend a lot of time figuring out and fixing

The Vulnerability

Link copied to clipboard
I am going to be fuzzing the program Xpdf, looking to find the vulnerability CVE-2019-13288 from cve details database, described as: >In Xpdf 4.01.01, the Parser::getObj() function in Parser.cc may cause infinite recursion via a crafted file. A remote attacker can leverage this for a DoS attack. ^471700
After trying and failing to build and make the version listed in the vulnerability page, 4.01.04, i went back to an older version - 3.02 which successfully built. I spent an hour or so playing with it and trying to understand the errors, which I was able to and fix some of them, but others were just a lost cause so I had to decide it wasn't worth my time trying this version anymore. Had a little bit of issues with making the 3.02 build but I was able to fix them after a while of playing around with the config files, I figured out that I had to specify locations of certain libraries outside of their usual places and feed that into the config before making, and was able to successfully do it.

Fuzzing

Link copied to clipboard
In order to use a program with AFL++, the program needs to have source code available, then to be compiled with one of the compilers that comes with the install. I used the afl clang fast compiler. For later reference, the code to do this is
export LLVM_CONFIG="llvm-config-11"
CC=$HOME/AFLplusplus/afl-clang-fast CXX=$HOME/AFLplusplus/afl-clang-fast++ ./configure --prefix="$HOME/MEGAsync/Lvl\ 7\ II/fuzzing_xpdf/install" **path here to source files**
make
make install
you also need to make sure you SPELL THE DIRECTORY RIGHT otherwise all your files will go into another place and youll be stuck later wondering why things aren't working and have to spend another hour starting over from scratch once you do find out its a typo. Also anytime there is a ./configure command, make sure to include --with-freetype2-includes=/usr/include/freetype2 --with-freetype2-library=/usr/lib/x86_64-linux-gnu
To get the fuzzer to run on some files, use this command afl-fuzz -i $HOME/MEGAsync/Lvl\ 7\ II/fuzzing_xpdf/pdf_examples/ -o $HOME/MEGAsync/Lvl\ 7\ II/fuzzing_xpdf/out/ -s 123 -- $HOME/MEGAsync/Lvl\ 7\ II/fuzzing_xpdf/install/bin/pdftotext @@ $HOME/MEGAsync/Lvl\ 7\ II/fuzzing_xpdf/output
-i = directory for the input files. this is a few example pdfs i downloaded -o = directory where the fuzzer will store the mutated files -s = the seed to use. because afl uses a non deterministic testing algorithm (diff result each time), using a fixed seed on the tests keeps the results for the runs similar -- = the command to use @@ = placeholder that AFL substitutes for each input file's name
pdftotext is part of xpdf's tools that comes when you install it.
Screenshot of fuzzer working

Debugging

Link copied to clipboard
Now it's found some crashes, I'll check the out folder for the mutated files and run one through pdftotext.
pdftotext id:000000,sig:11,src:000528,time:91864,execs:47928,op:havoc,rep:2 $HOME/MEGAsync/Lvl\ 7\ II/fuzzing_xpdf/output 
Error: PDF file is damaged - attempting to reconstruct xref table...
zsh: segmentation fault  pdftotext id:000000,sig:11,src:000528,time:91864,execs:47928,op:havoc,rep:2 
The name of the files is that big long thing starting with id: and ending with rep:2. so thats just using pdftotext, passing the file, and saying the output will be in the path that comes afterwards.
When doing that, it gives a segmentation fault and crashes the program.
To find out why this crash happens, we have to debug it. There's a program called GDB which helps you do this. You just have to install it, and then compile the program using gdb.
output from using gdb:
Reading symbols from /home/android66/MEGAsync/Lvl 7 II/fuzzing_xpdf/install/bin/pdftotext...
(gdb) run
Starting program: /home/android66/MEGAsync/Lvl 7 II/fuzzing_xpdf/install/bin/pdftotext /home/android66/MEGAsync/Lvl\ 7\ II/fuzzing_xpdf/out/default/crashes/id:000000,sig:11,src:000528,time:91864,execs:47928,op:havoc,rep:2 /home/android66/MEGAsync/Lvl\ 7\ II//fuzzing_xpdf/output
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Error: PDF file is damaged - attempting to reconstruct xref table...

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7ab638d in _int_malloc (av=av@entry=0x7ffff7bf1c60 <main_arena>, 
    bytes=4) at ./malloc/malloc.c:3979
3979	./malloc/malloc.c: No such file or directory.
(gdb) 
using the command bt (backtrace - printing a backtrace of all the active functions on the execution stack, i.e. looking at the functions of the pdftotext program) reveals this
#0  0x00007ffff7ab638d in _int_malloc (
    av=av@entry=0x7ffff7bf1c60 <main_arena>, bytes=4) at ./malloc/malloc.c:3979
#1  0x00007ffff7ab789a in __GI___libc_malloc (bytes=<optimized out>)
    at ./malloc/malloc.c:3315
#2  0x000055555562092a in gmalloc (size=4) at gmem.cc:97
#3  0x0000555555620b5d in copyString (s=0x5555565564e4 "obj") at gmem.cc:261
#4  0x00005555555f52e6 in Object::initCmd (this=0x555556556498, 
    cmdA=0x5555565564e4 "obj")
    at /home/android66/MEGAsync/Lvl 7 II/fuzzing_xpdf/xpdf-3.02/xpdf/Object.h:103
#5  0x00005555555f15ff in Lexer::getObj (this=0x5555565564c0, 
    obj=0x555556556498) at Lexer.cc:458
#6  0x00005555555f9e53 in Parser::shift (this=0x555556556470) at Parser.cc:226
#7  0x00005555555f97e9 in Parser::getObj (this=0x555556556470, 
    obj=0x7fffff7ff2a0, fileKey=0x0, encAlgorithm=cryptRC4, keyLength=0, 
    objNum=0, objGen=0) at Parser.cc:108
#8  0x000055555561bcd6 in XRef::fetch (this=0x5555556c22f0, num=7, gen=0, 
    obj=0x7fffff7ff3e0) at XRef.cc:811
#9  0x00005555555f4c22 in Object::fetch (this=0x555556556368, 
    xref=0x5555556c22f0, obj=0x7fffff7ff3e0) at Object.cc:106
#10 0x000055555559b726 in Dict::lookup (this=0x555556556310, 
    key=0x555555643a8f "Length", obj=0x7fffff7ff3e0) at Dict.cc:76
#11 0x00005555555f580d in Object::dictLookup (this=0x7fffff7ff690, 
On line 13, function #7, we see Parser::getObj, which matches the vulnerability we were looking for. To be honest I have no idea how exactly an attacker can use this to perform a dos attack. I think I found the section in the program's code that it's referring to, in the file parser.cc line 108 is the first shift(); in this section.
// indirect reference or integer
  } else if (buf1.isInt()) {
    num = buf1.getInt();
    shift();
    if (buf1.isInt() && buf2.isCmd("R")) {
      obj->initRef(num, buf1.getInt());
      shift();
      shift();
    } else {
      obj->initInt(num);
    }

Afterthoughts

Link copied to clipboard
While this is great and I found a good repository of guides for using AFL++ on software this week, and also managed to get it working to even detect a known vulnerability, i've been using the fuzzers that are prebuilt in with the AFL++ stuff, rather than the bits and pieces of fuzzers in the LibAfl library, which is a fork of ++, and is the library that can be used to create custom fuzzers. Having done this and gotten familiar with how it works and the commands to use, I can now start to use LibAfl to stitch together a fuzzer made from scratch to perform the same operations as outlined above.
Made with Markbase