Null pointer dereference vulnerability in the function init_music_line( ) – abcm2ps-8.14.1
December 20, 2018
CVE Number
–
CWE
CWE-476: NULL Pointer Dereference
Product Details
abcm2ps is a C program which converts music tunes from the ABC music notation to PostScript or SVG.
URL: https://github.com/leesavide/abcm2ps.git
Vulnerable Versions
8.14.1-master
Vulnerability Details
Null Pointer Dereference vulnerability is discovered in the abcm2ps (8.14.1-master). The same can be triggered by sending a crafted abc file to the abcm2ps binary. It allows an attacker to cause Denial of Service (Segmentation fault) or possibly have unspecified other impact when a victim opens a specially crafted file.
SYNOPSIS
We observed that the function output_music
, it generates the music loop per line, set_piece
is being called by output_music
, it defines the start and end of a piece of tune & also sets the end of voices, from here it invokes the function init_music_line
is located in music.c
, in condition if (last_s->voice == voice && last_s->type == BAR)
, it checks for the voice with voice in last_s
& type
in last_s
with predefined BAR. Now in next line p_voice->last_sym = last_s
the last_s
contains the value of p_voice->last_sym
,in the next line last_s = last_s->ts_next
here last_s
contains the value of last_s->ts_next
. Now when a crafted file is passed to the binary last_s=last_s->ts_next
the value of last_s->ts_next=0x0
which is being assigned of last_s. When exeecuting the condition if (last_s->voice == voice && last_s->type == BAR)
we observed that last_s
tries to access 0x0
which triggers a NULL pointer dereference.
Vulnerable code
for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { int bar_start; voice = p_voice - voice_tb; if (last_s->voice == voice && last_s->type == BAR) { p_voice->last_sym = last_s; last_s = last_s->ts_next; continue; }
Analysis
Program received signal SIGSEGV, Segmentation fault. [ Legend: Modified register | Code | Heap | Stack | String] ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ registers ]──── $rax : 0x0 $rbx : 0x5555557cc240 → 0x0000000000000031 ("1"?) $rcx : 0x555555876538 → 0x0000000000000000 $rdx : 0x0 $rsp : 0x7fffffffdbb0 → 0x00000000ffffdbc0 $rbp : 0x7fffffffdd00 → 0x0101010101010101 $rsi : 0x5555557c39a0 → 0x00005555557dabc8 → 0x0000000000000000 $rdi : 0x5555557db7a8 → 0x0000000000000000 $rip : 0x555555582a65 → movzx edx, BYTE PTR [r12+0x3a] $r8 : 0x5555557c39a0 → 0x00005555557dabc8 → 0x0000000000000000 $r9 : 0x0 $r10 : 0x0 $r11 : 0x1 $r12 : 0x0 $r13 : 0x5555557cc440 → 0x0000000000000032 ("2"?) $r14 : 0x0 $r15 : 0xff000000ff $eflags: [zero carry parity adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification] $ss: 0x002b $cs: 0x0033 $gs: 0x0000 $fs: 0x0000 $ds: 0x0000 $es: 0x0000 ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ stack ]──── 0x00007fffffffdbb0│+0x00: 0x00000000ffffdbc0 ← $rsp 0x00007fffffffdbb8│+0x08: 0x00005555557c39a0 → 0x00005555557dabc8 → 0x0000000000000000 0x00007fffffffdbc0│+0x10: 0x00007fffffffdce0 → 0x0101010101010101 0x00007fffffffdbc8│+0x18: 0x00005555557c39a0 → 0x00005555557dabc8 → 0x0000000000000000 0x00007fffffffdbd0│+0x20: 0x43bd000042f80000 0x00007fffffffdbd8│+0x28: 0x000055555585fab0 → 0x000055555585fd00 → 0x000055555585ff50 → 0x00005555558601a0 → 0x00005555558688e8 → 0x0000555555868b38 → 0x0000555555868d88 0x00007fffffffdbe0│+0x30: 0x00007fffffffdcf0 → 0x0101010101010101 0x00007fffffffdbe8│+0x38: 0x00007fffffffdce0 → 0x0101010101010101 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ code:i386:x86-64 ]──── 0x555555582a58 mov r13, QWORD PTR [r13+0x10] 0x555555582a5c test r13, r13 0x555555582a5f je 0x555555582870 → 0x555555582a65 movzx edx, BYTE PTR [r12+0x3a] 0x555555582a6b mov rax, r13 0x555555582a6e sub rax, rbx 0x555555582a71 sar rax, 0x9 0x555555582a75 cmp eax, edx 0x555555582a77 jne 0x555555582950 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ source:music.c+3323 ]──── 3318 for (p_voice = first_voice; p_voice; p_voice = p_voice->next) { 3319 int bar_start; 3320 3321 // if bar already, keep it in sequence 3322 voice = p_voice - voice_tb; → 3323 if (last_s->voice == voice && last_s->type == BAR) { 3324 p_voice->last_sym = last_s; 3325 last_s = last_s->ts_next; 3326 continue; 3327 } 3328 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ threads ]──── [#0] Id 1, Name: "abcm2ps", stopped, reason: SIGSEGV ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ trace ]──── [#0] 0x555555582a65 → Name: init_music_line() [#1] 0x555555582a65 → Name: set_piece() [#2] 0x555555582a65 → Name: output_music() [#3] 0x5555555886c1 → Name: generate() [#4] 0x555555588c38 → Name: gen_ly(eob=0x0) [#5] 0x55555558eab8 → Name: do_tune() [#6] 0x555555560ce2 → Name: abc_parse(p=0x5555557ddbb0 "", fname=0x5555557f7f10 "abcm2ps_output/crashes/crash4062", ln=0x65) [#7] 0x555555578c14 → Name: txt_add_eos(fname=0x5555557f7f10 "abcm2ps_output/crashes/crash4062", linenum=0x65) [#8] 0x5555555790a4 → Name: frontend(s=, ftype=, fname=, linenum=) [#9] 0x55555555c0bd → Name: treat_file(fn=0x7fffffffe66a "abcm2ps_output/crashes/crash4062", ext=) ────────────────────────────── init_music_line () at music.c:3323 3323 if (last_s->voice == voice && last_s->type == BAR) { gef➤ p last_s $1 = (struct SYMBOL *) 0x0 gef➤ i r rax 0x0 0x0 rbx 0x5555557cc240 0x5555557cc240 rcx 0x555555876538 0x555555876538 rdx 0x0 0x0 rsi 0x5555557c39a0 0x5555557c39a0 rdi 0x5555557db7a8 0x5555557db7a8 rbp 0x7fffffffdd00 0x7fffffffdd00 rsp 0x7fffffffdbb0 0x7fffffffdbb0 r8 0x5555557c39a0 0x5555557c39a0 r9 0x0 0x0 r10 0x0 0x0 r11 0x1 0x1 r12 0x0 0x0 r13 0x5555557cc440 0x5555557cc440 r14 0x0 0x0 r15 0xff000000ff 0xff000000ff rip 0x555555582a65 0x555555582a65 eflags 0x10202 [ IF RF] cs 0x33 0x33 ss 0x2b 0x2b ds 0x0 0x0 es 0x0 0x0 fs 0x0 0x0 gs 0x0 0x0
Tested environment
64-bit ubuntu 16.04 LTS
Proof of Concept
./abcm2ps r -E -g -x -v -O fff -O = -i -k 1 $POC -s 10 -w 1 -m 100 -d 100 -a 0 -f musicfont.fmt -D Bar/ -p -l -I 500 -x -M -N 3 -1 -G -j 0 -b 1 -f -T all -c -B 10
Timeline
Vendor Disclosure: 2018-12-13
Public Disclosure:
Credit
Discovered by ACE Team – Loginsoft