ffjpeg icon indicating copy to clipboard operation
ffjpeg copied to clipboard

Buffer overflow in jfif_load()

Open 0xdd96 opened this issue 2 years ago • 6 comments

version: master (commit caade60) poc: poc command: ./ffjpeg -d $poc$

Here is the backtrace in GDB:

pwndbg> backtrace
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007ffff73bd859 in __GI_abort () at abort.c:79
#2  0x00007ffff742829e in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff755208f "*** %s ***: terminated\n") at ../sysdeps/posix/libc_fatal.c:155
#3  0x00007ffff74caaea in __GI___fortify_fail (msg=msg@entry=0x7ffff7552025 "buffer overflow detected") at fortify_fail.c:26
#4  0x00007ffff74c9386 in __GI___chk_fail () at chk_fail.c:28
#5  0x00007ffff74c9a85 in __fread_chk (ptr=ptr@entry=0x631000000800, ptrlen=ptrlen@entry=65536, size=size@entry=1, n=n@entry=18446744073709551613, stream=stream@entry=0x615000000300) at fread_chk.c:39
#6  0x000055555555c569 in fread (__stream=0x615000000300, __n=18446744073709551613, __size=1, __ptr=0x631000000800) at /usr/include/x86_64-linux-gnu/bits/stdio2.h:292
#7  jfif_load (file=<optimized out>) at jfif.c:175
#8  0x0000555555556b54 in main (argc=argc@entry=3, argv=argv@entry=0x7fffffffe4a8) at ffjpeg.c:23
#9  0x00007ffff73bf0b3 in __libc_start_main (main=0x5555555568b0 <main>, argc=3, argv=0x7fffffffe4a8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe498) at ../csu/libc-start.c:308
#10 0x000055555555704e in _start ()

The size of the buf is 0x10000 (line 152), the size variable is calculated using the data provided in the file (line 170-172) and is controlled by the user.

Executing fread without checking size and the boundary of buf will cause a buffer overflow (line 175).

https://github.com/rockcarry/ffjpeg/blob/caade60a69633d74100bd3c2528bddee0b6a1291/src/jfif.c#L152-L175

0xdd96 avatar Mar 28 '22 09:03 0xdd96

I cannot reproduce the crash with the provided poc, neither in normally compiled ffjpeg or ffjpeg compiled with Address Sanitizer.

With the provided poc, the size in fread() is -3. And after the size = (int)fread(buf, 1, -3, fp) is executed, the size is assigned with 0 instead of crashing the program.

(gdb) b jfif.c:175
Breakpoint 1 at 0x1c1a: file jfif.c, line 175.
(gdb) r
Starting program: /home/ubuntu178/cvelibf/test/ffjpeg/caade60/bin_normal/bin/ffjpeg -d ffjpeg-jfif_load-buffer-overflow 

Breakpoint 1, jfif_load (file=0x7fffffffe1c0 "ffjpeg-jfif_load-buffer-overflow") at jfif.c:175
175             size = (int)fread(buf, 1, size, fp);
(gdb) p/d size
$1 = -3
(gdb) n
176             switch (type) {
(gdb) p size
$2 = 0
(gdb) c
Continuing.
file eof !
invalid input params !
[Inferior 1 (process 2741514) exited normally]
(gdb)

Tested in Ubuntu 20.04, 64bit; Clang 12.0.0; GLIBC 2.31.

Marsman1996 avatar Mar 31 '22 14:03 Marsman1996

The details about the downloaded poc file:

❯ xxd ffjpeg-jfif_load-buffer-overflow
00000000: 9090 9090 90b3 9090 90a3 908a f5ec f4f4  ................
00000010: 0000 2100 20ff e8                        ..!. ..
❯ sha1sum ./ffjpeg-jfif_load-buffer-overflow
36abf0f73d4aa1b4f079c582237b69d5c99b4e29  ./ffjpeg-jfif_load-buffer-overflow

Marsman1996 avatar Apr 01 '22 04:04 Marsman1996

I can't reproduce it either.

GHTHYS avatar Apr 01 '22 07:04 GHTHYS

I use afl-gcc to compile the target program.

CC=afl-gcc CXX=afl-g++ make -e -j

It looks like the program invoked different fread.

# make -j
pwndbg> b jfif.c:175
Breakpoint 1 at 0x3ca9: file jfif.c, line 175.
pwndbg> x/10i 0x3ca9
   0x3ca9 <jfif_load+369>:      mov    eax,DWORD PTR [rbp-0x60]
   0x3cac <jfif_load+372>:      movsxd rdx,eax
   0x3caf <jfif_load+375>:      mov    rcx,QWORD PTR [rbp-0x30]
   0x3cb3 <jfif_load+379>:      mov    rax,QWORD PTR [rbp-0x10]
   0x3cb7 <jfif_load+383>:      mov    esi,0x1
   0x3cbc <jfif_load+388>:      mov    rdi,rax
   0x3cbf <jfif_load+391>:      call   0x23d0 <fread@plt>
# CC=afl-gcc CXX=afl-g++ make -e -j
pwndbg> b jfif.c:170
Breakpoint 2 at 0x82fc: file jfif.c, line 170.
pwndbg> x/20i 0x82fc
   0x82fc <jfif_load+4300>:     mov    rdi,r12
   0x82ff <jfif_load+4303>:     call   0x24e0 <fgetc@plt>
   0x8304 <jfif_load+4308>:     mov    rdi,r12
   0x8307 <jfif_load+4311>:     shl    eax,0x8
   0x830a <jfif_load+4314>:     mov    ebp,eax
   0x830c <jfif_load+4316>:     call   0x24e0 <fgetc@plt>
   0x8311 <jfif_load+4321>:     mov    rdi,QWORD PTR [rsp+0x8]
   0x8316 <jfif_load+4326>:     mov    r8,r12
   0x8319 <jfif_load+4329>:     mov    edx,0x1
   0x831e <jfif_load+4334>:     or     ebp,eax
   0x8320 <jfif_load+4336>:     mov    esi,0x10000
   0x8325 <jfif_load+4341>:     lea    ecx,[rbp-0x2]
   0x8328 <jfif_load+4344>:     movsxd rcx,ecx
   0x832b <jfif_load+4347>:     call   0x2590 <__fread_chk@plt>

0xdd96 avatar Apr 01 '22 07:04 0xdd96

With program compiled with afl-gcc, I can get the following crash report:

Breakpoint 4, jfif_load (file=<optimized out>) at jfif.c:171
171                 size |= fgetc(fp) << 0;
(gdb) n
175             size = (int)fread(buf, 1, size, fp);
(gdb) p size
$2 = -3
(gdb) n
*** buffer overflow detected ***: terminated

Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50      ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007ffff7ddf859 in __GI_abort () at abort.c:79
#2  0x00007ffff7e4a3ee in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff7f7407c "*** %s ***: terminated\n") at ../sysdeps/posix/libc_fatal.c:155
#3  0x00007ffff7eecb4a in __GI___fortify_fail (msg=msg@entry=0x7ffff7f74012 "buffer overflow detected") at fortify_fail.c:26
#4  0x00007ffff7eeb3e6 in __GI___chk_fail () at chk_fail.c:28
#5  0x00007ffff7eebae5 in __fread_chk (ptr=0x5555555754a0, ptrlen=<optimized out>, size=1, n=18446744073709551613, stream=0x5555555854b0) at fread_chk.c:39
#6  0x000055555555a5ec in fread (__stream=0x5555555854b0, __n=18446744073709551613, __size=1, __ptr=0x5555555754a0) at /usr/include/x86_64-linux-gnu/bits/stdio2.h:292
#7  jfif_load (file=<optimized out>) at jfif.c:175
#8  0x0000555555555644 in main (argc=<optimized out>, argv=0x7fffffffde38) at ffjpeg.c:23

As far as I know, afl-gcc will insert instrumentation code to the program and add compilation options. I'm not sure what makes ffjpeg crashes, I will do more researches about it.

Thanks for your information!

Marsman1996 avatar Apr 01 '22 11:04 Marsman1996

So it is a bug caused by afl-gcc instead of a bug of ffjpeg, right? Since fread is not expected to crash when the size is very large.

Marsman1996 avatar Apr 01 '22 15:04 Marsman1996