看这篇文章之前可以先阅读一下这篇文章 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 @@

这样就可以正常执行了

alt

关于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

preView