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