AFL++安装

1
2
3
4
sudo apt-get update
sudo apt-get install -y build-essential python3-dev automake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools
sudo apt-get install -y lld-11 llvm-11 llvm-11-dev clang-11 || sudo apt-get install -y lld llvm llvm-dev clang
sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-dev

跟着官网安装依赖,装完gcc,clang以及llvm-ar,随后make、sudo make install

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
:~$ gcc --version
gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

:~$ clang --version
Ubuntu clang version 14.0.0-1ubuntu1.1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

:~$ llvm-ar --version
Ubuntu LLVM version 14.0.0

Optimized build.
Default target: x86_64-pc-linux-gnu
Host CPU: znver3
pwn111@pwn111-VM:~$

afl-cc -v有输出即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
:~$ afl-cc -v
afl-cc++4.41a by Michal Zalewski, Laszlo Szekeres, Marc Heuse - mode: LLVM-PCGUARD
Ubuntu clang version 14.0.0-1ubuntu1.1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-14/bin
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/11
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Candidate multilib: x32;@mx32
Selected multilib: .;@m64

编译xpdf

1
2
3
4
5
6
wget https://dl.xpdfreader.com/old/xpdf-3.02.tar.gz
tar -zxvf xpdf-3.02.tar.gz
cd xpdf-3.02/
CC=afl-clang-lto CXX=afl-clang-lto++ ./configure --prefix="$HOME/Desktop/AFL/Exercise1_Xpdf/xpdf-3.02/out"
make -j$(nproc)
make install
1
2
3
:~/Desktop/AFL/Exercise1_Xpdf/xpdf-3.02/out/bin$ ./pdfinfo -v
pdfinfo version 3.02
Copyright 1996-2007 Glyph & Cog, LLC

下载一些测试用例:

1
wget https://github.com/mozilla/pdf.js-sample-files/raw/master/helloworld.pdf
1
2
3
4
5
6
7
8
9
10
11
12
13
:~/Desktop/AFL/Exercise1_Xpdf/xpdf-3.02/out/bin$ ./pdfinfo -box -meta helloworld.pdf 
Tagged: no
Pages: 1
Encrypted: no
Page size: 200 x 200 pts
MediaBox: 0.00 0.00 200.00 200.00
CropBox: 0.00 0.00 200.00 200.00
BleedBox: 0.00 0.00 200.00 200.00
TrimBox: 0.00 0.00 200.00 200.00
ArtBox: 0.00 0.00 200.00 200.00
File size: 678 bytes
Optimized: no
PDF version: 1.7

AFL Fuzz

1
afl-fuzz -i inputs -o outs -s 123 -- ./pdftotext @@ outputs

得到崩溃后,使用gdb进行调试

1
gdb --args pdftotext '/home/pwn111/Desktop/AFL/Exercise1_Xpdf/xpdf-3.02/out/bin/outs/default/crashes/id:000000,sig:11,src:000578,time:103442,execs:112572,op:havoc,rep:8' /home/pwn111/Desktop/AFL/Exercise1_Xpdf/xpdf-3.02/out/bin/outputs

然后,运行之后,使用bt进行堆栈查看

一直在重复:

1
2
3
4
5
6
7
8
9
#3209 Stream::addFilters (this=0x555556704930, dict=0x7fffffa02848) at Stream.cc:102
#3210 0x0000555555691d0b in Parser::makeStream (this=0x5555567041e0, dict=0x7fffffa02848, fileKey=0x0, encAlgorithm=cryptRC4, keyLength=0, objNum=3, objGen=<optimized out>) at Parser.cc:203
#3211 Parser::getObj (this=0x5555567041e0, obj=0x7fffffa02848, fileKey=0x0, encAlgorithm=cryptRC4, keyLength=0, objNum=3, objGen=0) at Parser.cc:94
#3212 0x000055555568fee4 in Parser::getObj (this=0x2, obj=0x7fffffa02908, fileKey=0x1 <error: Cannot access memory at address 0x1>, encAlgorithm=(cryptAES | unknown: 0xf7914906), keyLength=36, objNum=-6637995, objGen=0) at Parser.cc:85
#3213 0x000055555568fee4 in Parser::getObj (this=0x2, obj=0x7fffffa02a60, fileKey=0x1 <error: Cannot access memory at address 0x1>, encAlgorithm=(cryptAES | unknown: 0xf7914906), keyLength=36, objNum=-6637995, objGen=0) at Parser.cc:85
#3214 0x00005555556ca0c7 in XRef::fetch (this=0x555555954670, num=<optimized out>, gen=0, obj=0x7fffffa02a60) at XRef.cc:823
#3215 0x000055555569c982 in Object::fetch (this=<optimized out>, xref=0x2, obj=0x7fffffa02a60) at /home/pwn111/Desktop/AFL/Exercise1_Xpdf/xpdf-3.02/xpdf/Object.cc:106
#3216 Dict::lookup (this=0x555556703e80, obj=0x7fffffa02a60, key=<optimized out>) at /home/pwn111/Desktop/AFL/Exercise1_Xpdf/xpdf-3.02/xpdf/Dict.cc:76
#3217 Object::dictLookup (this=0x7fffffa02c18, obj=0x7fffffa02a60, key=<optimized out>) at ./Object.h:253

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  dict->dictLookup("Filter", &obj);
if (obj.isNull()) {
obj.free();
dict->dictLookup("F", &obj);
}

|
|
|
|
\ /
inline Object *Object::dictLookup(char *key, Object *obj)
{ return dict->lookup(key, obj); }
|
|
|
|
\ /
Object *Dict::lookup(char *key, Object *obj) {
DictEntry *e;

return (e = find(key)) ? e->val.fetch(xref, obj) : obj->initNull();
}
|
|
|
|
\ /
Object *XRef::fetch(int num, int gen, Object *obj) {
XRefEntry *e;
Parser *parser;
Object obj1, obj2, obj3;

// check for bogus ref - this can happen in corrupted PDF files
if (num < 0 || num >= size) {
goto err;
}

e = &entries[num];
switch (e->type) {

case xrefEntryUncompressed:
if (e->gen != gen) {
goto err;
}
obj1.initNull();
parser = new Parser(this,
new Lexer(this,
str->makeSubStream(start + e->offset, gFalse, 0, &obj1)),
gTrue);
parser->getObj(&obj1);
parser->getObj(&obj2);
parser->getObj(&obj3);
if (!obj1.isInt() || obj1.getInt() != num ||
!obj2.isInt() || obj2.getInt() != gen ||
!obj3.isCmd("obj")) {
obj1.free();
obj2.free();
obj3.free();
delete parser;
goto err;
}
parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL,
encAlgorithm, keyLength, num, gen);
obj1.free();
obj2.free();
obj3.free();
delete parser;
break;