ffjpeg
ffjpeg copied to clipboard
Buffer overflow in jfif_load()
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
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.
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
I can't reproduce it either.
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>
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!
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.