看这篇文章之前可以先阅读一下这篇文章 AFL漏洞挖掘技术漫谈(一):用AFL开始你的第一次Fuzzing
准备
- afl-fuzz 2.5.2
- pdfcrack source 0.16
- ubuntu 18.04
编译
首先对pdfcrack source进行编译,编译的时候我们尽量采用afl自带的gcc进行编译,afl-gcc在编译时可以进行插桩,使用如下命令:
CC=afl-gcc make
此时pdfcrack已经可以使用了
kaka@kaka-virtual-machine:~/pdfcrack$ ./pdfcrack-0.16/pdfcrack
Usage: ./pdfcrack-0.16/pdfcrack -f filename [OPTIONS]
OPTIONS:
-b, --bench perform benchmark and exit
-c, --charset=STRING Use the characters in STRING as charset
-w, --wordlist=FILE Use FILE as source of passwords to try
-n, --minpw=INTEGER Skip trying passwords shorter than this
-m, --maxpw=INTEGER Stop when reaching this passwordlength
-l, --loadState=FILE Continue from the state saved in FILENAME
-o, --owner Work with the ownerpassword
-u, --user Work with the userpassword (default)
-p, --password=STRING Give userpassword to speed up breaking
ownerpassword (implies -o)
-q, --quiet Run quietly
-s, --permutate Try permutating the passwords (currently only
supports switching first character to uppercase)
-v, --version Print version and exit
该软件可以对已加密的pdf进行破解密码
afl自带的testcase里面也已经自带了pdf样本
/testcases/others/pdf/small.pdf
先用pdfcrack测试一下这个样本,发现报错了
kaka@kaka-virtual-machine:~/pdfcrack$ ./pdfcrack-0.16/pdfcrack /home/kaka/afl-2.52b/testcases/others/pdf/small.pdf
Error: Encryption not detected (is the document password protected?)
报错提示我们这是一个没有密码保护的pdf文件,我们可以通过一些在线的pdf加密的网站对该文件进行加密。
准备fuzz
首先建立两个文件夹---输入,输出文件夹,我这里命名为in,out
此时的目录结构
kaka@kaka-virtual-machine:~/pdfcrack$ ls -l
total 28
drwxrwxr-x 2 kaka kaka 4096 12月 29 10:27 in
drwxrwxr-x 5 kaka kaka 4096 12月 29 10:34 out
drwxrwxr-x 5 kaka kaka 4096 12月 29 10:34 out1
drwxr-xr-x 4 kaka root 4096 12月 28 16:54 pdfcrack-0.16
-rw------- 1 kaka kaka 1274 12月 28 19:06 p.pdf
(多出来的out1是我做其他测试用的,p.pdf是已经有密码保护的pdf文件)
在这里我直接对程序进行fuzz,发现过了好久都没有发生崩溃,再回顾一下上面程序所展示的一些功能,这个参数引起了注意
-l, --loadState=FILE Continue from the state saved in FILENAME
意思差不多是如果一次恢复密码没有完成的话,可能会产生一个中间文件,下次可以直接load这个文件,继续上次的任务。
这样我们先测试一下,需要注意的是,在对pdf文件进行加密的时候,尽量密码选择的稍微复杂一点,要不然在破解密码的时候,还没来得及按CTRL+c,就已经破解完了。
kaka@kaka-virtual-machine:~/pdfcrack$ ./pdfcrack-0.16/pdfcrack p.pdf
PDF version 1.6
Security Handler: Standard
V: 2
R: 3
P: -4
Length: 128
Encrypted Metadata: True
FileID: bf009c4d37b7fbbf18a17a2e0ab6e4ba
U: 534a8f91a56dbccdce2886f6ab041f5f28bf4e5e4e758a4164004e56fffa0108
O: 09bb0b88f5eeb18f87b82246a416c481a0877462a4cb401676f49569404c7a0a
程序在这个状态停留了一会,我们可以选择在此时,停止破解
U: 534a8f91a56dbccdce2886f6ab041f5f28bf4e5e4e758a4164004e56fffa0108
O: 09bb0b88f5eeb18f87b82246a416c481a0877462a4cb401676f49569404c7a0a
^CCaught signal 2!
Trying to save state...
Successfully saved state to savedstate.sav!
kaka@kaka-virtual-machine:~/pdfcrack$ ls -l
total 28
drwxrwxr-x 2 kaka kaka 4096 12月 29 10:27 in
drwxrwxr-x 5 kaka kaka 4096 12月 29 10:44 out
drwxrwxr-x 5 kaka kaka 4096 12月 29 10:44 out1
drwxr-xr-x 4 kaka root 4096 12月 28 16:54 pdfcrack-0.16
-rw------- 1 kaka kaka 1274 12月 28 19:06 p.pdf
-rw-rw-r-- 1 kaka kaka 583 12月 29 10:44 savedstate.sav
程序自动生成了一个.sav文件,可以在当前目录下看到
然后使用 -l 参数确实可以继续破解
我们把这个sav文件放到in/文件夹内,使用下面的命令就可以开始fuzz了
在此之前先执行
echo core >/proc/sys/kernel/core_pattern
afl-fuzz -i in/ -o out/ ./pdfcrack-0.16/pdfcrack -l @@
但是又出现了
[-] PROGRAM ABORT : Test case 'id:000000,orig:s1.sav' results in a timeout
Location : perform_dry_run(), afl-fuzz.c:2777
推测程序执行可能超时了,再加上 -t 参数
afl-fuzz -i in/ -o out/ -t 5000 ./pdfcrack-0.16/pdfcrack -l @@
这样就可以正常执行了
关于cpu占用率:因为afl只占用一个cpu逻辑内核,所以不会占用太高,因此可以开多个afl进行并行测试。
等一会就会发现崩溃了
崩溃的文件会存放在out/crash/文件夹中
分析
取一个文件重命名为test,作为例子进行简略分析
kaka@kaka-virtual-machine:~/pdfcrack$ cp out/crashes/id\:000000\,sig\:11\,src\:000000\,op\:flip1\,pos\:12 test
kaka@kaka-virtual-machine:~/pdfcrack$ ./pdfcrack-0.16/pdfcrack -l test
Loaded state for test
PDF version 1.6
Security Handler: dard
O:
V: 2
R: 7
P: -4
Length: 128
Encrypted Metadata: True
FileID: bf009c4d37b7fbbf18a17a2e0ab6e4ba
U: 534a8f91a56dbccdce2886f6ab041f5f28bf4e5e4e758a4164004e56fffa0108
O: 09bb0b88f5eeb18f87b82246a416c481a0877462a4cb401676f49569404c7a0a
Segmentation fault
确实出现了段错误
利用gdb分析
pwndbg> bt
#0 0x0000000000000000 in ?? ()
#1 0x000000000040ff99 in runCrackRev3 () at pdfcrack.c:418
#2 0x0000000000412945 in runCrack () at pdfcrack.c:556
#3 0x0000000000402505 in main (argc=argc@entry=3, argv=argv@entry=0x7fffffffde08) at main.c:309
#4 0x00007ffff7a2d830 in __libc_start_main (main=0x4012f0 <main>, argc=3, argv=0x7fffffffde08, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffddf8) at ../csu/libc-start.c:291
#5 0x00000000004030e9 in _start ()
通过bt发现访问到一个空指针
In file: /home/kaka/pdfcrack/pdfcrack-0.16/md5.c
328 else
329 md5_50_variant = &md5_50s;
330 }
331
332 void
► 333 md5_50(uint8_t *msg, const unsigned int msgLen) {
334 md5_50_variant(msg, msgLen);
335 }
─────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffda58 —▸ 0x40ff99 (runCrackRev3+313) ◂— mov rcx, qword ptr [rip + 0x2164f8]
01:0008│ 0x7fffffffda60 —▸ 0x6282c0 ◂— 0xbffbb7374d9c00bf
02:0010│ 0x7fffffffda68 ◂— 0x0
03:0018│ rdi 0x7fffffffda70 ◂— 0x955d1951d4792cb7
04:0020│ 0x7fffffffda78 ◂— 0x36a3a3da42528292
05:0028│ 0x7fffffffda80 ◂— 0x2
06:0030│ 0x7fffffffda88 ◂— 0x0
... ↓
───────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────
► f 0 40ab5a md5_50+58
f 1 40ff99 runCrackRev3+313
f 2 412945 runCrack+309
f 3 402505 main+4629
f 4 7ffff7a2d830 __libc_start_main+240
pwndbg> p md5_50_variant
$1 = (void (*)()) 0x0
pwndbg> hexdump $rip+0x21b8e0
+0000 0x62643a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │....│....│....│....│
...
+0020 0x62645a 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 │....│....│....│....│
+0030 0x62646a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │....│....│....│....│
程序在jmp的时候访问到了一个空指针导致程序崩溃。
结合源码可知,此处应该调用md5_50_variant函数,但是该函数指针为0导致出现段错误
相关链接:http://tudr.thapar.edu:8080/jspui/bitstream/10266/4500/4/4500.pdf