rockcarry / ffjpeg

a simple jpeg codec.
GNU General Public License v3.0
106 stars 46 forks source link

Stack-buffer-overflows in jfif_decode() at jfif.c:513 #21

Closed 14isnot40 closed 4 years ago

14isnot40 commented 4 years ago

Describe the bug A stack-based buffer overflow was discovered in ffjpeg, during the out bound of read in array 'yuv_datbuf'. The issue is being triggered in the function jfif_decode() at jfif.c:513.

To Reproduce Steps to reproduce the behavior:

  1. Compile ffjpeg with address sanitizer
  2. execute command
    ffjpeg -d $poc

    poc can be found here.

Expected behavior An attacker can exploit this vulnerability by submitting a malicious jpeg that exploits this issue. This will result in a Denial of Service (DoS) when the application attempts to process the file.

Screenshots ASAN Reports

=================================================================
==102581==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffffffd778 at pc 0x00000040557b bp 0x7fffffffd5a0 sp 0x7fffffffd590
READ of size 8 at 0x7fffffffd778 thread T0
    #0 0x40557a in jfif_decode /home/test/Desktop/evaulation/ffjpeg/ffjpeg/src/jfif.c:513
    #1 0x4011b0 in main /home/test/Desktop/evaulation/ffjpeg/ffjpeg/src/ffjpeg.c:24
    #2 0x7ffff6ac082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #3 0x400f78 in _start (/home/test/Desktop/evaulation/ffjpeg/ffjpeg/src/ffjpeg+0x400f78)

Address 0x7fffffffd778 is located in stack of thread T0 at offset 248 in frame
    #0 0x40448a in jfif_decode /home/test/Desktop/evaulation/ffjpeg/ffjpeg/src/jfif.c:378

  This frame has 6 object(s):
    [32, 44) 'yuv_stride'
    [96, 108) 'yuv_height'
    [160, 176) 'dc'
    [224, 248) 'yuv_datbuf' <== Memory access at offset 248 overflows this variable
    [288, 416) 'ftab'
    [448, 704) 'du'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/test/Desktop/evaulation/ffjpeg/ffjpeg/src/jfif.c:513 jfif_decode
Shadow bytes around the buggy address:
  0x10007fff7a90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fff7aa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fff7ab0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fff7ac0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fff7ad0: f1 f1 f1 f1 00 04 f4 f4 f2 f2 f2 f2 00 04 f4 f4
=>0x10007fff7ae0: f2 f2 f2 f2 00 00 f4 f4 f2 f2 f2 f2 00 00 00[f4]
  0x10007fff7af0: f2 f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fff7b00: 00 00 00 00 f2 f2 f2 f2 00 00 00 00 00 00 00 00
  0x10007fff7b10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fff7b20: 00 00 00 00 00 00 00 00 f3 f3 f3 f3 f3 f3 f3 f3
  0x10007fff7b30: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==102581==ABORTING

gdb debug

Breakpoint 2, jfif_decode (ctxt=0x61500000fd00, pb=0x7fffffffd9f0) at jfif.c:513
513                     idst = yuv_datbuf[c] + y * yuv_stride[c] + x;
[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x0               
$rbx   : 0x00007fffffffd980  →  0x00007fffffffd9d0  →  0x0000000041b58ab3
$rcx   : 0x000061500000fd00  →  0x0000001000000006  →  0x0000000000000000
$rdx   : 0x0               
$rsp   : 0x00007fffffffd5b0  →  0x00007fffffffd9f0  →  0x0000000000000000
$rbp   : 0x00007fffffffd9a0  →  0x00007fffffffda50  →  0x000000000040e630  →  <__libc_csu_init+0> push r15
$rsi   : 0x0               
$rdi   : 0x7               
$rip   : 0x0000000000405547  →  <jfif_decode+4300> lea rax, [rbx-0x220]
$r8    : 0x7               
$r9    : 0x7               
$r10   : 0x0               
$r11   : 0x7               
$r12   : 0x00000ffffffffad0  →  0x0000000000000000
$r13   : 0x00007fffffffd680  →  0x0000000041b58ab3
$r14   : 0x00007fffffffd680  →  0x0000000041b58ab3
$r15   : 0x0               
$eflags: [carry PARITY adjust zero sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000 
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffd5b0│+0x0000: 0x00007fffffffd9f0  →  0x0000000000000000    ← $rsp
0x00007fffffffd5b8│+0x0008: 0x000061500000fd00  →  0x0000001000000006  →  0x0000000000000000
0x00007fffffffd5c0│+0x0010: 0x00007fffffffda50  →  0x000000000040e630  →  <__libc_csu_init+0> push r15
0x00007fffffffd5c8│+0x0018: 0x00000000f7de6ad6  →  0x0000000000000000
0x00007fffffffd5d0│+0x0020: 0x0000000000000001
0x00007fffffffd5d8│+0x0028: 0x0000000000000003
0x00007fffffffd5e0│+0x0030: 0x0000000200000000  →  0x0000000000000000
0x00007fffffffd5e8│+0x0038: 0xffffffff00000003
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x40553a <jfif_decode+4287> cdq    
     0x40553b <jfif_decode+4288> idiv   DWORD PTR [rbp-0x3b8]
     0x405541 <jfif_decode+4294> mov    DWORD PTR [rbp-0x384], eax
 →   0x405547 <jfif_decode+4300> lea    rax, [rbx-0x220]
     0x40554e <jfif_decode+4307> mov    edx, DWORD PTR [rbp-0x3c8]
     0x405554 <jfif_decode+4313> movsxd rdx, edx
     0x405557 <jfif_decode+4316> shl    rdx, 0x3
     0x40555b <jfif_decode+4320> add    rax, rdx
     0x40555e <jfif_decode+4323> mov    rdx, rax
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "ffjpeg", stopped, reason: BREAKPOINT
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x405547 → jfif_decode(ctxt=0x61500000fd00, pb=0x7fffffffd9f0)
[#1] 0x4011b1 → main(argc=0x3, argv=0x7fffffffdb38)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤  p c
$15 = 0x3
gef➤  p yuv_datbuf   
$16 = {0x61d00001ea80, 0x60200000efd0, 0x61200000bec0}
gef➤  p yuv_datbuf[c]
$17 = (int *) 0x0
gef➤  c
Continuing.
=================================================================
==102581==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffffffd778 at pc 0x00000040557b bp 0x7fffffffd5a0 sp 0x7fffffffd590
READ of size 8 at 0x7fffffffd778 thread T0
    #0 0x40557a in jfif_decode /home/test/Desktop/evaulation/ffjpeg/ffjpeg/src/jfif.c:513
    #1 0x4011b0 in main /home/test/Desktop/evaulation/ffjpeg/ffjpeg/src/ffjpeg.c:24
    #2 0x7ffff6ac082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #3 0x400f78 in _start (/home/test/Desktop/evaulation/ffjpeg/ffjpeg/src/ffjpeg+0x400f78)

Address 0x7fffffffd778 is located in stack of thread T0 at offset 248 in frame
    #0 0x40448a in jfif_decode /home/test/Desktop/evaulation/ffjpeg/ffjpeg/src/jfif.c:378

  This frame has 6 object(s):
    [32, 44) 'yuv_stride'
    [96, 108) 'yuv_height'
    [160, 176) 'dc'
    [224, 248) 'yuv_datbuf' <== Memory access at offset 248 overflows this variable
    [288, 416) 'ftab'
    [448, 704) 'du'

Possible causes of vulnerabilitie Missing value check for variable c leads to out-of-bounds reading of array yuv_datbuf:

idst = yuv_datbuf[c] + y * yuv_stride[c] + x;
int   i, j, c, h, v, x, y;

int   sfh_max = 0;

int   sfv_max = 0;

int   yuv_stride[3] = {0};

int   yuv_height[3] = {0};

int  *yuv_datbuf[3] = {0};

System (please complete the following information):

rockcarry commented 4 years ago

new commit 6293600c5ba214eaaf6641e22bdc1d75b46eeb81 fix this is issue @14isnot40 please test.

14isnot40 commented 4 years ago

new commit 6293600 fix this is issue @14isnot40 please test.

Tested and patched, thanks for your work