Denial of service in VCFtools 0.1.16Loginsoft-2018-1007August 29, 2018
CWE
CWE-20: Improper Input Validation
Product Details
VCFtools is a suite of functions for use on genetic variation data in the form of VCF and BCF files. The tools provided will be used mainly to summarize data, run calculations on data, filter out data, and convert data into other useful file formats.
URL: https://vcftools.github.io/
Vulnerable Versions
VCFtools 0.1.16
Vulnerability Details
A Denial of service was discovered in VCFtools 0.1.16 version.
SYNOPSIS
```
N_allele = n_allele_info >> 16; [1]
N_info = n_allele_info & (uint32_t)65535;
ALT_pos = line_pos;
```
```
void bcf_entry::set_ALT(const int n_allele)
{
ALT.resize(n_allele-1); [2]
```
Vcftools binary while parsing an BCF file type, it calls the function variant_file::write_stats() which gets all the entries from the object & then attempts to parse those entries calling bcf_entry::parse_basic_entry(). Inside there’s a computation being done to calculate the value of number of allele `N_allele` that is by using `n_allele_info ` & right sifting it by 16 [1], the resultant value is then being passed to bcf_entry::set_ALT() . bcf_entry::set_ALT() responsible for setting the alleles. The value of N_allele is then passed to ALT.resize(), which decrements the value by 1 [2].
In case the value of n_allele_info is zero, the value of N_allele would be zero, which when passed to ALT_resize would then be subtract by 1, leaving a negative number ( -1). Whenever an invalid size is passed to vector::resize, it throws an std::length_error exception, internally calling abort(), raising a SIGABRT signal.
Fix: As a part of fix, a bound check is added to confirm if the number of alleles is greater than zero.
+ if (n_allele <= 0)
+ LOG.error(“Number of alleles must be positive.”);
ALT.resize(n_allele-1);
Commit: cdc24330ec86dff246152cde38ebb45b93035432
Analysis
gef➤ p n_allele
$1 = 0x0
gef➤ ptype ALT
type = std::vector
Backtrace
gef➤ bt
#0 0x00007ffff6f7b428 in __GI_raise (sig=sig@entry=0x6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007ffff6f7d02a in __GI_abort () at abort.c:89
#2 0x00007ffff78bd8f7 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x00007ffff78c3a46 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4 0x00007ffff78c3a81 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x00007ffff78c3cb4 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6 0x00007ffff78bf7a9 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7 0x000000000041d08b in std::vector, std::allocator >, std::allocator, std::allocator > > >::_M_check_len (__s=0x4b6531 "vector::_M_fill_insert", __n=0xffffffffffffffff, this=0x70c348) at /usr/include/c++/5/bits/stl_vector.h:1425
#8 std::vector, std::allocator >, std::allocator, std::allocator > > >::_M_fill_insert (this=this@entry=0x70c348, __position=__position@entry=non-dereferenceable iterator for std::vector, __n=__n@entry=0xffffffffffffffff, __x="") at /usr/include/c++/5/bits/vector.tcc:489
#9 0x00000000004156e2 in std::vector, std::allocator >, std::allocator, std::allocator > > >::insert (__x="", __n=0xffffffffffffffff, __position=..., this=0x70c348) at /usr/include/c++/5/bits/stl_vector.h:1073
#10 std::vector, std::allocator >, std::allocator, std::allocator > > >::resize (__x=, __new_size=0xffffffffffffffff, this=0x70c348) at /usr/include/c++/5/bits/stl_vector.h:716
#11 bcf_entry::set_ALT (this=this@entry=0x70bf00, n_allele=0x0) at bcf_entry_setters.cpp:13
#12 0x000000000040d7f6 in bcf_entry::parse_basic_entry (this=0x70bf00, parse_ALT=, parse_FILTER=, parse_INFO=) at bcf_entry.cpp:115
#13 0x0000000000475a6a in variant_file::write_stats (this=this@entry=0x709580, params=...) at variant_file_output.cpp:5416
#14 0x0000000000406436 in main (argc=, argv=) at vcftools.cpp:58
gef➤ i r
rax 0x0 0x0
rbx 0x7071a8 0x7071a8
rcx 0x7ffff6f7b428 0x7ffff6f7b428
rdx 0x6 0x6
rsi 0xdcc 0xdcc
rdi 0xdcc 0xdcc
rbp 0x6d4b00 0x6d4b00
rsp 0x7fffffffcdb8 0x7fffffffcdb8
r8 0x7ffff730c770 0x7ffff730c770
r9 0x7ffff7fd9740 0x7ffff7fd9740
r10 0x8 0x8
r11 0x246 0x246
r12 0x70bce0 0x70bce0
r13 0xffffffffffffffff 0xffffffffffffffff
r14 0x7fffffffd050 0x7fffffffd050
r15 0x70c348 0x70c348
rip 0x7ffff6f7b428 0x7ffff6f7b428 <__GI_raise+56>
eflags 0x246 [ PF ZF IF ]
cs 0x33 0x33
ss 0x2b 0x2b
ds 0x0 0x0
es 0x0 0x0
fs 0x0 0x0
gs 0x0 0x0
Proof of Concept
vcftools --bcf $POC
Timeline
Vendor Disclosure: 2018-08-29
Patch Release: 2018-08-30
Public Disclosure: 2018-08-31
Credit
Discovered by ACE Team - Loginsoft