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